summaryrefslogtreecommitdiffstats
path: root/debian/missing-sources/epoch/src/data.coffee
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/missing-sources/epoch/src/data.coffee311
1 files changed, 311 insertions, 0 deletions
diff --git a/debian/missing-sources/epoch/src/data.coffee b/debian/missing-sources/epoch/src/data.coffee
new file mode 100644
index 0000000..7627fd4
--- /dev/null
+++ b/debian/missing-sources/epoch/src/data.coffee
@@ -0,0 +1,311 @@
+Epoch.Data ?= {}
+Epoch.Data.Format ?= {}
+
+# Private Helper Function for data formats below
+applyLayerLabel = (layer, options, i, keys=[]) ->
+ [labels, autoLabels, keyLabels] = [options.labels, options.autoLabels, options.keyLabels]
+ if labels? and Epoch.isArray(labels) and labels.length > i
+ layer.label = labels[i]
+ else if keyLabels and keys.length > i
+ layer.label = keys[i]
+ else if autoLabels
+ label = []
+ while i >= 0
+ label.push String.fromCharCode(65+(i%26))
+ i -= 26
+ layer.label = label.join('')
+ return layer
+
+# Formats a given input array for the chart of the specified type. Notes:
+#
+# * Basic pie charts require a flat array of numbers
+# * Real-time histogram charts require sparse histogram objects
+#
+# @param data Data array to format (can be multidimensional to allow for multiple layers).
+# @option options [String] type Type of chart for which to format the data.
+# @option options [Function] x(d, i) Maps the data to x values given a data point and the index of the point.
+# @option options [Function] y(d, i) Maps the data to y values given a data point and the index of the point.
+# @option options [Function] time(d, i, startTime) Maps the data to time values for real-time plots given the point and index.
+# @option options [Array] labels Labels to apply to each data layer.
+# @option options [Boolean] autoLabels Apply labels of ascending capital letters to each layer if true.
+# @option options [Number] startTime Unix timestamp used as the starting point for auto acsending times in
+# real-time data formatting.
+Epoch.Data.Format.array = (->
+ defaultOptions =
+ x: (d, i) -> i
+ y: (d, i) -> d
+ time: (d, i, startTime) -> parseInt(startTime) + parseInt(i)
+ type: 'area'
+ autoLabels: false
+ labels: []
+ startTime: parseInt(new Date().getTime() / 1000)
+
+ buildLayers = (data, options, mapFn) ->
+ result = []
+ if Epoch.isArray(data[0])
+ for own i, series of data
+ result.push applyLayerLabel({values: series.map(mapFn)}, options, parseInt(i))
+ else
+ result.push applyLayerLabel({values: data.map(mapFn)}, options, 0)
+ return result
+
+ formatBasicPlot = (data, options) ->
+ buildLayers data, options, (d, i) ->
+ { x: options.x(d, i), y: options.y(d, i) }
+
+ formatTimePlot = (data, options) ->
+ buildLayers data, options, (d, i) ->
+ { time: options.time(d, i, options.startTime), y: options.y(d, i) }
+
+ formatHeatmap = (data, options) ->
+ buildLayers data, options, (d, i) ->
+ { time: options.time(d, i, options.startTime), histogram: d }
+
+ formatPie = (data, options) ->
+ result = []
+ for own i, v of data
+ return [] unless Epoch.isNumber(data[0])
+ result.push applyLayerLabel({ value: v }, options, i)
+ return result
+
+ format = (data=[], options={}) ->
+ return [] unless Epoch.isNonEmptyArray(data)
+ opt = Epoch.Util.defaults options, defaultOptions
+
+ if opt.type == 'time.heatmap'
+ formatHeatmap data, opt
+ else if opt.type.match /^time\./
+ formatTimePlot data, opt
+ else if opt.type == 'pie'
+ formatPie data, opt
+ else
+ formatBasicPlot data, opt
+
+ format.entry = (datum, options={}) ->
+ if options.type == 'time.gauge'
+ return 0 unless datum?
+ opt = Epoch.Util.defaults options, defaultOptions
+ d = if Epoch.isArray(datum) then datum[0] else datum
+ return opt.y(d, 0)
+
+ return [] unless datum?
+ unless options.startTime?
+ options.startTime = parseInt(new Date().getTime() / 1000)
+
+ if Epoch.isArray(datum)
+ data = datum.map (d) -> [d]
+ else
+ data = [datum]
+
+ (layer.values[0] for layer in format(data, options))
+
+ return format
+)()
+
+# Formats an input array of tuples such that the first element of the tuple is set
+# as the x-coordinate and the second element as the y-coordinate. Supports layers
+# of tupled series. For real-time plots the first element of a tuple is set as the
+# time component of the value.
+#
+# This formatter will return an empty array if the chart <code>type</code> option is
+# set as 'time.heatmap', 'time.gauge', or 'pie'.
+#
+# @param data Data array to format (can be multidimensional to allow for multiple layers).
+# @option options [String] type Type of chart for which to format the data.
+# @option options [Function] x(d, i) Maps the data to x values given a data point and the index of the point.
+# @option options [Function] y(d, i) Maps the data to y values given a data point and the index of the point.
+# @option options [Function] time(d, i, startTime) Maps the data to time values for real-time plots given the point and index.
+# @option options [Array] labels Labels to apply to each data layer.
+# @option options [Boolean] autoLabels Apply labels of ascending capital letters to each layer if true.
+Epoch.Data.Format.tuple = (->
+ defaultOptions =
+ x: (d, i) -> d
+ y: (d, i) -> d
+ time: (d, i) -> d
+ type: 'area'
+ autoLabels: false
+ labels: []
+
+ buildLayers = (data, options, mapFn) ->
+ return [] unless Epoch.isArray(data[0])
+ result = []
+ if Epoch.isArray(data[0][0])
+ for own i, series of data
+ result.push applyLayerLabel({values: series.map(mapFn)}, options, parseInt(i))
+ else
+ result.push applyLayerLabel({values: data.map(mapFn)}, options, 0)
+ return result
+
+ format = (data=[], options={}) ->
+ return [] unless Epoch.isNonEmptyArray(data)
+ opt = Epoch.Util.defaults options, defaultOptions
+
+ if opt.type == 'pie' or opt.type == 'time.heatmap' or opt.type == 'time.gauge'
+ return []
+ else if opt.type.match /^time\./
+ buildLayers data, opt, (d, i) ->
+ {time: opt.time(d[0], parseInt(i)), y: opt.y(d[1], parseInt(i))}
+ else
+ buildLayers data, opt, (d, i) ->
+ {x: opt.x(d[0], parseInt(i)), y: opt.y(d[1], parseInt(i))}
+
+ format.entry = (datum, options={}) ->
+ return [] unless datum?
+ unless options.startTime?
+ options.startTime = parseInt(new Date().getTime() / 1000)
+
+ if Epoch.isArray(datum) and Epoch.isArray(datum[0])
+ data = datum.map (d) -> [d]
+ else
+ data = [datum]
+
+ (layer.values[0] for layer in format(data, options))
+
+ return format
+)()
+
+# This formatter expects to be passed a flat array of objects and a list of keys.
+# It then extracts the value for each key across each of the objects in the array
+# to produce multi-layer plot data of the given chart type. Note that this formatter
+# also can be passed an <code>x</code> or <code>time</code> option as a string that
+# allows the programmer specify a key to use for the value of the first component
+# (x or time) of each resulting layer value.
+#
+# Note that this format does not work with basic pie charts nor real-time gauge charts.
+#
+# @param [Array] data Flat array of objects to format.
+# @param [Array] keys List of keys used to extract data from each of the objects.
+# @option options [String] type Type of chart for which to format the data.
+# @option options [Function, String] x Either the key to use for the x-componet of
+# the resulting values or a function of the data at that point and index of the data.
+# @option options [Function, String] time Either an object key or function to use for the
+# time-component of resulting real-time plot values.
+# @option options [Function] y(d, i) Maps the data to y values given a data point and the index of the point.
+# @option options [Array] labels Labels to apply to each data layer.
+# @option options [Boolean] autoLabels Apply labels of ascending capital letters to each layer if true.
+# @option options [Boolean] keyLabels Apply labels using the keys passed to the formatter (defaults to true).
+# @option options [Number] startTime Unix timestamp used as the starting point for auto acsending times in
+# real-time data formatting.
+Epoch.Data.Format.keyvalue = (->
+ defaultOptions =
+ type: 'area',
+ x: (d, i) -> parseInt(i)
+ y: (d, i) -> d
+ time: (d, i, startTime) -> parseInt(startTime) + parseInt(i)
+ labels: []
+ autoLabels: false
+ keyLabels: true
+ startTime: parseInt(new Date().getTime() / 1000)
+
+ buildLayers = (data, keys, options, mapFn) ->
+ result = []
+ for own j, key of keys
+ values = []
+ for own i, d of data
+ values.push mapFn(d, key, parseInt(i))
+ result.push applyLayerLabel({ values: values }, options, parseInt(j), keys)
+ return result
+
+ formatBasicPlot = (data, keys, options) ->
+ buildLayers data, keys, options, (d, key, i) ->
+ if Epoch.isString(options.x)
+ x = d[options.x]
+ else
+ x = options.x(d, parseInt(i))
+ { x: x, y: options.y(d[key], parseInt(i)) }
+
+ formatTimePlot = (data, keys, options, rangeName='y') ->
+ buildLayers data, keys, options, (d, key, i) ->
+ if Epoch.isString(options.time)
+ value = { time: d[options.time] }
+ else
+ value = { time: options.time(d, parseInt(i), options.startTime) }
+ value[rangeName] = options.y(d[key], parseInt(i))
+ value
+
+ format = (data=[], keys=[], options={}) ->
+ return [] unless Epoch.isNonEmptyArray(data) and Epoch.isNonEmptyArray(keys)
+ opt = Epoch.Util.defaults options, defaultOptions
+
+ if opt.type == 'pie' or opt.type == 'time.gauge'
+ return []
+ else if opt.type == 'time.heatmap'
+ formatTimePlot data, keys, opt, 'histogram'
+ else if opt.type.match /^time\./
+ formatTimePlot data, keys, opt
+ else
+ formatBasicPlot data, keys, opt
+
+ format.entry = (datum, keys=[], options={}) ->
+ return [] unless datum? and Epoch.isNonEmptyArray(keys)
+ unless options.startTime?
+ options.startTime = parseInt(new Date().getTime() / 1000)
+ (layer.values[0] for layer in format([datum], keys, options))
+
+ return format
+)()
+
+# Convenience data formatting method for easily accessing the various formatters.
+# @param [String] formatter Name of the formatter to use.
+# @param [Array] data Data to format.
+# @param [Object] options Options to pass to the formatter (if any).
+Epoch.data = (formatter, args...) ->
+ return [] unless (formatFn = Epoch.Data.Format[formatter])?
+ formatFn.apply formatFn, args
+
+
+# Method used by charts and models for handling option based data formatting.
+# Abstracted here because we'd like to allow models and indivisual charts to
+# perform this action depending on the context.
+Epoch.Data.formatData = (data=[], type, dataFormat) ->
+ return data unless Epoch.isNonEmptyArray(data)
+
+ if Epoch.isString(dataFormat)
+ opts = { type: type }
+ return Epoch.data(dataFormat, data, opts)
+
+ return data unless Epoch.isObject(dataFormat)
+ return data unless dataFormat.name? and Epoch.isString(dataFormat.name)
+ return data unless Epoch.Data.Format[dataFormat.name]?
+
+ args = [dataFormat.name, data]
+ if dataFormat.arguments? and Epoch.isArray(dataFormat.arguments)
+ args.push(a) for a in dataFormat.arguments
+
+ if dataFormat.options?
+ opts = dataFormat.options
+ if type?
+ opts.type ?= type
+ args.push opts
+ else if type?
+ args.push {type: type}
+
+ Epoch.data.apply(Epoch.data, args)
+
+# Method used to format incoming entries for real-time charts.
+Epoch.Data.formatEntry = (datum, type, format) ->
+ return datum unless format?
+
+ if Epoch.isString(format)
+ opts = { type: type }
+ return Epoch.Data.Format[format].entry datum, opts
+
+ return datum unless Epoch.isObject(format)
+ return datum unless format.name? and Epoch.isString(format.name)
+ return datum unless Epoch.Data.Format[format.name]?
+
+ dataFormat = Epoch.Util.defaults format, {}
+
+ args = [datum]
+ if dataFormat.arguments? and Epoch.isArray(dataFormat.arguments)
+ args.push(a) for a in dataFormat.arguments
+
+ if dataFormat.options?
+ opts = dataFormat.options
+ opts.type = type
+ args.push opts
+ else if type?
+ args.push {type: type}
+
+ entry = Epoch.Data.Format[dataFormat.name].entry
+ entry.apply entry, args