Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- BLOCK_HEIGHT = 62
- freeboard.loadWidgetPlugin
- "type_name": "line_chart"
- "display_name": "Line Chart"
- "description": "Line Chart widget powered by C3.js, " +
- "written by Tomas Sandven"
- "external_scripts": [
- "https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js",
- "https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"
- ]
- "fill_size": true
- "settings": [
- {
- name: "height",
- display_name: "Height (in blocks)"
- type: "number"
- default_value: 5
- }
- {
- name: "columns"
- display_name: "Columns"
- type: "calculated"
- }
- {
- name: "flow"
- display_name: "Flow data"
- type: "boolean"
- default: false
- description: """
- Displays a neat animation when data flows from right to left.
- Only set this to true if past data never changes.
- """
- }
- {
- name: "chart_type"
- display_name: "Chart type"
- type: "option"
- default_value: "area"
- options: [
- {
- name: "Area chart"
- value: "area"
- }
- {
- name: "Bar chart"
- value: "bar"
- }
- {
- name: "Line chart"
- value: "line"
- }
- {
- name: "Pie chart"
- value: "pie"
- }
- {
- name: "Donut chart"
- value: "donut"
- }
- ]
- }
- {
- name: "legend_position"
- display_name: "Legend position"
- type: "option"
- default_value: "bottom"
- options: [
- {
- name: "Bottom"
- value: "bottom"
- }
- {
- name: "Right"
- value: "right"
- }
- {
- name: "Inset"
- value: "inset"
- }
- ]
- }
- {
- name: "time_format"
- display_name: "X Axis Time Format"
- type: "text"
- default_value: "%Y-%m-%d %H:%M:%S"
- }
- {
- name: "display_markers"
- display_name: "Display Time Markers"
- type: "boolean"
- }
- {
- name: "marker_interval"
- display_name: "Time Markers: Interval"
- type: "option"
- options: [
- {
- name: "Every 30 seconds"
- value: 30
- }
- {
- name: "Every minute"
- value: 60
- }
- {
- name: "Every 10 minutes"
- value: 60 * 10
- }
- {
- name: "Every 30 minutes"
- value: 60 * 30
- }
- {
- name: "Every hour"
- value: 60 * 60
- }
- {
- name: "Every 2 hours"
- value: 60 * 60 * 2
- }
- {
- name: "Every 3 hours"
- value: 60 * 60 * 3
- }
- {
- name: "Every 4 hours"
- value: 60 * 60 * 4
- }
- {
- name: "Every 6 hours"
- value: 60 * 60 * 6
- }
- {
- name: "Every day"
- value: 60 * 60 * 24
- }
- {
- name: "Every 3 days"
- value: 60 * 60 * 24 * 3
- }
- ]
- }
- {
- name: "marker_time_format"
- display_name: "Time Markers: Format"
- type: "text"
- default_value: "%Y-%m-%d %H:%M:%S"
- }
- ]
- "newInstance": (settings, newInstanceCallback) ->
- newInstanceCallback(new LineChartWidget(settings))
- class LineChartWidget
- constructor: (settings) ->
- #console.log "Initializing LineChartWidget with settings", settings
- @setSettings(settings)
- setSettings: (newSettings) =>
- oldSettings = @settings
- @settings = newSettings
- if @chart
- size =
- width: @chartElement.outerWidth()
- height: @settings["height"] * BLOCK_HEIGHT
- if @settings["size"] != size
- @chart.resize size
- if oldSettings["chart_type"] != newSettings["chart_type"]
- @chart.transform @settings["chart_type"]
- if oldSettings["legend_position"] != newSettings["legend_position"]
- @chart.destroy()
- @chart = @createChart()
- @updateTimeMarkers()
- createChart: =>
- # Groups causes flow to bug out. That needs to be worked around before
- # groups can be used.
- #groups = [x[0] for x in @columns[1..]]
- chart = c3.generate
- bindto: @chartElement[0]
- size:
- width: @chartElement.outerWidth()
- height: Number(@settings["height"]) * BLOCK_HEIGHT
- data:
- type: @settings["chart_type"]
- x: "x"
- xFormat: @settings["time_format"]
- columns: @columns
- #groups: groups
- axis:
- x:
- type: "timeseries"
- show: false
- tick:
- format: "%Y-%m-%d %H:%M:%S"
- culling: true
- fit: true
- rotate: 45
- legend:
- position: @settings["legend_position"]
- # Performance options
- interaction:
- enabled: false
- transition:
- duration: 0
- return chart
- updateChart: (oldColumns, newColumns) =>
- if oldColumns == newColumns
- return
- if @settings["flow"]
- @flowChartData(oldColumns, newColumns)
- else
- @chart.load({"columns": newColumns, "unload": true})
- flowChartData: (oldColumns, newColumns) =>
- additions = []
- $(newColumns).each (index, column) ->
- additions.push(column.slice(0))
- # The first column is assumed to be the X axis
- xColumn = newColumns[0]
- xColumnOld = oldColumns[0]
- # The amount of elements to be deleted from the new array
- deleteCount = xColumn.length - 1
- $(xColumn.slice(0).reverse()).each (index, value) ->
- # Skip the last item (the column name)
- if index == xColumn.length - 1
- return false
- if value not in xColumnOld
- deleteCount -= 1
- else
- return false
- return null
- $(additions).each (index, value) ->
- value.splice(1, deleteCount)
- @chart.flow
- columns: additions
- updateTimeMarkers: =>
- return if not @chart
- if not @settings["display_markers"]
- @chart.xgrids.remove()
- return
- #console.group("updateTimeMarkers")
- parse = d3.time.format(@settings["time_format"]).parse
- format = d3.time.format(@settings["marker_time_format"])
- tzOffset = (new Date().getTimezoneOffset() * 60)
- firstDate = parse(@columns[0][1])
- lastDate = parse(@columns[0][@columns[0].length - 1])
- #console.log "First date", firstDate
- #console.log "Last date", lastDate
- first = firstDate.valueOf() / 1000
- last = lastDate.valueOf() / 1000
- interval = Number(@settings["marker_interval"])
- overflow = (first % interval)
- firstMark = (first - overflow)
- firstMarkDate = new Date(firstMark * 1000)
- overflow = ((last + interval) % interval)
- lastMark = ((last + interval) - overflow)
- lastMarkDate = new Date(lastMark * 1000)
- #console.log "First mark", firstMarkD6
- #console.log "Last mark", lastMarkDate
- marks = []
- # The cursor is aligned to the start of the day. This allows uneven
- # intervals like 6 hours to start from 00:00 rather than (for instance)
- # 02:00.
- day = 60 * 60 * 24
- cursor = (firstMark - (firstMark % day))
- #console.log "Cursor starts at:", new Date(cursor * 1000)
- while true
- break if cursor > lastMark
- if cursor < firstMark
- cursor += interval
- continue
- # If the interval is greater than an hour, the effect of the local
- # time zone has to be counteracted
- if interval > 3600
- date = new Date((cursor + tzOffset) * 1000)
- else
- date = new Date(cursor * 1000)
- marks.push
- value: date
- text: format(date)
- cursor += interval
- #console.log "New marks generated:", marks
- @chart.xgrids marks
- #console.groupEnd()
- return null
- displayLoading: =>
- @container.empty()
- textContainer = $("<div>")
- .css
- "display": "flex",
- "height": @settings["height"] * BLOCK_HEIGHT
- "justify-content": "center"
- "align-items": "center"
- "font-size": "2em"
- .appendTo(@container)
- text = $("<div>")
- .text("Loading data...")
- .appendTo(textContainer)
- #
- # API
- #
- render: (containerElement) =>
- if containerElement
- @container = $(containerElement)
- if not @columns
- @displayLoading()
- return null
- if not @chart
- @container.empty()
- @chartElement = $("<div>")
- @container.append(@chartElement)
- @chart = @createChart()
- @updateTimeMarkers()
- return null
- getHeight: =>
- return @settings["height"]
- onSettingsChanged: (newSettings) =>
- @setSettings(newSettings)
- return null
- onCalculatedValueChanged: (settingName, newValue) =>
- if settingName == "columns"
- oldColumns = @columns
- @columns = newValue
- # First render? It's necessary to wait for a bit before drawing the
- # chart so the opening animations can finish.
- if not oldColumns
- setTimeout @render, 1000
- else
- @updateChart(oldColumns, @columns)
- @updateTimeMarkers()
- return null
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement