UNPKG

epoch-charting

Version:

A general purpose real-time charting library for building beautiful, smooth, and high performance visualizations.

1,838 lines (1,657 loc) 116 kB
var base, base1, base2, base3; if (window.Epoch == null) { window.Epoch = {}; } if ((base = window.Epoch).Chart == null) { base.Chart = {}; } if ((base1 = window.Epoch).Time == null) { base1.Time = {}; } if ((base2 = window.Epoch).Util == null) { base2.Util = {}; } if ((base3 = window.Epoch).Formats == null) { base3.Formats = {}; } Epoch.warn = function(msg) { return (console.warn || console.log)("Epoch Warning: " + msg); }; Epoch.exception = function(msg) { throw "Epoch Error: " + msg; }; Epoch.TestContext = (function() { var VOID_METHODS; VOID_METHODS = ['arc', 'arcTo', 'beginPath', 'bezierCurveTo', 'clearRect', 'clip', 'closePath', 'drawImage', 'fill', 'fillRect', 'fillText', 'moveTo', 'quadraticCurveTo', 'rect', 'restore', 'rotate', 'save', 'scale', 'scrollPathIntoView', 'setLineDash', 'setTransform', 'stroke', 'strokeRect', 'strokeText', 'transform', 'translate', 'lineTo']; function TestContext() { var i, len, method; this._log = []; for (i = 0, len = VOID_METHODS.length; i < len; i++) { method = VOID_METHODS[i]; this._makeFauxMethod(method); } } TestContext.prototype._makeFauxMethod = function(name) { return this[name] = function() { var arg; return this._log.push(name + "(" + (((function() { var i, len, results; results = []; for (i = 0, len = arguments.length; i < len; i++) { arg = arguments[i]; results.push(arg.toString()); } return results; }).apply(this, arguments)).join(',')) + ")"); }; }; TestContext.prototype.getImageData = function() { var arg; this._log.push("getImageData(" + (((function() { var i, len, results; results = []; for (i = 0, len = arguments.length; i < len; i++) { arg = arguments[i]; results.push(arg.toString()); } return results; }).apply(this, arguments)).join(',')) + ")"); return { width: 0, height: 0, resolution: 1.0, data: [] }; }; return TestContext; })(); var ref, typeFunction, hasProp = {}.hasOwnProperty; typeFunction = function(objectName) { return function(v) { return Object.prototype.toString.call(v) === ("[object " + objectName + "]"); }; }; Epoch.isArray = (ref = Array.isArray) != null ? ref : typeFunction('Array'); Epoch.isObject = typeFunction('Object'); Epoch.isString = typeFunction('String'); Epoch.isFunction = typeFunction('Function'); Epoch.isNumber = typeFunction('Number'); Epoch.isElement = function(v) { if (typeof HTMLElement !== "undefined" && HTMLElement !== null) { return v instanceof HTMLElement; } else { return (v != null) && Epoch.isObject(v) && v.nodeType === 1 && Epoch.isString(v.nodeName); } }; Epoch.isNonEmptyArray = function(v) { return Epoch.isArray(v) && v.length > 0; }; Epoch.Util.copy = function(original) { var copy, k, v; if (original == null) { return null; } copy = {}; for (k in original) { if (!hasProp.call(original, k)) continue; v = original[k]; copy[k] = v; } return copy; }; Epoch.Util.defaults = function(options, defaults) { var bothAreObjects, def, k, opt, result, v; result = Epoch.Util.copy(options); for (k in defaults) { if (!hasProp.call(defaults, k)) continue; v = defaults[k]; opt = options[k]; def = defaults[k]; bothAreObjects = Epoch.isObject(opt) && Epoch.isObject(def); if ((opt != null) && (def != null)) { if (bothAreObjects && !Epoch.isArray(opt)) { result[k] = Epoch.Util.defaults(opt, def); } else { result[k] = opt; } } else if (opt != null) { result[k] = opt; } else { result[k] = def; } } return result; }; Epoch.Util.formatSI = function(v, fixed, fixIntegers) { var base, i, label, q, ref1; if (fixed == null) { fixed = 1; } if (fixIntegers == null) { fixIntegers = false; } if (v < 1000) { q = v; if (!((q | 0) === q && !fixIntegers)) { q = q.toFixed(fixed); } return q; } ref1 = ['K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; for (i in ref1) { if (!hasProp.call(ref1, i)) continue; label = ref1[i]; base = Math.pow(10, ((i | 0) + 1) * 3); if (v >= base && v < Math.pow(10, ((i | 0) + 2) * 3)) { q = v / base; if (!((q % 1) === 0 && !fixIntegers)) { q = q.toFixed(fixed); } return q + " " + label; } } }; Epoch.Util.formatBytes = function(v, fixed, fix_integers) { var base, i, label, q, ref1; if (fixed == null) { fixed = 1; } if (fix_integers == null) { fix_integers = false; } if (v < 1024) { q = v; if (!((q % 1) === 0 && !fix_integers)) { q = q.toFixed(fixed); } return q + " B"; } ref1 = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; for (i in ref1) { if (!hasProp.call(ref1, i)) continue; label = ref1[i]; base = Math.pow(1024, (i | 0) + 1); if (v >= base && v < Math.pow(1024, (i | 0) + 2)) { q = v / base; if (!((q % 1) === 0 && !fix_integers)) { q = q.toFixed(fixed); } return q + " " + label; } } }; Epoch.Util.dasherize = function(str) { return Epoch.Util.trim(str).replace("\n", '').replace(/\s+/g, '-').toLowerCase(); }; Epoch.Util.domain = function(layers, key) { var domain, entry, j, l, layer, len, len1, ref1, set; if (key == null) { key = 'x'; } set = {}; domain = []; for (j = 0, len = layers.length; j < len; j++) { layer = layers[j]; ref1 = layer.values; for (l = 0, len1 = ref1.length; l < len1; l++) { entry = ref1[l]; if (set[entry[key]] != null) { continue; } domain.push(entry[key]); set[entry[key]] = true; } } return domain; }; Epoch.Util.trim = function(string) { if (!Epoch.isString(string)) { return null; } return string.replace(/^\s+/g, '').replace(/\s+$/g, ''); }; Epoch.Util.getComputedStyle = function(element, pseudoElement) { if (Epoch.isFunction(window.getComputedStyle)) { return window.getComputedStyle(element, pseudoElement); } else if (element.currentStyle != null) { return element.currentStyle; } }; Epoch.Util.toRGBA = function(color, opacity) { var all, b, g, parts, r, result, v; if ((parts = color.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*[0-9\.]+\)/))) { all = parts[0], r = parts[1], g = parts[2], b = parts[3]; result = "rgba(" + r + "," + g + "," + b + "," + opacity + ")"; } else if ((v = d3.rgb(color))) { result = "rgba(" + v.r + "," + v.g + "," + v.b + "," + opacity + ")"; } return result; }; Epoch.Util.getContext = function(node, type) { if (type == null) { type = '2d'; } return node.getContext(type); }; Epoch.Events = (function() { function Events() { this._events = {}; } Events.prototype.on = function(name, callback) { var base1; if (callback == null) { return; } if ((base1 = this._events)[name] == null) { base1[name] = []; } return this._events[name].push(callback); }; Events.prototype.onAll = function(map) { var callback, name, results; if (!Epoch.isObject(map)) { return; } results = []; for (name in map) { if (!hasProp.call(map, name)) continue; callback = map[name]; results.push(this.on(name, callback)); } return results; }; Events.prototype.off = function(name, callback) { var i, results; if (!Epoch.isArray(this._events[name])) { return; } if (callback == null) { return delete this._events[name]; } results = []; while ((i = this._events[name].indexOf(callback)) >= 0) { results.push(this._events[name].splice(i, 1)); } return results; }; Events.prototype.offAll = function(mapOrList) { var callback, j, len, name, results, results1; if (Epoch.isArray(mapOrList)) { results = []; for (j = 0, len = mapOrList.length; j < len; j++) { name = mapOrList[j]; results.push(this.off(name)); } return results; } else if (Epoch.isObject(mapOrList)) { results1 = []; for (name in mapOrList) { if (!hasProp.call(mapOrList, name)) continue; callback = mapOrList[name]; results1.push(this.off(name, callback)); } return results1; } }; Events.prototype.trigger = function(name) { var args, callback, fn, i, j, len, ref1, results; if (this._events[name] == null) { return; } args = (function() { var j, ref1, results; results = []; for (i = j = 1, ref1 = arguments.length; 1 <= ref1 ? j < ref1 : j > ref1; i = 1 <= ref1 ? ++j : --j) { results.push(arguments[i]); } return results; }).apply(this, arguments); ref1 = this._events[name]; results = []; for (j = 0, len = ref1.length; j < len; j++) { callback = ref1[j]; fn = null; if (Epoch.isString(callback)) { fn = this[callback]; } else if (Epoch.isFunction(callback)) { fn = callback; } if (fn == null) { Epoch.exception("Callback for event '" + name + "' is not a function or reference to a method."); } results.push(fn.apply(this, args)); } return results; }; return Events; })(); Epoch.Util.flatten = function(multiarray) { var array, item, j, l, len, len1, result; if (!Array.isArray(multiarray)) { throw new Error('Epoch.Util.flatten only accepts arrays'); } result = []; for (j = 0, len = multiarray.length; j < len; j++) { array = multiarray[j]; if (Array.isArray(array)) { for (l = 0, len1 = array.length; l < len1; l++) { item = array[l]; result.push(item); } } else { result.push(array); } } return result; }; d3.selection.prototype.width = function(value) { if ((value != null) && Epoch.isString(value)) { return this.style('width', value); } else if ((value != null) && Epoch.isNumber(value)) { return this.style('width', value + "px"); } else { return +Epoch.Util.getComputedStyle(this.node(), null).width.replace('px', ''); } }; d3.selection.prototype.height = function(value) { if ((value != null) && Epoch.isString(value)) { return this.style('height', value); } else if ((value != null) && Epoch.isNumber(value)) { return this.style('height', value + "px"); } else { return +Epoch.Util.getComputedStyle(this.node(), null).height.replace('px', ''); } }; var d3Seconds; Epoch.Formats.regular = function(d) { return d; }; Epoch.Formats.si = function(d) { return Epoch.Util.formatSI(d); }; Epoch.Formats.percent = function(d) { return (d * 100).toFixed(1) + "%"; }; Epoch.Formats.seconds = function(t) { return d3Seconds(new Date(t * 1000)); }; d3Seconds = d3.time.format('%I:%M:%S %p'); Epoch.Formats.bytes = function(d) { return Epoch.Util.formatBytes(d); }; var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Epoch.Chart.Base = (function(superClass) { var defaults, optionListeners; extend(Base, superClass); defaults = { width: 320, height: 240, dataFormat: null }; optionListeners = { 'option:width': 'dimensionsChanged', 'option:height': 'dimensionsChanged', 'layer:shown': 'layerChanged', 'layer:hidden': 'layerChanged' }; function Base(options1) { this.options = options1 != null ? options1 : {}; Base.__super__.constructor.call(this); if (this.options.model) { if (this.options.model.hasData() != null) { this.setData(this.options.model.getData(this.options.type, this.options.dataFormat)); } else { this.setData(this.options.data || []); } this.options.model.on('data:updated', (function(_this) { return function() { return _this.setDataFromModel(); }; })(this)); } else { this.setData(this.options.data || []); } if (this.options.el != null) { this.el = d3.select(this.options.el); } this.width = this.options.width; this.height = this.options.height; if (this.el != null) { if (this.width == null) { this.width = this.el.width(); } if (this.height == null) { this.height = this.el.height(); } } else { if (this.width == null) { this.width = defaults.width; } if (this.height == null) { this.height = defaults.height; } this.el = d3.select(document.createElement('DIV')).attr('width', this.width).attr('height', this.height); } this.onAll(optionListeners); } Base.prototype._getAllOptions = function() { return Epoch.Util.defaults({}, this.options); }; Base.prototype._getOption = function(key) { var parts, scope, subkey; parts = key.split('.'); scope = this.options; while (parts.length && (scope != null)) { subkey = parts.shift(); scope = scope[subkey]; } return scope; }; Base.prototype._setOption = function(key, value) { var parts, scope, subkey; parts = key.split('.'); scope = this.options; while (parts.length) { subkey = parts.shift(); if (parts.length === 0) { scope[subkey] = arguments[1]; this.trigger("option:" + arguments[0]); return; } if (scope[subkey] == null) { scope[subkey] = {}; } scope = scope[subkey]; } }; Base.prototype._setManyOptions = function(options, prefix) { var key, results, value; if (prefix == null) { prefix = ''; } results = []; for (key in options) { if (!hasProp.call(options, key)) continue; value = options[key]; if (Epoch.isObject(value)) { results.push(this._setManyOptions(value, (prefix + key) + ".")); } else { results.push(this._setOption(prefix + key, value)); } } return results; }; Base.prototype.option = function() { if (arguments.length === 0) { return this._getAllOptions(); } else if (arguments.length === 1 && Epoch.isString(arguments[0])) { return this._getOption(arguments[0]); } else if (arguments.length === 2 && Epoch.isString(arguments[0])) { return this._setOption(arguments[0], arguments[1]); } else if (arguments.length === 1 && Epoch.isObject(arguments[0])) { return this._setManyOptions(arguments[0]); } }; Base.prototype.setDataFromModel = function() { var prepared; prepared = this._prepareData(this.options.model.getData(this.options.type, this.options.dataFormat)); this.data = this._annotateLayers(prepared); return this.draw(); }; Base.prototype.setData = function(data, options) { var prepared; if (options == null) { options = {}; } prepared = this._prepareData((this.rawData = this._formatData(data))); return this.data = this._annotateLayers(prepared); }; Base.prototype._prepareData = function(data) { return data; }; Base.prototype._formatData = function(data) { return Epoch.Data.formatData(data, this.options.type, this.options.dataFormat); }; Base.prototype._annotateLayers = function(data) { var category, classes, i, layer, len; category = 1; for (i = 0, len = data.length; i < len; i++) { layer = data[i]; classes = ['layer']; classes.push("category" + category); layer.category = category; layer.visible = true; if (layer.label != null) { classes.push(Epoch.Util.dasherize(layer.label)); } layer.className = classes.join(' '); category++; } return data; }; Base.prototype._findLayer = function(labelOrIndex) { var i, index, l, layer, len, ref; layer = null; if (Epoch.isString(labelOrIndex)) { ref = this.data; for (i = 0, len = ref.length; i < len; i++) { l = ref[i]; if (l.label === labelOrIndex) { layer = l; break; } } } else if (Epoch.isNumber(labelOrIndex)) { index = parseInt(labelOrIndex); if (!(index < 0 || index >= this.data.length)) { layer = this.data[index]; } } return layer; }; Base.prototype.showLayer = function(labelOrIndex) { var layer; if (!(layer = this._findLayer(labelOrIndex))) { return; } if (layer.visible) { return; } layer.visible = true; return this.trigger('layer:shown'); }; Base.prototype.hideLayer = function(labelOrIndex) { var layer; if (!(layer = this._findLayer(labelOrIndex))) { return; } if (!layer.visible) { return; } layer.visible = false; return this.trigger('layer:hidden'); }; Base.prototype.toggleLayer = function(labelOrIndex) { var layer; if (!(layer = this._findLayer(labelOrIndex))) { return; } layer.visible = !layer.visible; if (layer.visible) { return this.trigger('layer:shown'); } else { return this.trigger('layer:hidden'); } }; Base.prototype.isLayerVisible = function(labelOrIndex) { var layer; if (!(layer = this._findLayer(labelOrIndex))) { return null; } return layer.visible; }; Base.prototype.getVisibleLayers = function() { return this.data.filter(function(layer) { return layer.visible; }); }; Base.prototype.update = function(data, draw) { if (draw == null) { draw = true; } this.setData(data); if (draw) { return this.draw(); } }; Base.prototype.draw = function() { return this.trigger('draw'); }; Base.prototype._getScaleDomain = function(givenDomain) { var layers, maxFn, minFn, values; if (Array.isArray(givenDomain)) { return givenDomain; } if (Epoch.isString(givenDomain)) { layers = this.getVisibleLayers().filter(function(l) { return l.range === givenDomain; }).map(function(l) { return l.values; }); if ((layers != null) && layers.length) { values = Epoch.Util.flatten(layers).map(function(d) { return d.y; }); minFn = function(memo, curr) { if (curr < memo) { return curr; } else { return memo; } }; maxFn = function(memo, curr) { if (curr > memo) { return curr; } else { return memo; } }; return [values.reduce(minFn, values[0]), values.reduce(maxFn, values[0])]; } } if (Array.isArray(this.options.range)) { return this.options.range; } else if (this.options.range && Array.isArray(this.options.range.left)) { return this.options.range.left; } else if (this.options.range && Array.isArray(this.options.range.right)) { return this.options.range.right; } else { return this.extent(function(d) { return d.y; }); } }; Base.prototype.extent = function(cmp) { return [ d3.min(this.getVisibleLayers(), function(layer) { return d3.min(layer.values, cmp); }), d3.max(this.getVisibleLayers(), function(layer) { return d3.max(layer.values, cmp); }) ]; }; Base.prototype.dimensionsChanged = function() { this.width = this.option('width') || this.width; this.height = this.option('height') || this.height; this.el.width(this.width); return this.el.height(this.height); }; Base.prototype.layerChanged = function() { return this.draw(); }; return Base; })(Epoch.Events); Epoch.Chart.SVG = (function(superClass) { extend(SVG, superClass); function SVG(options1) { this.options = options1 != null ? options1 : {}; SVG.__super__.constructor.call(this, this.options); if (this.el != null) { this.svg = this.el.append('svg'); } else { this.svg = d3.select(document.createElement('svg')); } this.svg.attr({ xmlns: 'http://www.w3.org/2000/svg', width: this.width, height: this.height }); } SVG.prototype.dimensionsChanged = function() { SVG.__super__.dimensionsChanged.call(this); return this.svg.attr('width', this.width).attr('height', this.height); }; return SVG; })(Epoch.Chart.Base); Epoch.Chart.Canvas = (function(superClass) { extend(Canvas, superClass); function Canvas(options1) { this.options = options1 != null ? options1 : {}; Canvas.__super__.constructor.call(this, this.options); if (this.options.pixelRatio != null) { this.pixelRatio = this.options.pixelRatio; } else if (window.devicePixelRatio != null) { this.pixelRatio = window.devicePixelRatio; } else { this.pixelRatio = 1; } this.canvas = d3.select(document.createElement('CANVAS')); this.canvas.style({ 'width': this.width + "px", 'height': this.height + "px" }); this.canvas.attr({ width: this.getWidth(), height: this.getHeight() }); if (this.el != null) { this.el.node().appendChild(this.canvas.node()); } this.ctx = Epoch.Util.getContext(this.canvas.node()); } Canvas.prototype.getWidth = function() { return this.width * this.pixelRatio; }; Canvas.prototype.getHeight = function() { return this.height * this.pixelRatio; }; Canvas.prototype.clear = function() { return this.ctx.clearRect(0, 0, this.getWidth(), this.getHeight()); }; Canvas.prototype.getStyles = function(selector) { return Epoch.QueryCSS.getStyles(selector, this.el); }; Canvas.prototype.dimensionsChanged = function() { Canvas.__super__.dimensionsChanged.call(this); this.canvas.style({ 'width': this.width + "px", 'height': this.height + "px" }); return this.canvas.attr({ width: this.getWidth(), height: this.getHeight() }); }; Canvas.prototype.redraw = function() { Epoch.QueryCSS.purge(); return this.draw(); }; return Canvas; })(Epoch.Chart.Base); var QueryCSS; QueryCSS = (function() { var CONTAINER_HASH_ATTR, PUT_EXPR, REFERENCE_CONTAINER_ID, containerCount, logging, nextContainerId, put; function QueryCSS() {} REFERENCE_CONTAINER_ID = '_canvas_css_reference'; CONTAINER_HASH_ATTR = 'data-epoch-container-id'; containerCount = 0; nextContainerId = function() { return "epoch-container-" + (containerCount++); }; PUT_EXPR = /^([^#. ]+)?(#[^. ]+)?(\.[^# ]+)?$/; logging = false; put = function(selector) { var classNames, element, id, match, tag, whole; match = selector.match(PUT_EXPR); if (match == null) { return Epoch.error('Query CSS cannot match given selector: ' + selector); } whole = match[0], tag = match[1], id = match[2], classNames = match[3]; tag = (tag != null ? tag : 'div').toUpperCase(); element = document.createElement(tag); if (id != null) { element.id = id.substr(1); } if (classNames != null) { element.className = classNames.substr(1).replace(/\./g, ' '); } return element; }; QueryCSS.log = function(b) { return logging = b; }; QueryCSS.cache = {}; QueryCSS.styleList = ['fill', 'stroke', 'stroke-width']; QueryCSS.container = null; QueryCSS.purge = function() { return QueryCSS.cache = {}; }; QueryCSS.getContainer = function() { var container; if (QueryCSS.container != null) { return QueryCSS.container; } container = document.createElement('DIV'); container.id = REFERENCE_CONTAINER_ID; document.body.appendChild(container); return QueryCSS.container = d3.select(container); }; QueryCSS.hash = function(selector, container) { var containerId; containerId = container.attr(CONTAINER_HASH_ATTR); if (containerId == null) { containerId = nextContainerId(); container.attr(CONTAINER_HASH_ATTR, containerId); } return containerId + "__" + selector; }; QueryCSS.getStyles = function(selector, container) { var cache, cacheKey, el, element, i, j, k, len, len1, len2, name, parent, parentNode, parents, ref, ref1, ref2, root, sel, selectorList, styles, subSelector; cacheKey = QueryCSS.hash(selector, container); cache = QueryCSS.cache[cacheKey]; if (cache != null) { return cache; } parents = []; parentNode = container.node().parentNode; while ((parentNode != null) && parentNode.nodeName.toLowerCase() !== 'body') { parents.unshift(parentNode); parentNode = parentNode.parentNode; } parents.push(container.node()); selectorList = []; for (i = 0, len = parents.length; i < len; i++) { element = parents[i]; sel = element.nodeName.toLowerCase(); if ((element.id != null) && element.id.length > 0) { sel += '#' + element.id; } if ((element.className != null) && element.className.length > 0) { sel += '.' + Epoch.Util.trim(element.className).replace(/\s+/g, '.'); } selectorList.push(sel); } selectorList.push('svg'); ref1 = Epoch.Util.trim(selector).split(/\s+/); for (j = 0, len1 = ref1.length; j < len1; j++) { subSelector = ref1[j]; selectorList.push(subSelector); } if (logging) { console.log(selectorList); } parent = root = put(selectorList.shift()); while (selectorList.length) { el = put(selectorList.shift()); parent.appendChild(el); parent = el; } if (logging) { console.log(root); } QueryCSS.getContainer().node().appendChild(root); ref = d3.select('#' + REFERENCE_CONTAINER_ID + ' ' + selector); styles = {}; ref2 = QueryCSS.styleList; for (k = 0, len2 = ref2.length; k < len2; k++) { name = ref2[k]; styles[name] = ref.style(name); } QueryCSS.cache[cacheKey] = styles; QueryCSS.getContainer().html(''); return styles; }; return QueryCSS; })(); Epoch.QueryCSS = QueryCSS; var applyLayerLabel, base, hasProp = {}.hasOwnProperty, slice = [].slice; if (Epoch.Data == null) { Epoch.Data = {}; } if ((base = Epoch.Data).Format == null) { base.Format = {}; } applyLayerLabel = function(layer, options, i, keys) { var autoLabels, keyLabels, label, labels, ref; if (keys == null) { keys = []; } ref = [options.labels, options.autoLabels, options.keyLabels], labels = ref[0], autoLabels = ref[1], keyLabels = ref[2]; if ((labels != null) && Epoch.isArray(labels) && labels.length > i) { layer.label = labels[i]; } else if (keyLabels && 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; }; Epoch.Data.Format.array = (function() { var buildLayers, defaultOptions, format, formatBasicPlot, formatHeatmap, formatPie, formatTimePlot; defaultOptions = { x: function(d, i) { return i; }, y: function(d, i) { return d; }, time: function(d, i, startTime) { return parseInt(startTime) + parseInt(i); }, type: 'area', autoLabels: false, labels: [], startTime: parseInt(new Date().getTime() / 1000) }; buildLayers = function(data, options, mapFn) { var i, result, series; result = []; if (Epoch.isArray(data[0])) { for (i in data) { if (!hasProp.call(data, i)) continue; series = data[i]; result.push(applyLayerLabel({ values: series.map(mapFn) }, options, parseInt(i))); } } else { result.push(applyLayerLabel({ values: data.map(mapFn) }, options, 0)); } return result; }; formatBasicPlot = function(data, options) { return buildLayers(data, options, function(d, i) { return { x: options.x(d, i), y: options.y(d, i) }; }); }; formatTimePlot = function(data, options) { return buildLayers(data, options, function(d, i) { return { time: options.time(d, i, options.startTime), y: options.y(d, i) }; }); }; formatHeatmap = function(data, options) { return buildLayers(data, options, function(d, i) { return { time: options.time(d, i, options.startTime), histogram: d }; }); }; formatPie = function(data, options) { var i, result, v; result = []; for (i in data) { if (!hasProp.call(data, i)) continue; v = data[i]; if (!Epoch.isNumber(data[0])) { return []; } result.push(applyLayerLabel({ value: v }, options, i)); } return result; }; format = function(data, options) { var opt; if (data == null) { data = []; } if (options == null) { options = {}; } if (!Epoch.isNonEmptyArray(data)) { return []; } opt = Epoch.Util.defaults(options, defaultOptions); if (opt.type === 'time.heatmap') { return formatHeatmap(data, opt); } else if (opt.type.match(/^time\./)) { return formatTimePlot(data, opt); } else if (opt.type === 'pie') { return formatPie(data, opt); } else { return formatBasicPlot(data, opt); } }; format.entry = function(datum, options) { var d, data, k, layer, len, opt, ref, results; if (options == null) { options = {}; } if (options.type === 'time.gauge') { if (datum == null) { return 0; } opt = Epoch.Util.defaults(options, defaultOptions); d = Epoch.isArray(datum) ? datum[0] : datum; return opt.y(d, 0); } if (datum == null) { return []; } if (options.startTime == null) { options.startTime = parseInt(new Date().getTime() / 1000); } if (Epoch.isArray(datum)) { data = datum.map(function(d) { return [d]; }); } else { data = [datum]; } ref = format(data, options); results = []; for (k = 0, len = ref.length; k < len; k++) { layer = ref[k]; results.push(layer.values[0]); } return results; }; return format; })(); Epoch.Data.Format.tuple = (function() { var buildLayers, defaultOptions, format; defaultOptions = { x: function(d, i) { return d; }, y: function(d, i) { return d; }, time: function(d, i) { return d; }, type: 'area', autoLabels: false, labels: [] }; buildLayers = function(data, options, mapFn) { var i, result, series; if (!Epoch.isArray(data[0])) { return []; } result = []; if (Epoch.isArray(data[0][0])) { for (i in data) { if (!hasProp.call(data, i)) continue; series = data[i]; result.push(applyLayerLabel({ values: series.map(mapFn) }, options, parseInt(i))); } } else { result.push(applyLayerLabel({ values: data.map(mapFn) }, options, 0)); } return result; }; format = function(data, options) { var opt; if (data == null) { data = []; } if (options == null) { options = {}; } if (!Epoch.isNonEmptyArray(data)) { return []; } opt = Epoch.Util.defaults(options, defaultOptions); if (opt.type === 'pie' || opt.type === 'time.heatmap' || opt.type === 'time.gauge') { return []; } else if (opt.type.match(/^time\./)) { return buildLayers(data, opt, function(d, i) { return { time: opt.time(d[0], parseInt(i)), y: opt.y(d[1], parseInt(i)) }; }); } else { return buildLayers(data, opt, function(d, i) { return { x: opt.x(d[0], parseInt(i)), y: opt.y(d[1], parseInt(i)) }; }); } }; format.entry = function(datum, options) { var data, k, layer, len, ref, results; if (options == null) { options = {}; } if (datum == null) { return []; } if (options.startTime == null) { options.startTime = parseInt(new Date().getTime() / 1000); } if (Epoch.isArray(datum) && Epoch.isArray(datum[0])) { data = datum.map(function(d) { return [d]; }); } else { data = [datum]; } ref = format(data, options); results = []; for (k = 0, len = ref.length; k < len; k++) { layer = ref[k]; results.push(layer.values[0]); } return results; }; return format; })(); Epoch.Data.Format.keyvalue = (function() { var buildLayers, defaultOptions, format, formatBasicPlot, formatTimePlot; defaultOptions = { type: 'area', x: function(d, i) { return parseInt(i); }, y: function(d, i) { return d; }, time: function(d, i, startTime) { return parseInt(startTime) + parseInt(i); }, labels: [], autoLabels: false, keyLabels: true, startTime: parseInt(new Date().getTime() / 1000) }; buildLayers = function(data, keys, options, mapFn) { var d, i, j, key, result, values; result = []; for (j in keys) { if (!hasProp.call(keys, j)) continue; key = keys[j]; values = []; for (i in data) { if (!hasProp.call(data, i)) continue; d = data[i]; values.push(mapFn(d, key, parseInt(i))); } result.push(applyLayerLabel({ values: values }, options, parseInt(j), keys)); } return result; }; formatBasicPlot = function(data, keys, options) { return buildLayers(data, keys, options, function(d, key, i) { var x; if (Epoch.isString(options.x)) { x = d[options.x]; } else { x = options.x(d, parseInt(i)); } return { x: x, y: options.y(d[key], parseInt(i)) }; }); }; formatTimePlot = function(data, keys, options, rangeName) { if (rangeName == null) { rangeName = 'y'; } return buildLayers(data, keys, options, function(d, key, i) { var value; 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)); return value; }); }; format = function(data, keys, options) { var opt; if (data == null) { data = []; } if (keys == null) { keys = []; } if (options == null) { options = {}; } if (!(Epoch.isNonEmptyArray(data) && Epoch.isNonEmptyArray(keys))) { return []; } opt = Epoch.Util.defaults(options, defaultOptions); if (opt.type === 'pie' || opt.type === 'time.gauge') { return []; } else if (opt.type === 'time.heatmap') { return formatTimePlot(data, keys, opt, 'histogram'); } else if (opt.type.match(/^time\./)) { return formatTimePlot(data, keys, opt); } else { return formatBasicPlot(data, keys, opt); } }; format.entry = function(datum, keys, options) { var k, layer, len, ref, results; if (keys == null) { keys = []; } if (options == null) { options = {}; } if (!((datum != null) && Epoch.isNonEmptyArray(keys))) { return []; } if (options.startTime == null) { options.startTime = parseInt(new Date().getTime() / 1000); } ref = format([datum], keys, options); results = []; for (k = 0, len = ref.length; k < len; k++) { layer = ref[k]; results.push(layer.values[0]); } return results; }; return format; })(); Epoch.data = function() { var args, formatFn, formatter; formatter = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; if ((formatFn = Epoch.Data.Format[formatter]) == null) { return []; } return formatFn.apply(formatFn, args); }; Epoch.Data.formatData = function(data, type, dataFormat) { var a, args, k, len, opts, ref; if (data == null) { data = []; } if (!Epoch.isNonEmptyArray(data)) { return data; } if (Epoch.isString(dataFormat)) { opts = { type: type }; return Epoch.data(dataFormat, data, opts); } if (!Epoch.isObject(dataFormat)) { return data; } if (!((dataFormat.name != null) && Epoch.isString(dataFormat.name))) { return data; } if (Epoch.Data.Format[dataFormat.name] == null) { return data; } args = [dataFormat.name, data]; if ((dataFormat["arguments"] != null) && Epoch.isArray(dataFormat["arguments"])) { ref = dataFormat["arguments"]; for (k = 0, len = ref.length; k < len; k++) { a = ref[k]; args.push(a); } } if (dataFormat.options != null) { opts = dataFormat.options; if (type != null) { if (opts.type == null) { opts.type = type; } } args.push(opts); } else if (type != null) { args.push({ type: type }); } return Epoch.data.apply(Epoch.data, args); }; Epoch.Data.formatEntry = function(datum, type, format) { var a, args, dataFormat, entry, k, len, opts, ref; if (format == null) { return datum; } if (Epoch.isString(format)) { opts = { type: type }; return Epoch.Data.Format[format].entry(datum, opts); } if (!Epoch.isObject(format)) { return datum; } if (!((format.name != null) && Epoch.isString(format.name))) { return datum; } if (Epoch.Data.Format[format.name] == null) { return datum; } dataFormat = Epoch.Util.defaults(format, {}); args = [datum]; if ((dataFormat["arguments"] != null) && Epoch.isArray(dataFormat["arguments"])) { ref = dataFormat["arguments"]; for (k = 0, len = ref.length; k < len; k++) { a = ref[k]; args.push(a); } } if (dataFormat.options != null) { opts = dataFormat.options; opts.type = type; args.push(opts); } else if (type != null) { args.push({ type: type }); } entry = Epoch.Data.Format[dataFormat.name].entry; return entry.apply(entry, args); }; var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Epoch.Model = (function(superClass) { var defaults; extend(Model, superClass); defaults = { dataFormat: null }; function Model(options) { if (options == null) { options = {}; } Model.__super__.constructor.call(this); options = Epoch.Util.defaults(options, defaults); this.dataFormat = options.dataFormat; this.data = options.data; this.loading = false; } Model.prototype.setData = function(data) { this.data = data; return this.trigger('data:updated'); }; Model.prototype.push = function(entry) { this.entry = entry; return this.trigger('data:push'); }; Model.prototype.hasData = function() { return this.data != null; }; Model.prototype.getData = function(type, dataFormat) { if (dataFormat == null) { dataFormat = this.dataFormat; } return Epoch.Data.formatData(this.data, type, dataFormat); }; Model.prototype.getNext = function(type, dataFormat) { if (dataFormat == null) { dataFormat = this.dataFormat; } return Epoch.Data.formatEntry(this.entry, type, dataFormat); }; return Model; })(Epoch.Events); var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Epoch.Chart.Plot = (function(superClass) { var defaultAxisMargins, defaults, optionListeners; extend(Plot, superClass); defaults = { domain: null, range: null, axes: ['left', 'bottom'], ticks: { top: 14, bottom: 14, left: 5, right: 5 }, tickFormats: { top: Epoch.Formats.regular, bottom: Epoch.Formats.regular, left: Epoch.Formats.si, right: Epoch.Formats.si } }; defaultAxisMargins = { top: 25, right: 50, bottom: 25, left: 50 }; optionListeners = { 'option:margins.top': 'marginsChanged', 'option:margins.right': 'marginsChanged', 'option:margins.bottom': 'marginsChanged', 'option:margins.left': 'marginsChanged', 'option:axes': 'axesChanged', 'option:ticks.top': 'ticksChanged', 'option:ticks.right': 'ticksChanged', 'option:ticks.bottom': 'ticksChanged', 'option:ticks.left': 'ticksChanged', 'option:tickFormats.top': 'tickFormatsChanged', 'option:tickFormats.right': 'tickFormatsChanged', 'option:tickFormats.bottom': 'tickFormatsChanged', 'option:tickFormats.left': 'tickFormatsChanged', 'option:domain': 'domainChanged', 'option:range': 'rangeChanged' }; function Plot(options) { var givenMargins, i, len, pos, ref; this.options = options != null ? options : {}; givenMargins = Epoch.Util.copy(this.options.margins) || {}; Plot.__super__.constructor.call(this, this.options = Epoch.Util.defaults(this.options, defaults)); this.margins = {}; ref = ['top', 'right', 'bottom', 'left']; for (i = 0, len = ref.length; i < len; i++) { pos = ref[i]; this.margins[pos] = (this.options.margins != null) && (this.options.margins[pos] != null) ? this.options.margins[pos] : this.hasAxis(pos) ? defaultAxisMargins[pos] : 6; } this.g = this.svg.append("g").attr("transform", "translate(" + this.margins.left + ", " + this.margins.top + ")"); this.onAll(optionListeners); } Plot.prototype.setTickFormat = function(axis, fn) { return this.options.tickFormats[axis] = fn; }; Plot.prototype.hasAxis = function(axis) { return this.options.axes.indexOf(axis) > -1; }; Plot.prototype.innerWidth = function() { return this.width - (this.margins.left + this.margins.right); }; Plot.prototype.innerHeight = function() { return this.height - (this.margins.top + this.margins.bottom); }; Plot.prototype.x = function() { var domain, ref; domain = (ref = this.options.domain) != null ? ref : this.extent(function(d) { return d.x; }); return d3.scale.linear().domain(domain).range([0, this.innerWidth()]); }; Plot.prototype.y = function(givenDomain) { return d3.scale.linear().domain(this._getScaleDomain(givenDomain)).range([this.innerHeight(), 0]); }; Plot.prototype.bottomAxis = function() { return d3.svg.axis().scale(this.x()).orient('bottom').ticks(this.options.ticks.bottom).tickFormat(this.options.tickFormats.bottom); }; Plot.prototype.topAxis = function() { return d3.svg.axis().scale(this.x()).orient('top').ticks(this.options.ticks.top).tickFormat(this.options.tickFormats.top); }; Plot.prototype.leftAxis = function() { var range; range = this.options.range ? this.options.range.left : null; return d3.svg.axis().scale(this.y(range)).orient('left').ticks(this.options.ticks.left).tickFormat(this.options.tickFormats.left); }; Plot.prototype.rightAxis = function() { var range; range = this.options.range ? this.options.range.right : null; return d3.svg.axis().scale(this.y(range)).orient('right').ticks(this.options.ticks.right).tickFormat(this.options.tickFormats.right); }; Plot.prototype.draw = function() { if (this._axesDrawn) { this._redrawAxes(); } else { this._drawAxes(); } return Plot.__super__.draw.call(this); }; Plot.prototype._redrawAxes = function() { if (this.hasAxis('bottom')) { this.g.selectAll('.x.axis.bottom').transition().duration(500).ease('linear').call(this.bottomAxis()); } if (this.hasAxis('top')) { this.g.selectAll('.x.axis.top').transition().duration(500).ease('linear').call(this.topAxis()); } if (this.hasAxis('left')) { this.g.selectAll('.y.axis.left').transition().duration(500).ease('linear').call(this.leftAxis()); } if (this.hasAxis('right')) { return this.g.selectAll('.y.axis.right').transition().duration(500).ease('linear').call(this.rightAxis()); } }; Plot.prototype._drawAxes = function() { if (this.hasAxis('bottom')) { this.g.append("g").attr("class", "x axis bottom").attr("transform", "translate(0, " + (this.innerHeight()) + ")").call(this.bottomAxis()); } if (this.hasAxis('top')) { this.g.append("g").attr('class', 'x axis top').call(this.topAxis()); } if (this.hasAxis('left')) { this.g.append("g").attr("class", "y axis left").call(this.leftAxis()); } if (this.hasAxis('right')) { this.g.append('g').attr('class', 'y axis right').attr('transform', "translate(" + (this.innerWidth()) + ", 0)").call(this.rightAxis()); } return this._axesDrawn = true; }; Plot.prototype.dimensionsChanged = function() { Plot.__super__.dimensionsChanged.call(this); this.g.selectAll('.axis').remove(); this._axesDrawn = false; return this.draw(); }; Plot.prototype.marginsChanged = function() { var pos, ref, size; if (this.options.margins == null) { return; } ref = this.options.margins; for (pos in ref) { if (!hasProp.call(ref, pos)) continue; size = ref[pos]; if (size == null) { this.margins[pos] = 6; } else { this.margins[pos] = size; } } this.g.transition().duration(750).attr("transform", "translate(" + this.margins.left + ", " + this.margins.top + ")"); return this.draw(); }; Plot.prototype.axesChanged = function() { var i, len, pos, ref; ref = ['top', 'right', 'bottom', 'left']; for (i = 0, len = ref.length; i < len; i++) { pos = ref[i]; if ((this.options.margins != null) && (this.options.margins[pos] != null)) { continue; } if (this.hasAxis(pos)) { this.margins[pos] = defaultAxisMargins[pos]; } else { this.margins[pos] = 6; } } this.g.transition().duration(750).attr("transform", "translate(" + this.margins.left + ", " + this.margins.top + ")"); this.g.selectAll('.axis').remove(); this._axesDrawn = false; return this.draw(); }; Plot.prototype.ticksChanged = function() { return this.draw(); }; Plot.prototype.tickFormatsChanged = function() { return this.draw(); }; Plot.prototype.domainChanged = function() { return this.draw(); }; Plot.prototype.rangeChanged = function() { return this.draw(); }; return Plot; })(Epoch.Chart.SVG); var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Epoch.Chart.Area = (function(superClass) { extend(Area, superClass); function Area(options) { var base; this.options = options != null ? options : {}; if ((base = this.options).type == null) { base.type = 'area'; } Area.__super__.constructor.call(this, this.options); this.draw(); } Area.prototype.y = function() { var a, i, k, layer, len, ref, ref1, ref2, v; a = []; ref = this.getVisibleLayers(); for (i = 0, len = ref.length; i < len; i++) { layer = ref[i]; ref1 = layer.values; for (k in ref1) { if (!hasProp.call(ref1, k)) continue; v = ref1[k]; if (a[k] != null) { a[k] += v.y; } if (a[k] == null) { a[k] = v.y; } } } return d3.scale.linear().domain((ref2 = this.options.range) != null ? ref2 : [0, d3.max(a)]).range([this.height - this.margins.top - this.margins.bottom, 0]); }; Area.prototype.draw = function() { var area, data, layer, layers, ref, stack, x, y; ref = [this.x(), this.y(), this.getVisibleLayers()], x = ref[0], y = ref[1], layers = ref[2]; this.g.selectAll('.layer').remove(); if (layers.length === 0) { return; } area = d3.svg.area().x(function(d) { return x(d.x); }).y0(function(d) { return y(d.y0); }).y1(function(d) { return y(d.y0 + d.y); }); stack = d3.layout.stack().values(function(d) { return d.values; }); data = stack(layers); layer = this.g.selectAll('.layer').data(layers, function(d) { return d.category; }); layer.select('.area').attr('d', function(d) { return area(d.values); }); layer.enter().append('g').attr('class', function(d) { return d.className; }); layer.append('path').attr('class', 'area').attr('d', function(d) { return area(d.values); }); return Area.__super__.draw.call(this); }; return Area; })(Epoch.Chart.Plot); var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Epoch.Chart.Bar = (function(superClass) { var defaults, horizontal_defaults, horizontal_specific, optionListeners; extend(Bar, superClass); defaults = { type: 'bar', style: 'grouped', orientation: 'vertical', padding: { bar: 0.08, group: 0.1 }, outerPadding: { bar: 0.08, group: 0.1 } }; horizontal_specific = {