From 61848e29995f3d86b72d35fbb5a7e536407b17e3 Mon Sep 17 00:00:00 2001 From: hamilton Date: Wed, 17 Dec 2014 16:49:10 -0800 Subject: [PATCH] Should fix most of #216, #281, #282, and probably a few others. We are now namespacing. MG is the top level. --- README.md | 2 + dist/metricsgraphics.js | 7138 +++++++++++++++++---------------- dist/metricsgraphics.min.js | 592 +-- examples/dev.htm | 1 + examples/examples.htm | 2 +- examples/index.htm | 14 +- examples/js/main.js | 126 +- gulp/index.js | 7 +- src/js/charts/line.js | 8 +- src/js/charts/table.js | 4 +- src/js/common/data_graphic.js | 38 +- src/js/end.js | 2 +- src/js/layout/button.js | 2 +- src/js/misc/process.js | 6 +- src/js/misc/utility.js | 36 +- 15 files changed, 3776 insertions(+), 4202 deletions(-) diff --git a/README.md b/README.md index 00ca6804e8..61eaf8e7aa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ +(disclaimer: right now please use v1.1 and not the most recent of master. We are migrating to v2.0.0 at the moment and the documentation for v2.0 is unfinished.) + _MetricsGraphics.js_ is a library optimized for visualizing and laying out time-series data. At under 50KB (minified), it provides a simple way to produce common types of graphics in a principled, consistent and responsive way. The library currently supports line charts, scatterplots and histograms as well as features like rug plots and basic linear regression. A sample set of examples may be found on [the examples page](http://metricsgraphicsjs.org). The example below demonstrates how easy it is to produce a graphic. Our graphics function provides a robust layer of indirection, allowing one to more efficiently build, say, a dashboard of interactive graphics, each of which may be pulling data from a different data source. For the complete list of options, and for download instructions, [take a look at the sections below](https://github.com/mozilla/metrics-graphics/wiki). diff --git a/dist/metricsgraphics.js b/dist/metricsgraphics.js index 57f71a1050..1b57fb6d18 100644 --- a/dist/metricsgraphics.js +++ b/dist/metricsgraphics.js @@ -1,3899 +1,4043 @@ +(function() { + "use strict"; + var MG = {version:'2.0.0'}; + + + var charts = {}; + + MG.globals = {}; + MG.deprecations = { + rollover_callback: { replacement: 'mouseover', version: '2.0' }, + rollout_callback: { replacement: 'mouseout', version: '2.0' } + }; + MG.globals.link = false; + MG.globals.version = "1.1"; + + MG.data_graphic = function() { + 'use strict'; + var defaults = {}; + defaults.all = { + missing_is_zero: false, // if true, missing values will be treated as zeros + legend: '' , // an array identifying the labels for a chart's lines + legend_target: '', // if set, the specified element is populated with a legend + error: '', // if set, a graph will show an error icon and log the error to the console + animate_on_load: false, // animate lines on load + top: 40, // the size of the top margin + bottom: 30, // the size of the bottom margin + right: 10, // size of the right margin + left: 50, // size of the left margin + buffer: 8, // the buffer between the actual chart area and the margins + width: 350, // the width of the entire graphic + height: 220, // the height of the entire graphic + small_height_threshold: 120, // the height threshold for when smaller text appears + small_width_threshold: 160, // the width threshold for when smaller text appears + small_text: false, // coerces small text regardless of graphic size + xax_count: 6, // number of x axis ticks + xax_tick_length: 5, // x axis tick length + yax_count: 5, // number of y axis ticks + yax_tick_length: 5, // y axis tick length + x_extended_ticks: false, // extends x axis ticks across chart - useful for tall charts + y_extended_ticks: false, // extends y axis ticks across chart - useful for long charts + y_scale_type: 'linear', + max_x: null, + max_y: null, + min_x: null, + min_y: null, // if set, y axis starts at an arbitrary value + min_y_from_data: false, // if set, y axis will start at minimum value rather than at 0 + point_size: 2.5, // the size of the dot that appears on a line on mouse-over + x_accessor: 'date', + xax_units: '', + x_label: '', + x_axis: true, + y_axis: true, + y_accessor: 'value', + y_label: '', + yax_units: '', + x_rug: false, + y_rug: false, + transition_on_update: true, + mouseover: null, + show_rollover_text: true, + show_confidence_band: null, // given [l, u] shows a confidence at each point from l to u + xax_format: function(d) { + var df = d3.time.format('%b %d'); + var pf = d3.formatPrefix(d); + + // format as date or not, of course user can pass in + // a custom function if desired + switch($.type(args.data[0][0][args.x_accessor])) { + case 'date': + return df(d); + break; + case 'number': + return pf.scale(d) + pf.symbol; + break; + default: + return d; + } + }, + area: true, + chart_type: 'line', + data: [], + decimals: 2, // the number of decimals in any rollover + format: 'count', // format = {count, percentage} + inflator: 10/9, // for setting y axis max + linked: false, // links together all other graphs with linked:true, so rollovers in one trigger rollovers in the others + list: false, + baselines: null, // sets the baseline lines + markers: null, // sets the marker lines + scalefns: {}, + scales: {}, + show_years: true, + target: '#viz', + interpolate: 'cardinal', // interpolation method to use when rendering lines + custom_line_color_map: [], // allows arbitrary mapping of lines to colors, e.g. [2,3] will map line 1 to color 2 and line 2 to color 3 + max_data_size: null // explicitly specify the the max number of line series, for use with custom_line_color_map + } + defaults.point = { + buffer: 16, + ls: false, + lowess: false, + point_size: 2.5, + size_accessor: null, + color_accessor: null, + size_range: null, // when we set a size_accessor option, this array determines the size range, e.g. [1,5] + color_range: null, // e.g. ['blue', 'red'] to color different groups of points + size_domain: null, + color_domain: null, + color_type: 'number' // can be either 'number' - the color scale is quantitative - or 'category' - the color scale is qualitative. + } + defaults.histogram = { + mouseover: function(d, i) { + $('#histogram svg .active_datapoint') + .html('Frequency Count: ' + d.y); + }, + binned: false, + bins: null, + processed_x_accessor: 'x', + processed_y_accessor: 'y', + processed_dx_accessor: 'dx', + bar_margin: 1 + } + defaults.bar = { + y_accessor: 'factor', + x_accessor: 'value', + baseline_accessor: null, + predictor_accessor: null, + predictor_proportion: 5, + dodge_accessor: null, + binned: true, + padding_percentage: 0, + outer_padding_percentage: .1, + height: 500, + top: 20, + bar_height: 20, + left: 70 + } + defaults.missing = { + top: 0, + bottom: 0, + right: 0, + left: 0, + legend_target: '', + width: 350, + height: 220, + missing_text: 'Data currently missing or unavailable' + } + var args = arguments[0]; + if (!args) { args = {}; } + //args = merge_with_defaults(args, moz.defaults.all); -var charts = {}; -var globals = {}; -globals.link = false; -globals.version = "1.1"; + var g = ''; + if (args.list) { + args.x_accessor = 0; + args.y_accessor = 1; + } -function data_graphic() { - 'use strict'; - var moz = {}; - moz.defaults = {}; - moz.defaults.all = { - missing_is_zero: false, // if true, missing values will be treated as zeros - legend: '' , // an array identifying the labels for a chart's lines - legend_target: '', // if set, the specified element is populated with a legend - error: '', // if set, a graph will show an error icon and log the error to the console - animate_on_load: false, // animate lines on load - top: 40, // the size of the top margin - bottom: 30, // the size of the bottom margin - right: 10, // size of the right margin - left: 50, // size of the left margin - buffer: 8, // the buffer between the actual chart area and the margins - width: 350, // the width of the entire graphic - height: 220, // the height of the entire graphic - small_height_threshold: 120, // the height threshold for when smaller text appears - small_width_threshold: 160, // the width threshold for when smaller text appears - small_text: false, // coerces small text regardless of graphic size - xax_count: 6, // number of x axis ticks - xax_tick_length: 5, // x axis tick length - yax_count: 5, // number of y axis ticks - yax_tick_length: 5, // y axis tick length - x_extended_ticks: false, // extends x axis ticks across chart - useful for tall charts - y_extended_ticks: false, // extends y axis ticks across chart - useful for long charts - y_scale_type: 'linear', - max_x: null, - max_y: null, - min_x: null, - min_y: null, // if set, y axis starts at an arbitrary value - min_y_from_data: false, // if set, y axis will start at minimum value rather than at 0 - point_size: 2.5, // the size of the dot that appears on a line on mouse-over - x_accessor: 'date', - xax_units: '', - x_label: '', - x_axis: true, - y_axis: true, - y_accessor: 'value', - y_label: '', - yax_units: '', - x_rug: false, - y_rug: false, - transition_on_update: true, - rollover_callback: null, - show_rollover_text: true, - show_confidence_band: null, // given [l, u] shows a confidence at each point from l to u - xax_format: function(d) { - var df = d3.time.format('%b %d'); - var pf = d3.formatPrefix(d); - - // format as date or not, of course user can pass in - // a custom function if desired - switch($.type(args.data[0][0][args.x_accessor])) { - case 'date': - return df(d); - break; - case 'number': - return pf.scale(d) + pf.symbol; - break; - default: - return d; - } - }, - area: true, - chart_type: 'line', - data: [], - decimals: 2, // the number of decimals in any rollover - format: 'count', // format = {count, percentage} - inflator: 10/9, // for setting y axis max - linked: false, // links together all other graphs with linked:true, so rollovers in one trigger rollovers in the others - list: false, - baselines: null, // sets the baseline lines - markers: null, // sets the marker lines - scalefns: {}, - scales: {}, - show_years: true, - target: '#viz', - interpolate: 'cardinal', // interpolation method to use when rendering lines - custom_line_color_map: [], // allows arbitrary mapping of lines to colors, e.g. [2,3] will map line 1 to color 2 and line 2 to color 3 - max_data_size: null // explicitly specify the the max number of line series, for use with custom_line_color_map - } - moz.defaults.point = { - buffer: 16, - ls: false, - lowess: false, - point_size: 2.5, - size_accessor: null, - color_accessor: null, - size_range: null, // when we set a size_accessor option, this array determines the size range, e.g. [1,5] - color_range: null, // e.g. ['blue', 'red'] to color different groups of points - size_domain: null, - color_domain: null, - color_type: 'number' // can be either 'number' - the color scale is quantitative - or 'category' - the color scale is qualitative. - } - moz.defaults.histogram = { - rollover_callback: function(d, i) { - $('#histogram svg .active_datapoint') - .html('Frequency Count: ' + d.y); - }, - binned: false, - bins: null, - processed_x_accessor: 'x', - processed_y_accessor: 'y', - processed_dx_accessor: 'dx', - bar_margin: 1 - } - moz.defaults.bar = { - y_accessor: 'factor', - x_accessor: 'value', - baseline_accessor: null, - predictor_accessor: null, - predictor_proportion: 5, - dodge_accessor: null, - binned: true, - padding_percentage: 0, - outer_padding_percentage: .1, - height: 500, - top: 20, - bar_height: 20, - left: 70 - } - moz.defaults.missing = { - top: 0, - bottom: 0, - right: 0, - left: 0, - legend_target: '', - width: 350, - height: 220, - missing_text: 'Data currently missing or unavailable' - } + // check for deprecated parameters + for (var key in MG.deprecations) { + if (args.hasOwnProperty(key)) { + var deprecation = MG.deprecations[key], + message = 'Use of `args.' + key + '` has been deprecated', + replacement = deprecation.replacement, + version; + + // transparently alias the deprecated + if (replacement) { + if (args[replacement]) { + message += '. The replacement - `args.' + replacement + '` - has already been defined. This definition will be discarded.'; + } else { + args[replacement] = args[key]; + } + } + + if (deprecation.warned) continue; + deprecation.warned = true; + + if (replacement) { + message += ' in favor of `args.' + replacement + '`' + } + + warnDeprecation(message, deprecation.version); + } + } + + //build the chart + if(args.chart_type == 'missing-data'){ + args = merge_with_defaults(args, defaults.missing); + charts.missing(args); + } + else if(args.chart_type == 'point'){ + var a = merge_with_defaults(defaults.point, defaults.all); + args = merge_with_defaults(args, a); + charts.point(args).mainPlot().markers().rollover(); + } + else if(args.chart_type == 'histogram'){ + var a = merge_with_defaults(defaults.histogram, defaults.all); + args = merge_with_defaults(args, a); + charts.histogram(args).mainPlot().markers().rollover(); + } + else if (args.chart_type == 'bar'){ + var a = merge_with_defaults(defaults.bar, defaults.all); + args = merge_with_defaults(args, a); + charts.bar(args).mainPlot().markers().rollover(); + } + else { + args = merge_with_defaults(args, defaults.all); + charts.line(args).markers().mainPlot().rollover(); + } - var args = arguments[0]; - if (!args) { args = {}; } - //args = merge_with_defaults(args, moz.defaults.all); + return args.data; + } - var g = ''; - if (args.list) { - args.x_accessor = 0; - args.y_accessor = 1; + /*! + * Bootstrap v3.3.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + + /*! + * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=698666b23215c58f23d4) + * Config saved to config.json and https://gist.github.com/698666b23215c58f23d4 + */ + if (typeof jQuery === 'undefined') { + throw new Error('Bootstrap\'s JavaScript requires jQuery') + } + +function ($) { + var version = $.fn.jquery.split(' ')[0].split('.') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') } + }(jQuery); + + /* ======================================================================== + * Bootstrap: tooltip.js v3.3.1 + * http://getbootstrap.com/javascript/#tooltip + * Inspired by the original jQuery.tipsy by Jason Frame + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + + +function ($) { + 'use strict'; - //build the chart - if(args.chart_type == 'missing-data'){ - args = merge_with_defaults(args, moz.defaults.missing); - charts.missing(args); - } - else if(args.chart_type == 'point'){ - var a = merge_with_defaults(moz.defaults.point, moz.defaults.all); - args = merge_with_defaults(args, a); - charts.point(args).mainPlot().markers().rollover(); - } - else if(args.chart_type == 'histogram'){ - var a = merge_with_defaults(moz.defaults.histogram, moz.defaults.all); - args = merge_with_defaults(args, a); - charts.histogram(args).mainPlot().markers().rollover(); + if(typeof $().tooltip == 'function') + return true; + + // TOOLTIP PUBLIC CLASS DEFINITION + // =============================== + + var Tooltip = function (element, options) { + this.type = + this.options = + this.enabled = + this.timeout = + this.hoverState = + this.$element = null + + this.init('tooltip', element, options) + } + + Tooltip.VERSION = '3.3.1' + + Tooltip.TRANSITION_DURATION = 150 + + Tooltip.DEFAULTS = { + animation: true, + placement: 'top', + selector: false, + template: '', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + container: false, + viewport: { + selector: 'body', + padding: 0 + } } - else if (args.chart_type == 'bar'){ - var a = merge_with_defaults(moz.defaults.bar, moz.defaults.all); - args = merge_with_defaults(args, a); - charts.bar(args).mainPlot().markers().rollover(); + + Tooltip.prototype.init = function (type, element, options) { + this.enabled = true + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) + + var triggers = this.options.trigger.split(' ') + + for (var i = triggers.length; i--;) { + var trigger = triggers[i] + + if (trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (trigger != 'manual') { + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' + + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + } + } + + this.options.selector ? + (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : + this.fixTitle() } - else { - args = merge_with_defaults(args, moz.defaults.all); - charts.line(args).markers().mainPlot().rollover(); + + Tooltip.prototype.getDefaults = function () { + return Tooltip.DEFAULTS } - return args.data; -} - -/*! - * Bootstrap v3.3.1 (http://getbootstrap.com) - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -/*! - * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=698666b23215c58f23d4) - * Config saved to config.json and https://gist.github.com/698666b23215c58f23d4 - */ -if (typeof jQuery === 'undefined') { - throw new Error('Bootstrap\'s JavaScript requires jQuery') -} -+function ($) { - var version = $.fn.jquery.split(' ')[0].split('.') - if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { - throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') - } -}(jQuery); - -/* ======================================================================== - * Bootstrap: tooltip.js v3.3.1 - * http://getbootstrap.com/javascript/#tooltip - * Inspired by the original jQuery.tipsy by Jason Frame - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - if(typeof $().tooltip == 'function') - return true; - - // TOOLTIP PUBLIC CLASS DEFINITION - // =============================== - - var Tooltip = function (element, options) { - this.type = - this.options = - this.enabled = - this.timeout = - this.hoverState = - this.$element = null - - this.init('tooltip', element, options) - } + Tooltip.prototype.getOptions = function (options) { + options = $.extend({}, this.getDefaults(), this.$element.data(), options) + + if (options.delay && typeof options.delay == 'number') { + options.delay = { + show: options.delay, + hide: options.delay + } + } - Tooltip.VERSION = '3.3.1' - - Tooltip.TRANSITION_DURATION = 150 - - Tooltip.DEFAULTS = { - animation: true, - placement: 'top', - selector: false, - template: '', - trigger: 'hover focus', - title: '', - delay: 0, - html: false, - container: false, - viewport: { - selector: 'body', - padding: 0 + return options } - } - Tooltip.prototype.init = function (type, element, options) { - this.enabled = true - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) + Tooltip.prototype.getDelegateOptions = function () { + var options = {} + var defaults = this.getDefaults() - var triggers = this.options.trigger.split(' ') + this._options && $.each(this._options, function (key, value) { + if (defaults[key] != value) options[key] = value + }) - for (var i = triggers.length; i--;) { - var trigger = triggers[i] + return options + } - if (trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (trigger != 'manual') { - var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' - var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' + Tooltip.prototype.enter = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget).data('bs.' + this.type) - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + if (self && self.$tip && self.$tip.is(':visible')) { + self.hoverState = 'in' + return } - } - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } + if (!self) { + self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) + $(obj.currentTarget).data('bs.' + this.type, self) + } - Tooltip.prototype.getDefaults = function () { - return Tooltip.DEFAULTS - } + clearTimeout(self.timeout) + + self.hoverState = 'in' - Tooltip.prototype.getOptions = function (options) { - options = $.extend({}, this.getDefaults(), this.$element.data(), options) + if (!self.options.delay || !self.options.delay.show) return self.show() - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay, - hide: options.delay - } + self.timeout = setTimeout(function () { + if (self.hoverState == 'in') self.show() + }, self.options.delay.show) } - return options - } + Tooltip.prototype.leave = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget).data('bs.' + this.type) - Tooltip.prototype.getDelegateOptions = function () { - var options = {} - var defaults = this.getDefaults() + if (!self) { + self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) + $(obj.currentTarget).data('bs.' + this.type, self) + } - this._options && $.each(this._options, function (key, value) { - if (defaults[key] != value) options[key] = value - }) + clearTimeout(self.timeout) - return options - } + self.hoverState = 'out' - Tooltip.prototype.enter = function (obj) { - var self = obj instanceof this.constructor ? - obj : $(obj.currentTarget).data('bs.' + this.type) + if (!self.options.delay || !self.options.delay.hide) return self.hide() - if (self && self.$tip && self.$tip.is(':visible')) { - self.hoverState = 'in' - return + self.timeout = setTimeout(function () { + if (self.hoverState == 'out') self.hide() + }, self.options.delay.hide) } - if (!self) { - self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) - $(obj.currentTarget).data('bs.' + this.type, self) - } + Tooltip.prototype.show = function () { + var e = $.Event('show.bs.' + this.type) - clearTimeout(self.timeout) + if (this.hasContent() && this.enabled) { + this.$element.trigger(e) - self.hoverState = 'in' + var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) + if (e.isDefaultPrevented() || !inDom) return + var that = this - if (!self.options.delay || !self.options.delay.show) return self.show() + var $tip = this.tip() - self.timeout = setTimeout(function () { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } + var tipId = this.getUID(this.type) - Tooltip.prototype.leave = function (obj) { - var self = obj instanceof this.constructor ? - obj : $(obj.currentTarget).data('bs.' + this.type) + this.setContent() + $tip.attr('id', tipId) + this.$element.attr('aria-describedby', tipId) - if (!self) { - self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) - $(obj.currentTarget).data('bs.' + this.type, self) - } + if (this.options.animation) $tip.addClass('fade') - clearTimeout(self.timeout) + var placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement - self.hoverState = 'out' + var autoToken = /\s?auto?\s?/i + var autoPlace = autoToken.test(placement) + if (autoPlace) placement = placement.replace(autoToken, '') || 'top' - if (!self.options.delay || !self.options.delay.hide) return self.hide() + $tip + .detach() + .css({ top: 0, left: 0, display: 'block' }) + .addClass(placement) + .data('bs.' + this.type, this) - self.timeout = setTimeout(function () { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } + this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) - Tooltip.prototype.show = function () { - var e = $.Event('show.bs.' + this.type) + var pos = this.getPosition() + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight - if (this.hasContent() && this.enabled) { - this.$element.trigger(e) + if (autoPlace) { + var orgPlacement = placement + var $container = this.options.container ? $(this.options.container) : this.$element.parent() + var containerDim = this.getPosition($container) - var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) - if (e.isDefaultPrevented() || !inDom) return - var that = this + placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' : + placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' : + placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' : + placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' : + placement - var $tip = this.tip() + $tip + .removeClass(orgPlacement) + .addClass(placement) + } + + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) + + this.applyPlacement(calculatedOffset, placement) + + var complete = function () { + var prevHoverState = that.hoverState + that.$element.trigger('shown.bs.' + that.type) + that.hoverState = null + + if (prevHoverState == 'out') that.leave(that) + } - var tipId = this.getUID(this.type) + $.support.transition && this.$tip.hasClass('fade') ? + $tip + .one('bsTransitionEnd', complete) + .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : + complete() + } + } - this.setContent() - $tip.attr('id', tipId) - this.$element.attr('aria-describedby', tipId) + Tooltip.prototype.applyPlacement = function (offset, placement) { + var $tip = this.tip() + var width = $tip[0].offsetWidth + var height = $tip[0].offsetHeight - if (this.options.animation) $tip.addClass('fade') + // manually read margins because getBoundingClientRect includes difference + var marginTop = parseInt($tip.css('margin-top'), 10) + var marginLeft = parseInt($tip.css('margin-left'), 10) - var placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement + // we must check for NaN for ie 8/9 + if (isNaN(marginTop)) marginTop = 0 + if (isNaN(marginLeft)) marginLeft = 0 - var autoToken = /\s?auto?\s?/i - var autoPlace = autoToken.test(placement) - if (autoPlace) placement = placement.replace(autoToken, '') || 'top' + offset.top = offset.top + marginTop + offset.left = offset.left + marginLeft - $tip - .detach() - .css({ top: 0, left: 0, display: 'block' }) - .addClass(placement) - .data('bs.' + this.type, this) + // $.fn.offset doesn't round pixel values + // so we use setOffset directly with our own function B-0 + $.offset.setOffset($tip[0], $.extend({ + using: function (props) { + $tip.css({ + top: Math.round(props.top), + left: Math.round(props.left) + }) + } + }, offset), 0) - this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + $tip.addClass('in') - var pos = this.getPosition() + // check to see if placing tip in new offset caused the tip to resize itself var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight - if (autoPlace) { - var orgPlacement = placement - var $container = this.options.container ? $(this.options.container) : this.$element.parent() - var containerDim = this.getPosition($container) + if (placement == 'top' && actualHeight != height) { + offset.top = offset.top + height - actualHeight + } - placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' : - placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' : - placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' : - placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' : - placement + var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) - $tip - .removeClass(orgPlacement) - .addClass(placement) - } + if (delta.left) offset.left += delta.left + else offset.top += delta.top - var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) + var isVertical = /top|bottom/.test(placement) + var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight + var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' - this.applyPlacement(calculatedOffset, placement) + $tip.offset(offset) + this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) + } + + Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) { + this.arrow() + .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') + .css(isHorizontal ? 'top' : 'left', '') + } + + Tooltip.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() - var complete = function () { - var prevHoverState = that.hoverState - that.$element.trigger('shown.bs.' + that.type) - that.hoverState = null + $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) + $tip.removeClass('fade in top bottom left right') + } - if (prevHoverState == 'out') that.leave(that) + Tooltip.prototype.hide = function (callback) { + var that = this + var $tip = this.tip() + var e = $.Event('hide.bs.' + this.type) + + function complete() { + if (that.hoverState != 'in') $tip.detach() + that.$element + .removeAttr('aria-describedby') + .trigger('hidden.bs.' + that.type) + callback && callback() } + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + $tip.removeClass('in') + $.support.transition && this.$tip.hasClass('fade') ? $tip .one('bsTransitionEnd', complete) .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : complete() + + this.hoverState = null + + return this } - } - Tooltip.prototype.applyPlacement = function (offset, placement) { - var $tip = this.tip() - var width = $tip[0].offsetWidth - var height = $tip[0].offsetHeight + Tooltip.prototype.fixTitle = function () { + var $e = this.$element + if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') { + $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') + } + } - // manually read margins because getBoundingClientRect includes difference - var marginTop = parseInt($tip.css('margin-top'), 10) - var marginLeft = parseInt($tip.css('margin-left'), 10) + Tooltip.prototype.hasContent = function () { + return this.getTitle() + } - // we must check for NaN for ie 8/9 - if (isNaN(marginTop)) marginTop = 0 - if (isNaN(marginLeft)) marginLeft = 0 + Tooltip.prototype.getPosition = function ($element) { + $element = $element || this.$element - offset.top = offset.top + marginTop - offset.left = offset.left + marginLeft + var el = $element[0] + var isBody = el.tagName == 'BODY' - // $.fn.offset doesn't round pixel values - // so we use setOffset directly with our own function B-0 - $.offset.setOffset($tip[0], $.extend({ - using: function (props) { - $tip.css({ - top: Math.round(props.top), - left: Math.round(props.left) - }) + var elRect = el.getBoundingClientRect() + if (elRect.width == null) { + // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 + elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) } - }, offset), 0) + var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() + var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } + var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null - $tip.addClass('in') + return $.extend({}, elRect, scroll, outerDims, elOffset) + } - // check to see if placing tip in new offset caused the tip to resize itself - var actualWidth = $tip[0].offsetWidth - var actualHeight = $tip[0].offsetHeight + Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { + return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : + /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } - if (placement == 'top' && actualHeight != height) { - offset.top = offset.top + height - actualHeight } - var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) - - if (delta.left) offset.left += delta.left - else offset.top += delta.top + Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { + var delta = { top: 0, left: 0 } + if (!this.$viewport) return delta - var isVertical = /top|bottom/.test(placement) - var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight - var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' + var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 + var viewportDimensions = this.getPosition(this.$viewport) - $tip.offset(offset) - this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) - } + if (/right|left/.test(placement)) { + var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll + var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight + if (topEdgeOffset < viewportDimensions.top) { // top overflow + delta.top = viewportDimensions.top - topEdgeOffset + } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow + delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset + } + } else { + var leftEdgeOffset = pos.left - viewportPadding + var rightEdgeOffset = pos.left + viewportPadding + actualWidth + if (leftEdgeOffset < viewportDimensions.left) { // left overflow + delta.left = viewportDimensions.left - leftEdgeOffset + } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow + delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset + } + } - Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) { - this.arrow() - .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') - .css(isHorizontal ? 'top' : 'left', '') - } + return delta + } - Tooltip.prototype.setContent = function () { - var $tip = this.tip() - var title = this.getTitle() + Tooltip.prototype.getTitle = function () { + var title + var $e = this.$element + var o = this.options - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } + title = $e.attr('data-original-title') + || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - Tooltip.prototype.hide = function (callback) { - var that = this - var $tip = this.tip() - var e = $.Event('hide.bs.' + this.type) - - function complete() { - if (that.hoverState != 'in') $tip.detach() - that.$element - .removeAttr('aria-describedby') - .trigger('hidden.bs.' + that.type) - callback && callback() + return title } - this.$element.trigger(e) - - if (e.isDefaultPrevented()) return - - $tip.removeClass('in') + Tooltip.prototype.getUID = function (prefix) { + do prefix += ~~(Math.random() * 1000000) + while (document.getElementById(prefix)) + return prefix + } - $.support.transition && this.$tip.hasClass('fade') ? - $tip - .one('bsTransitionEnd', complete) - .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : - complete() + Tooltip.prototype.tip = function () { + return (this.$tip = this.$tip || $(this.options.template)) + } - this.hoverState = null + Tooltip.prototype.arrow = function () { + return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) + } - return this - } + Tooltip.prototype.enable = function () { + this.enabled = true + } - Tooltip.prototype.fixTitle = function () { - var $e = this.$element - if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') + Tooltip.prototype.disable = function () { + this.enabled = false } - } - Tooltip.prototype.hasContent = function () { - return this.getTitle() - } + Tooltip.prototype.toggleEnabled = function () { + this.enabled = !this.enabled + } - Tooltip.prototype.getPosition = function ($element) { - $element = $element || this.$element + Tooltip.prototype.toggle = function (e) { + var self = this + if (e) { + self = $(e.currentTarget).data('bs.' + this.type) + if (!self) { + self = new this.constructor(e.currentTarget, this.getDelegateOptions()) + $(e.currentTarget).data('bs.' + this.type, self) + } + } - var el = $element[0] - var isBody = el.tagName == 'BODY' + self.tip().hasClass('in') ? self.leave(self) : self.enter(self) + } - var elRect = el.getBoundingClientRect() - if (elRect.width == null) { - // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 - elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) + Tooltip.prototype.destroy = function () { + var that = this + clearTimeout(this.timeout) + this.hide(function () { + that.$element.off('.' + that.type).removeData('bs.' + that.type) + }) } - var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() - var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } - var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null - return $.extend({}, elRect, scroll, outerDims, elOffset) - } - Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { - return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : - placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : - placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : - /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + // TOOLTIP PLUGIN DEFINITION + // ========================= - } + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tooltip') + var options = typeof option == 'object' && option + var selector = options && options.selector - Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { - var delta = { top: 0, left: 0 } - if (!this.$viewport) return delta - - var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 - var viewportDimensions = this.getPosition(this.$viewport) - - if (/right|left/.test(placement)) { - var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll - var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight - if (topEdgeOffset < viewportDimensions.top) { // top overflow - delta.top = viewportDimensions.top - topEdgeOffset - } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow - delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset - } - } else { - var leftEdgeOffset = pos.left - viewportPadding - var rightEdgeOffset = pos.left + viewportPadding + actualWidth - if (leftEdgeOffset < viewportDimensions.left) { // left overflow - delta.left = viewportDimensions.left - leftEdgeOffset - } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow - delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset - } + if (!data && option == 'destroy') return + if (selector) { + if (!data) $this.data('bs.tooltip', (data = {})) + if (!data[selector]) data[selector] = new Tooltip(this, options) + } else { + if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) + } + if (typeof option == 'string') data[option]() + }) } - return delta - } + var old = $.fn.tooltip - Tooltip.prototype.getTitle = function () { - var title - var $e = this.$element - var o = this.options + $.fn.tooltip = Plugin + $.fn.tooltip.Constructor = Tooltip - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - return title - } + // TOOLTIP NO CONFLICT + // =================== - Tooltip.prototype.getUID = function (prefix) { - do prefix += ~~(Math.random() * 1000000) - while (document.getElementById(prefix)) - return prefix - } + $.fn.tooltip.noConflict = function () { + $.fn.tooltip = old + return this + } - Tooltip.prototype.tip = function () { - return (this.$tip = this.$tip || $(this.options.template)) - } + }(jQuery); - Tooltip.prototype.arrow = function () { - return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) - } + /* ======================================================================== + * Bootstrap: popover.js v3.3.1 + * http://getbootstrap.com/javascript/#popovers + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ - Tooltip.prototype.enable = function () { - this.enabled = true - } - Tooltip.prototype.disable = function () { - this.enabled = false - } + +function ($) { + 'use strict'; - Tooltip.prototype.toggleEnabled = function () { - this.enabled = !this.enabled - } + if(typeof $().popover == 'function') + return true; + + // POPOVER PUBLIC CLASS DEFINITION + // =============================== - Tooltip.prototype.toggle = function (e) { - var self = this - if (e) { - self = $(e.currentTarget).data('bs.' + this.type) - if (!self) { - self = new this.constructor(e.currentTarget, this.getDelegateOptions()) - $(e.currentTarget).data('bs.' + this.type, self) - } + var Popover = function (element, options) { + this.init('popover', element, options) } - self.tip().hasClass('in') ? self.leave(self) : self.enter(self) - } + if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') - Tooltip.prototype.destroy = function () { - var that = this - clearTimeout(this.timeout) - this.hide(function () { - that.$element.off('.' + that.type).removeData('bs.' + that.type) - }) - } + Popover.VERSION = '3.3.1' + Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { + placement: 'right', + trigger: 'click', + content: '', + template: '' + }) - // TOOLTIP PLUGIN DEFINITION - // ========================= - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.tooltip') - var options = typeof option == 'object' && option - var selector = options && options.selector + // NOTE: POPOVER EXTENDS tooltip.js + // ================================ - if (!data && option == 'destroy') return - if (selector) { - if (!data) $this.data('bs.tooltip', (data = {})) - if (!data[selector]) data[selector] = new Tooltip(this, options) - } else { - if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) - } - if (typeof option == 'string') data[option]() - }) - } + Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) - var old = $.fn.tooltip + Popover.prototype.constructor = Popover - $.fn.tooltip = Plugin - $.fn.tooltip.Constructor = Tooltip + Popover.prototype.getDefaults = function () { + return Popover.DEFAULTS + } + Popover.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + var content = this.getContent() - // TOOLTIP NO CONFLICT - // =================== + $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) + $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events + this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' + ](content) - $.fn.tooltip.noConflict = function () { - $.fn.tooltip = old - return this - } + $tip.removeClass('fade top bottom left right in') -}(jQuery); + // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do + // this manually by checking the contents. + if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + } -/* ======================================================================== - * Bootstrap: popover.js v3.3.1 - * http://getbootstrap.com/javascript/#popovers - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ + Popover.prototype.hasContent = function () { + return this.getTitle() || this.getContent() + } + Popover.prototype.getContent = function () { + var $e = this.$element + var o = this.options -+function ($) { - 'use strict'; + return $e.attr('data-content') + || (typeof o.content == 'function' ? + o.content.call($e[0]) : + o.content) + } - if(typeof $().popover == 'function') - return true; - - // POPOVER PUBLIC CLASS DEFINITION - // =============================== + Popover.prototype.arrow = function () { + return (this.$arrow = this.$arrow || this.tip().find('.arrow')) + } - var Popover = function (element, options) { - this.init('popover', element, options) - } + Popover.prototype.tip = function () { + if (!this.$tip) this.$tip = $(this.options.template) + return this.$tip + } - if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') - Popover.VERSION = '3.3.1' + // POPOVER PLUGIN DEFINITION + // ========================= - Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { - placement: 'right', - trigger: 'click', - content: '', - template: '' - }) + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.popover') + var options = typeof option == 'object' && option + var selector = options && options.selector + if (!data && option == 'destroy') return + if (selector) { + if (!data) $this.data('bs.popover', (data = {})) + if (!data[selector]) data[selector] = new Popover(this, options) + } else { + if (!data) $this.data('bs.popover', (data = new Popover(this, options))) + } + if (typeof option == 'string') data[option]() + }) + } - // NOTE: POPOVER EXTENDS tooltip.js - // ================================ + var old = $.fn.popover - Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) + $.fn.popover = Plugin + $.fn.popover.Constructor = Popover - Popover.prototype.constructor = Popover - Popover.prototype.getDefaults = function () { - return Popover.DEFAULTS - } + // POPOVER NO CONFLICT + // =================== - Popover.prototype.setContent = function () { - var $tip = this.tip() - var title = this.getTitle() - var content = this.getContent() + $.fn.popover.noConflict = function () { + $.fn.popover = old + return this + } - $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) - $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events - this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' - ](content) + }(jQuery); - $tip.removeClass('fade top bottom left right in') + function chart_title(args) { + //is chart title different than existing, if so, clear the fine + //gentleman, otherwise, move along + 'use strict'; + var currentTitle = $(args.target).find('h2.chart_title'); + if(args.title && args.title !== currentTitle.text()) + currentTitle.remove(); + else + return; - // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do - // this manually by checking the contents. - if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + if (args.target && args.title) { + var newTitle; + //only show question mark if there's a description + var optional_question_mark = (args.description) + ? '' + : ''; + + $(args.target).prepend('

' + + args.title + optional_question_mark + '

'); + + //activate the question mark if we have a description + if (args.description){ + newTitle = $(args.target).find('h2.chart_title'); + newTitle.popover({ + html: true, + animation: false, + content: args.description, + trigger: 'hover', + placement: 'top', + container: newTitle + }); + } + } + + if(args.error) { + error(args); + } } + function y_rug(args) { + 'use strict'; + var svg = d3.select($(args.target).find('svg').get(0)); + var buffer_size = args.chart_type == 'point' + ? args.buffer / 2 + : args.buffer * 2 / 3; + + var all_data = []; + for (var i=0; i 0; }); + } + + if (a.length > 0) { + // get min/max in one pass + var extent = d3.extent(a,function(d) { + return d[args.y_accessor]; + }); + + if (!_set) { + // min_y and max_y haven't been set + min_y = extent[0]; + max_y = extent[1]; + _set = true; + } else { + min_y = Math.min(extent[0], min_y); + max_y = Math.max(extent[1], max_y); + } + } } - if (typeof option == 'string') data[option]() - }) - } - var old = $.fn.popover + // the default cause is for the y-axis to start at 0, unless we explicitly want it + // to start at ab arbitrary number or from the data's minimum value + if (min_y >= 0 && !args.min_y && !args.min_y_from_data){ + min_y = 0; + } - $.fn.popover = Plugin - $.fn.popover.Constructor = Popover + //if a min_y or max_y have been set, use those instead + min_y = args.min_y ? args.min_y : min_y; + max_y = args.max_y ? args.max_y : max_y; + + if (args.y_scale_type != 'log') { + // we are currently saying that if the min val > 0, set 0 as min y. + if (min_y >= 0){ + args.y_axis_negative = false; + } else { + min_y = min_y - (max_y * (args.inflator-1)); + args.y_axis_negative = true; + } + } + max_y = max_y * args.inflator; + if (!args.min_y && args.min_y_from_data){ + min_y = min_y / args.inflator; + } - // POPOVER NO CONFLICT - // =================== + if (args.y_scale_type == 'log'){ + if (args.chart_type == 'histogram') { + // log histogram plots should start just below 1 + // so that bins with single counts are visible + min_y = 0.2; + } else { + if (min_y <= 0) { + min_y = 1; + } + } + + args.scales.Y = d3.scale.log() + .domain([min_y, max_y]) + .range([args.height - args.bottom - args.buffer, args.top]) + .clamp(true); + } else { + args.scales.Y = d3.scale.linear() + .domain([min_y, max_y]) + .range([args.height - args.bottom - args.buffer, args.top]); + } - $.fn.popover.noConflict = function () { - $.fn.popover = old - return this - } + // used for ticks and such, and designed to be paired with log or linear. + args.scales.Y_axis = d3.scale.linear() + .domain([min_y, max_y]) + .range([args.height - args.bottom - args.buffer, args.top]); + + var yax_format; + if (args.format == 'count') { + yax_format = function(f) { + if (f < 1.0) { + // Don't scale tiny values. + return args.yax_units + d3.round(f, args.decimals); + } else { + var pf = d3.formatPrefix(f); + return args.yax_units + pf.scale(f) + pf.symbol; + } + }; + } + else { + yax_format = function(d_) { + var n = d3.format('%p'); + return n(d_); + } + } -}(jQuery); + //remove the old y-axis, add new one + $svg.find('.y-axis').remove(); + + if (!args.y_axis) return this; + + //y axis + g = svg.append('g') + .classed('y-axis', true) + .classed('y-axis-small', args.use_small_class); + + //are we adding a label? + if(args.y_label) { + g.append('text') + .attr('class', 'label') + .attr('x', function() { + return -1 * (args.top + args.buffer + + ((args.height - args.bottom - args.buffer) + - (args.top + args.buffer)) / 2); + }) + .attr('y', function() { + return args.left / 2; + }) + .attr("dy", "0.4em") + .attr('text-anchor', 'middle') + .text(function(d) { + return args.y_label; + }) + .attr("transform", function(d) { + return "rotate(-90)"; + }); + } -function chart_title(args) { - //is chart title different than existing, if so, clear the fine - //gentleman, otherwise, move along - 'use strict'; - var currentTitle = $(args.target).find('h2.chart_title'); - if(args.title && args.title !== currentTitle.text()) - currentTitle.remove(); - else - return; - - if (args.target && args.title) { - var newTitle; - //only show question mark if there's a description - var optional_question_mark = (args.description) - ? '' - : ''; - - $(args.target).prepend('

' - + args.title + optional_question_mark + '

'); - - //activate the question mark if we have a description - if (args.description){ - newTitle = $(args.target).find('h2.chart_title'); - newTitle.popover({ - html: true, - animation: false, - content: args.description, - trigger: 'hover', - placement: 'top', - container: newTitle - }); - } - } - - if(args.error) { - error(args); - } -} -function y_rug(args) { - 'use strict'; - var svg = d3.select($(args.target).find('svg').get(0)); - var buffer_size = args.chart_type == 'point' - ? args.buffer / 2 - : args.buffer * 2 / 3; - - var all_data = []; - for (var i=0; i 1-1e-6; + }); + } - var min_y, max_y; + //filter out fraction ticks if our data is ints and if ymax > number of generated ticks + var number_of_ticks = args.scales.Y.ticks(args.yax_count).length; + + //is our data object all ints? + var data_is_int = true; + $.each(args.data, function(i, d) { + $.each(d, function(i, d) { + if(d[args.y_accessor] % 1 !== 0) { + data_is_int = false; + return false; + } + }); + }); + + if(data_is_int && number_of_ticks > max_y && args.format == 'count') { + //remove non-integer ticks + scale_ticks = scale_ticks.filter(function(d){ + return d % 1 === 0; + }); + } - args.scalefns.yf = function(di) { - return args.scales.Y(di[args.y_accessor]); - } + var last_i = scale_ticks.length-1; + if(!args.x_extended_ticks && !args.y_extended_ticks) { + g.append('line') + .attr('x1', args.left) + .attr('x2', args.left) + .attr('y1', args.scales.Y(scale_ticks[0]).toFixed(2)) + .attr('y2', args.scales.Y(scale_ticks[last_i]).toFixed(2)); + } - var min_y, max_y; + //add y ticks + g.selectAll('.yax-ticks') + .data(scale_ticks).enter() + .append('line') + .classed('extended-y-ticks', args.y_extended_ticks) + .attr('x1', args.left) + .attr('x2', function() { + return (args.y_extended_ticks) + ? args.width - args.right + : args.left - args.yax_tick_length; + }) + .attr('y1', function(d) { return args.scales.Y(d).toFixed(2); }) + .attr('y2', function(d) { return args.scales.Y(d).toFixed(2); }); + + g.selectAll('.yax-labels') + .data(scale_ticks).enter() + .append('text') + .attr('x', args.left - args.yax_tick_length * 3 / 2) + .attr('dx', -3).attr('y', function(d) { + return args.scales.Y(d).toFixed(2); + }) + .attr('dy', '.35em') + .attr('text-anchor', 'end') + .text(function(d, i) { + var o = yax_format(d); + return o; + }) + + if (args.y_rug) { + y_rug(args); + } - var _set = false; - for (var i=0; i 0; }); - } + function y_axis_categorical(args) { + // first, come up with y_axis + var svg_height = args.height; + if (args.chart_type == 'bar' && svg_height == null){ + // we need to set a new height variable. + } - if (a.length > 0) { - // get min/max in one pass - var extent = d3.extent(a,function(d) { - return d[args.y_accessor]; - }); - - if (!_set) { - // min_y and max_y haven't been set - min_y = extent[0]; - max_y = extent[1]; - _set = true; - } else { - min_y = Math.min(extent[0], min_y); - max_y = Math.max(extent[1], max_y); - } - } - } + args.scales.Y = d3.scale.ordinal() + .domain(args.categorical_variables) + .rangeRoundBands([args.height - args.bottom - args.buffer, args.top], args.padding_percentage, args.outer_padding_percentage); - // the default cause is for the y-axis to start at 0, unless we explicitly want it - // to start at ab arbitrary number or from the data's minimum value - if (min_y >= 0 && !args.min_y && !args.min_y_from_data){ - min_y = 0; - } + args.scalefns.yf = function(di) { + return args.scales.Y(di[args.y_accessor]); + } - //if a min_y or max_y have been set, use those instead - min_y = args.min_y ? args.min_y : min_y; - max_y = args.max_y ? args.max_y : max_y; + var svg = d3.select($(args.target).find('svg').get(0)); + var $svg = $($(args.target).find('svg').get(0)); - if (args.y_scale_type != 'log') { - // we are currently saying that if the min val > 0, set 0 as min y. - if (min_y >= 0){ - args.y_axis_negative = false; - } else { - min_y = min_y - (max_y * (args.inflator-1)); - args.y_axis_negative = true; - } - } + //remove the old y-axis, add new one + $svg.find('.y-axis').remove(); - max_y = max_y * args.inflator; - if (!args.min_y && args.min_y_from_data){ - min_y = min_y / args.inflator; - } + var g = svg.append('g') + .classed('y-axis', true) + .classed('y-axis-small', args.use_small_class); - if (args.y_scale_type == 'log'){ - if (args.chart_type == 'histogram') { - // log histogram plots should start just below 1 - // so that bins with single counts are visible - min_y = 0.2; - } else { - if (min_y <= 0) { - min_y = 1; - } - } + if (!args.y_axis) return this; - args.scales.Y = d3.scale.log() - .domain([min_y, max_y]) - .range([args.height - args.bottom - args.buffer, args.top]) - .clamp(true); - } else { - args.scales.Y = d3.scale.linear() - .domain([min_y, max_y]) - .range([args.height - args.bottom - args.buffer, args.top]); - } + g.selectAll('text').data(args.categorical_variables).enter().append('svg:text') + .attr('x', args.left) + .attr('y', function(d) { + return args.scales.Y(d) + args.scales.Y.rangeBand() / 2 + + (args.buffer)*args.outer_padding_percentage; + }) + .attr('dy', '.35em') + .attr('text-anchor', 'end') + .text(String) - // used for ticks and such, and designed to be paired with log or linear. - args.scales.Y_axis = d3.scale.linear() - .domain([min_y, max_y]) - .range([args.height - args.bottom - args.buffer, args.top]); - - var yax_format; - if (args.format == 'count') { - yax_format = function(f) { - if (f < 1.0) { - // Don't scale tiny values. - return args.yax_units + d3.round(f, args.decimals); - } else { - var pf = d3.formatPrefix(f); - return args.yax_units + pf.scale(f) + pf.symbol; - } - }; - } - else { - yax_format = function(d_) { - var n = d3.format('%p'); - return n(d_); - } - } + return this; + } - //remove the old y-axis, add new one - $svg.find('.y-axis').remove(); - - if (!args.y_axis) return this; - - //y axis - g = svg.append('g') - .classed('y-axis', true) - .classed('y-axis-small', args.use_small_class); - - //are we adding a label? - if(args.y_label) { - g.append('text') - .attr('class', 'label') - .attr('x', function() { - return -1 * (args.top + args.buffer + - ((args.height - args.bottom - args.buffer) - - (args.top + args.buffer)) / 2); - }) - .attr('y', function() { - return args.left / 2; - }) - .attr("dy", "0.4em") - .attr('text-anchor', 'middle') - .text(function(d) { - return args.y_label; - }) - .attr("transform", function(d) { - return "rotate(-90)"; - }); - } + function x_rug(args) { + 'use strict'; + var buffer_size = args.chart_type =='point' + ? args.buffer / 2 + : args.buffer; + + var svg = d3.select($(args.target).find('svg').get(0)); + var all_data=[]; + for (var i=0; i 1-1e-6; - }); - } + //set the attributes that do not change after initialization, per + //D3's general update pattern + rug.enter().append('svg:line') + .attr('class', 'x-rug') + .attr('opacity', 0.3); - //filter out fraction ticks if our data is ints and if ymax > number of generated ticks - var number_of_ticks = args.scales.Y.ticks(args.yax_count).length; - - //is our data object all ints? - var data_is_int = true; - $.each(args.data, function(i, d) { - $.each(d, function(i, d) { - if(d[args.y_accessor] % 1 !== 0) { - data_is_int = false; - return false; - } - }); - }); - - if(data_is_int && number_of_ticks > max_y && args.format == 'count') { - //remove non-integer ticks - scale_ticks = scale_ticks.filter(function(d){ - return d % 1 === 0; - }); - } + //remove rug elements that are no longer in use + rug.exit().remove(); - var last_i = scale_ticks.length-1; - if(!args.x_extended_ticks && !args.y_extended_ticks) { - g.append('line') - .attr('x1', args.left) - .attr('x2', args.left) - .attr('y1', args.scales.Y(scale_ticks[0]).toFixed(2)) - .attr('y2', args.scales.Y(scale_ticks[last_i]).toFixed(2)); - } + //set coordinates of new rug elements + rug.exit().remove(); - //add y ticks - g.selectAll('.yax-ticks') - .data(scale_ticks).enter() - .append('line') - .classed('extended-y-ticks', args.y_extended_ticks) - .attr('x1', args.left) - .attr('x2', function() { - return (args.y_extended_ticks) - ? args.width - args.right - : args.left - args.yax_tick_length; - }) - .attr('y1', function(d) { return args.scales.Y(d).toFixed(2); }) - .attr('y2', function(d) { return args.scales.Y(d).toFixed(2); }); - - g.selectAll('.yax-labels') - .data(scale_ticks).enter() - .append('text') - .attr('x', args.left - args.yax_tick_length * 3 / 2) - .attr('dx', -3).attr('y', function(d) { - return args.scales.Y(d).toFixed(2); - }) - .attr('dy', '.35em') - .attr('text-anchor', 'end') - .text(function(d, i) { - var o = yax_format(d); - return o; - }) - - if (args.y_rug) { - y_rug(args); - } + rug.attr('x1', args.scalefns.xf) + .attr('x2', args.scalefns.xf) + .attr('y1', args.height-args.top+buffer_size) + .attr('y2', args.height-args.top); - return this; -} + if (args.color_accessor) { + rug.attr('stroke', args.scalefns.color); + rug.classed('x-rug-mono', false); + } + else { + rug.attr('stroke', null); + rug.classed('x-rug-mono', true); + } + } -function y_axis_categorical(args) { - // first, come up with y_axis - var svg_height = args.height; - if (args.chart_type == 'bar' && svg_height == null){ - // we need to set a new height variable. - } + function x_axis(args) { + 'use strict'; + var svg = d3.select($(args.target).find('svg').get(0)); + var $svg = $($(args.target).find('svg').get(0)); - args.scales.Y = d3.scale.ordinal() - .domain(args.categorical_variables) - .rangeRoundBands([args.height - args.bottom - args.buffer, args.top], args.padding_percentage, args.outer_padding_percentage); + var g; + var min_x; + var max_x; - args.scalefns.yf = function(di) { - return args.scales.Y(di[args.y_accessor]); - } + args.scalefns.xf = function(di) { + return args.scales.X(di[args.x_accessor]); + } - var svg = d3.select($(args.target).find('svg').get(0)); - var $svg = $($(args.target).find('svg').get(0)); + if (args.chart_type == 'point') { + // figure out + var min_size, max_size, min_color, max_color, size_range, color_range, size_domain, color_domain; + if (args.color_accessor != null) { + if (args.color_domain == null) { + if (args.color_type=='number') { + min_color = d3.min(args.data[0], function(d) { + return d[args.color_accessor] + }); + + max_color = d3.max(args.data[0], function(d){ + return d[args.color_accessor] + }); + + color_domain = [min_color, max_color]; + } + else if (args.color_type == 'category') { + color_domain = d3.set(args.data[0] + .map(function(d) { + return d[args.color_accessor]; + })) + .values(); + + color_domain.sort(); + } + } + else { + color_domain = args.color_domain; + } + + if (args.color_range == null){ + if (args.color_type=='number') { + color_range = ['blue', 'red']; + } else { + color_range = null; + } + + } else { + color_range = args.color_range; + } + + if (args.color_type=='number') { + args.scales.color = d3.scale.linear() + .domain(color_domain) + .range(color_range) + .clamp(true); + } else { + args.scales.color = args.color_range != null + ? d3.scale.ordinal().range(color_range) + : (color_domain.length > 10 + ? d3.scale.category20() : d3.scale.category10()); + + args.scales.color.domain(color_domain); + } + + args.scalefns.color = function(di) { + return args.scales.color(di[args.color_accessor]); + }; + } + + if (args.size_accessor != null) { + if (args.size_domain == null) { + min_size = d3.min(args.data[0], function(d){ + return d[args.size_accessor] + }); + + max_size = d3.max(args.data[0], function(d){ + return d[args.size_accessor]; + }); + + size_domain = [min_size, max_size]; + } else { + size_domain = args.size_domain; + } + if (args.size_range == null) { + size_range = [1,5];//args.size_domain; + } else { + size_range = args.size_range; + } + + args.scales.size=d3.scale.linear() + .domain(size_domain) + .range(size_range) + .clamp(true); + + args.scalefns.size = function(di) { + return args.scales.size(di[args.size_accessor]); + }; + } + } - //remove the old y-axis, add new one - $svg.find('.y-axis').remove(); + var last_i; - var g = svg.append('g') - .classed('y-axis', true) - .classed('y-axis-small', args.use_small_class); + if(args.chart_type == 'line') { + for(var i=0; i max_x || !max_x) + max_x = args.data[i][last_i][args.x_accessor]; + } + } + else if(args.chart_type == 'point') { + max_x = d3.max(args.data[0], function(d){return d[args.x_accessor]}); + min_x = d3.min(args.data[0], function(d){return d[args.x_accessor]}); + } + else if(args.chart_type == 'histogram') { + min_x = d3.min(args.data[0], function(d){return d[args.x_accessor]}); + max_x = d3.max(args.data[0], function(d){return d[args.x_accessor]}); + + //force override xax_format + //todo revisit to see if this makes sense + args.xax_format = function(f) { + if (f < 1.0) { + //don't scale tiny values + return args.yax_units + d3.round(f, args.decimals); + } + else { + var pf = d3.formatPrefix(f); + return args.xax_units + pf.scale(f) + pf.symbol; + } + } + } + else if(args.chart_type == 'bar') { + //min_x = d3.min(args.data[0], function(d){return d[args.value_accessor]}); + + min_x = 0; // TODO: think about what actually makes sense. + max_x = d3.max(args.data[0], function(d){ + var trio = []; + trio.push(d[args.x_accessor]); + + if (args.baseline_accessor!=null){ + trio.push(d[args.baseline_accessor]); + }; + + if (args.predictor_accessor!=null){ + trio.push(d[args.predictor_accessor]); + } + + return Math.max.apply(null, trio); + }); + + args.xax_format = function(f) { + if (f < 1.0) { + //don't scale tiny values + return args.yax_units + d3.round(f, args.decimals); + } + else { + var pf = d3.formatPrefix(f); + return args.xax_units + pf.scale(f) + pf.symbol; + } + } + } - return this; -} + min_x = args.min_x ? args.min_x : min_x; + max_x = args.max_x ? args.max_x : max_x; + args.x_axis_negative = false; -function x_rug(args) { - 'use strict'; - var buffer_size = args.chart_type =='point' - ? args.buffer / 2 - : args.buffer; - - var svg = d3.select($(args.target).find('svg').get(0)); - var all_data=[]; - for (var i=0; i 10 - ? d3.scale.category20() : d3.scale.category10()); - - args.scales.color.domain(color_domain); - } - - args.scalefns.color = function(di) { - return args.scales.color(di[args.color_accessor]); - }; - } + //add x ticks + g.selectAll('.xax-ticks') + .data(args.scales.X.ticks(args.xax_count)).enter() + .append('line') + .attr('x1', function(d) { return args.scales.X(d).toFixed(2); }) + .attr('x2', function(d) { return args.scales.X(d).toFixed(2); }) + .attr('y1', args.height - args.bottom) + .attr('y2', function() { + return (args.x_extended_ticks) + ? args.top + : args.height - args.bottom + args.xax_tick_length; + }) + .attr('class', function() { + if(args.x_extended_ticks) + return 'extended-x-ticks'; + }); + + g.selectAll('.xax-labels') + .data(args.scales.X.ticks(args.xax_count)).enter() + .append('text') + .attr('x', function(d) { return args.scales.X(d).toFixed(2); }) + .attr('y', (args.height - args.bottom + args.xax_tick_length * 7 / 3).toFixed(2)) + .attr('dy', '.50em') + .attr('text-anchor', 'middle') + .text(function(d) { + return args.xax_units + args.xax_format(d); + }) + + //are we adding years to x-axis + if (args.time_series && args.show_years) { + var min_x; + var max_x; + + for (var i=0; i max_x || !max_x) + max_x = args.data[i][last_i][args.x_accessor]; + } + + var years = d3.time.years(min_x, max_x); + + if (years.length == 0){ + var first_tick = args.scales.X.ticks(args.xax_count)[0]; + years = [first_tick]; + } + + //append year marker to x-axis group + g = g.append('g') + .classed('year-marker', true) + .classed('year-marker-small', args.use_small_class); + + g.selectAll('.year_marker') + .data(years).enter() + .append('line') + .attr('x1', function(d) { return args.scales.X(d).toFixed(2); }) + .attr('x2', function(d) { return args.scales.X(d).toFixed(2); }) + .attr('y1', args.top) + .attr('y2', args.height - args.bottom); + + var yformat = d3.time.format('%Y'); + g.selectAll('.year_marker') + .data(years).enter() + .append('text') + .attr('x', function(d) { return args.scales.X(d).toFixed(2); }) + .attr('y', (args.height - args.bottom + args.xax_tick_length * 7 / 1.3).toFixed(2)) + .attr('dy', args.use_small_class ? -3 : 0)//(args.y_extended_ticks) ? 0 : 0 ) + .attr('text-anchor', 'middle') + .text(function(d) { + return yformat(d); + }); + }; + + if (args.x_rug){ + x_rug(args); + } - if (args.size_accessor != null) { - if (args.size_domain == null) { - min_size = d3.min(args.data[0], function(d){ - return d[args.size_accessor] - }); - - max_size = d3.max(args.data[0], function(d){ - return d[args.size_accessor]; - }); - - size_domain = [min_size, max_size]; - } else { - size_domain = args.size_domain; - } - if (args.size_range == null) { - size_range = [1,5];//args.size_domain; - } else { - size_range = args.size_range; - } - - args.scales.size=d3.scale.linear() - .domain(size_domain) - .range(size_range) - .clamp(true); - - args.scalefns.size = function(di) { - return args.scales.size(di[args.size_accessor]); - }; - } - } + return this; + } - var last_i; + function init(args) { + 'use strict'; + var defaults = { + target: null, + title: null, + description: null + }; - if(args.chart_type == 'line') { - for(var i=0; i max_x || !max_x) - max_x = args.data[i][last_i][args.x_accessor]; - } - } - else if(args.chart_type == 'point') { - max_x = d3.max(args.data[0], function(d){return d[args.x_accessor]}); - min_x = d3.min(args.data[0], function(d){return d[args.x_accessor]}); - } - else if(args.chart_type == 'histogram') { - min_x = d3.min(args.data[0], function(d){return d[args.x_accessor]}); - max_x = d3.max(args.data[0], function(d){return d[args.x_accessor]}); - - //force override xax_format - //todo revisit to see if this makes sense - args.xax_format = function(f) { - if (f < 1.0) { - //don't scale tiny values - return args.yax_units + d3.round(f, args.decimals); - } - else { - var pf = d3.formatPrefix(f); - return args.xax_units + pf.scale(f) + pf.symbol; - } - } - } - else if(args.chart_type == 'bar') { - //min_x = d3.min(args.data[0], function(d){return d[args.value_accessor]}); - - min_x = 0; // TODO: think about what actually makes sense. - max_x = d3.max(args.data[0], function(d){ - var trio = []; - trio.push(d[args.x_accessor]); - - if (args.baseline_accessor!=null){ - trio.push(d[args.baseline_accessor]); - }; - - if (args.predictor_accessor!=null){ - trio.push(d[args.predictor_accessor]); - } - - return Math.max.apply(null, trio); - }); - - args.xax_format = function(f) { - if (f < 1.0) { - //don't scale tiny values - return args.yax_units + d3.round(f, args.decimals); - } - else { - var pf = d3.formatPrefix(f); - return args.xax_units + pf.scale(f) + pf.symbol; - } - } - } + //do we have a time_series? + if($.type(args.data[0][0][args.x_accessor]) == 'date') { + args.time_series = true; + } + else { + args.time_series = false; + } - min_x = args.min_x ? args.min_x : min_x; - max_x = args.max_x ? args.max_x : max_x; - args.x_axis_negative = false; + var linked; - if (!args.time_series) { - if (min_x < 0){ - min_x = min_x - (max_x * (args.inflator-1)); - args.x_axis_negative = true; - } - } + var svg_width = args.width; + var svg_height = args.height; - // this is for some charts that might need additional buffer, such as the bar chart. - var additional_buffer; + if (args.chart_type=='bar' && svg_height == null){ + svg_height = args.height = args.data[0].length * args.bar_height + args.top + args.bottom; + } + //remove the svg if the chart type has changed + var svg = $(args.target).find('svg'); + if((svg.find('.main-line').length > 0 && args.chart_type != 'line') + || (svg.find('.points').length > 0 && args.chart_type != 'point') + || (svg.find('.histogram').length > 0 && args.chart_type != 'histogram') + || (svg.find('.barplot').length > 0 && args.chart_type != 'bar') + ) { + $(args.target).empty(); - if (args.chart_type == 'bar'){ - additional_buffer = args.buffer*5; - } else { - additional_buffer = 0; - } + } - args.scales.X = (args.time_series) - ? d3.time.scale() - : d3.scale.linear(); - - args.scales.X - .domain([min_x, max_x]) - .range([args.left + args.buffer, args.width - args.right - args.buffer - additional_buffer]); - - //remove the old x-axis, add new one - $svg.find('.x-axis').remove(); - - if (!args.x_axis) return this; - - //x axis - g = svg.append('g') - .classed('x-axis', true) - .classed('x-axis-small', args.use_small_class); - - var last_i = args.scales.X.ticks(args.xax_count).length-1; - - //are we adding a label? - if(args.x_label) { - g.append('text') - .attr('class', 'label') - .attr('x', function() { - return args.left + args.buffer - + ((args.width - args.right - args.buffer) - - (args.left + args.buffer)) / 2; - }) - .attr('y', (args.height - args.bottom / 2).toFixed(2)) - .attr('dy', '.50em') - .attr('text-anchor', 'middle') - .text(function(d) { - return args.x_label; - }) - } + //add svg if it doesn't already exist + //using trim on html rather than :empty to ignore white spaces if they exist + if($.trim($(args.target).html()) == '') { + //add svg + d3.select(args.target) + .append('svg') + .classed('linked', args.linked) + .attr('width', svg_width) + .attr('height', svg_height); + } - if(args.chart_type != 'bar' && !args.x_extended_ticks && !args.y_extended_ticks) { - //extend axis line across bottom, rather than from domain's min..max - g.append('line') - .attr('x1', - (args.concise == false || args.xax_count == 0) - ? args.left + args.buffer - : (args.scales.X(args.scales.X.ticks(args.xax_count)[0])).toFixed(2) - ) - .attr('x2', - (args.concise == false || args.xax_count == 0) - ? args.width - args.right - args.buffer - : (args.scales.X(args.scales.X.ticks(args.xax_count)[last_i])).toFixed(2) - ) - .attr('y1', args.height - args.bottom) - .attr('y2', args.height - args.bottom); - } + var svg = d3.select(args.target).selectAll('svg'); + + //has the width or height changed? + if(args.width != Number(svg.attr('width'))) + svg.attr('width', args.width) + + if(args.height != Number(svg.attr('height'))) + svg.attr('height', args.height) + + // remove missing class + svg.classed('missing', false); + // remove missing text + svg.selectAll('.missing-text').remove(); + + //add chart title if it's different than existing one + chart_title(args); + + //draw axes + args.use_small_class = args.height - args.top - args.bottom - args.buffer + <= args.small_height_threshold && args.width - args.left-args.right - args.buffer * 2 + <= args.small_width_threshold || args.small_text; + + //if we're updating an existing chart and we have fewer lines than + //before, remove the outdated lines, e.g. if we had 3 lines, and we're calling + //data_graphic() on the same target with 2 lines, remove the 3rd line + if(args.data.length < $(args.target).find('svg .main-line').length) { + //now, the thing is we can't just remove, say, line3 if we have a custom + //line-color map, instead, see which are the lines to be removed, and delete those + if(args.custom_line_color_map.length > 0) { + var array_full_series = function(len) { + var arr = new Array(len); + for(var i=0;inum_of_new; i--) { + $(args.target).find('svg .main-line.line' + i + '-color').remove(); + } + } + } - //add x ticks - g.selectAll('.xax-ticks') - .data(args.scales.X.ticks(args.xax_count)).enter() - .append('line') - .attr('x1', function(d) { return args.scales.X(d).toFixed(2); }) - .attr('x2', function(d) { return args.scales.X(d).toFixed(2); }) - .attr('y1', args.height - args.bottom) - .attr('y2', function() { - return (args.x_extended_ticks) - ? args.top - : args.height - args.bottom + args.xax_tick_length; - }) - .attr('class', function() { - if(args.x_extended_ticks) - return 'extended-x-ticks'; - }); - - g.selectAll('.xax-labels') - .data(args.scales.X.ticks(args.xax_count)).enter() - .append('text') - .attr('x', function(d) { return args.scales.X(d).toFixed(2); }) - .attr('y', (args.height - args.bottom + args.xax_tick_length * 7 / 3).toFixed(2)) - .attr('dy', '.50em') - .attr('text-anchor', 'middle') - .text(function(d) { - return args.xax_units + args.xax_format(d); - }) - - //are we adding years to x-axis - if (args.time_series && args.show_years) { - var min_x; - var max_x; - - for (var i=0; i max_x || !max_x) - max_x = args.data[i][last_i][args.x_accessor]; - } + return this; + } - var years = d3.time.years(min_x, max_x); + function markers(args) { + 'use strict'; + var svg = d3.select($(args.target).find('svg').get(0)); + var gm; + var gb; + + if(args.markers) { + $(args.target).find('svg .markers').remove(); + + gm = svg.append('g') + .attr('class', 'markers'); + + gm.selectAll('.markers') + .data(args.markers.filter(function(d){ + return (args.scales.X(d[args.x_accessor]) > args.buffer + args.left) + && (args.scales.X(d[args.x_accessor]) < args.width - args.buffer - args.right); + })) + .enter() + .append('line') + .attr('x1', function(d) { + return args.scales.X(d[args.x_accessor]).toFixed(2); + }) + .attr('x2', function(d) { + return args.scales.X(d[args.x_accessor]).toFixed(2); + }) + .attr('y1', args.top) + .attr('y2', function() { + return args.height - args.bottom - args.buffer; + }) + .attr('stroke-dasharray', '3,1'); + + gm.selectAll('.markers') + .data(args.markers.filter(function(d){ + return (args.scales.X(d[args.x_accessor]) > args.buffer + args.left) + && (args.scales.X(d[args.x_accessor]) < args.width - args.buffer - args.right); + })) + .enter() + .append('text') + .attr('x', function(d) { + return args.scales.X(d[args.x_accessor]) + }) + .attr('y', args.top - 8) + .attr('text-anchor', 'middle') + .text(function(d) { + return d['label']; + }); + } - if (years.length == 0){ - var first_tick = args.scales.X.ticks(args.xax_count)[0]; - years = [first_tick]; - } + if(args.baselines) { + svg.selectAll('.baselines').remove(); + gb = svg.append('g') + .attr('class', 'baselines'); + + gb.selectAll('.baselines') + .data(args.baselines) + .enter().append('line') + .attr('x1', args.left + args.buffer) + .attr('x2', args.width-args.right-args.buffer) + .attr('y1', function(d){ + return args.scales.Y(d['value']).toFixed(2); + }) + .attr('y2', function(d){ + return args.scales.Y(d['value']).toFixed(2); + }); + + gb.selectAll('.baselines') + .data(args.baselines) + .enter().append('text') + .attr('x', args.width-args.right - args.buffer) + .attr('y', function(d){ + return args.scales.Y(d['value']).toFixed(2); + }) + .attr('dy', -3) + .attr('text-anchor', 'end') + .text(function(d) { + return d['label']; + }); + } - //append year marker to x-axis group - g = g.append('g') - .classed('year-marker', true) - .classed('year-marker-small', args.use_small_class); - - g.selectAll('.year_marker') - .data(years).enter() - .append('line') - .attr('x1', function(d) { return args.scales.X(d).toFixed(2); }) - .attr('x2', function(d) { return args.scales.X(d).toFixed(2); }) - .attr('y1', args.top) - .attr('y2', args.height - args.bottom); - - var yformat = d3.time.format('%Y'); - g.selectAll('.year_marker') - .data(years).enter() - .append('text') - .attr('x', function(d) { return args.scales.X(d).toFixed(2); }) - .attr('y', (args.height - args.bottom + args.xax_tick_length * 7 / 1.3).toFixed(2)) - .attr('dy', args.use_small_class ? -3 : 0)//(args.y_extended_ticks) ? 0 : 0 ) - .attr('text-anchor', 'middle') - .text(function(d) { - return yformat(d); - }); - }; - - if (args.x_rug){ - x_rug(args); + return this; + } + + /*! + * Bootstrap v3.3.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + + /*! + * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=c3834cc5b59ef727da53) + * Config saved to config.json and https://gist.github.com/c3834cc5b59ef727da53 + */ + if (typeof jQuery === 'undefined') { + throw new Error('Bootstrap\'s JavaScript requires jQuery') + } + +function ($) { + var version = $.fn.jquery.split(' ')[0].split('.') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') } + }(jQuery); - return this; -} + /* ======================================================================== + * Bootstrap: dropdown.js v3.3.1 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ -function init(args) { + + +function ($) { 'use strict'; - var defaults = { - target: null, - title: null, - description: null - }; - - var args = arguments[0]; - if (!args) { args = {}; } - args = merge_with_defaults(args, defaults); - - //this is how we're dealing with passing in a single array of data, - //but with the intention of using multiple values for multilines, etc. - - //do we have a time_series? - if($.type(args.data[0][0][args.x_accessor]) == 'date') { - args.time_series = true; - } - else { - args.time_series = false; - } - var linked; + if(typeof $().dropdown == 'function') + return true; - var svg_width = args.width; - var svg_height = args.height; + // DROPDOWN CLASS DEFINITION + // ========================= - if (args.chart_type=='bar' && svg_height == null){ - svg_height = args.height = args.data[0].length * args.bar_height + args.top + args.bottom; + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) } - //remove the svg if the chart type has changed - var svg = $(args.target).find('svg'); - if((svg.find('.main-line').length > 0 && args.chart_type != 'line') - || (svg.find('.points').length > 0 && args.chart_type != 'point') - || (svg.find('.histogram').length > 0 && args.chart_type != 'histogram') - || (svg.find('.barplot').length > 0 && args.chart_type != 'bar') - ) { - $(args.target).empty(); + Dropdown.VERSION = '3.3.1' + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('"); - var the_string = ''; - - for (var feature in this.feature_set) { - features = this.feature_set[feature]; - $(this.target + ' div.segments').append( - '
' + // This never changes. - '' + - '' - + '
'); - - for (var i=0;i' - + features[i] + '' - ); - } - } - - $('.' + this._strip_punctuation(feature) + '-btns .dropdown-menu li a').on('click', function() { - var k = $(this).data('key'); - var feature = $(this).data('feature'); - var manual_feature; - $('.' + this._strip_punctuation(feature) + '-btns button.btn span.title').html(k); - if (!manual_map.hasOwnProperty(feature)) { - callback(feature, k); - } else { - manual_feature = manual_map[feature]; - manual_callback[manual_feature](k); - } - - return false; - }) - } + this.init = function(args) { + chart_title(args); - return this; - } + // create svg if one doesn't exist + d3.select(args.target).selectAll('svg').data([args]) + .enter().append('svg') + .attr('width', args.width) + .attr('height', args.height); - return this -} + // delete child elements + d3.select(args.target).selectAll('svg *').remove() -charts.line = function(args) { - 'use strict'; - this.args = args; - - this.init = function(args) { - raw_data_transformation(args); - process_line(args); - init(args); - x_axis(args); - y_axis(args); - return this; - } + var svg = d3.select(args.target).select('svg') - this.mainPlot = function() { - var svg = d3.select($(args.target).find('svg').get(0)); - var g; - var data_median = 0; - - //main area - var area = d3.svg.area() - .x(args.scalefns.xf) - .y0(args.scales.Y.range()[0]) - .y1(args.scalefns.yf) - .interpolate(args.interpolate); - - //confidence band - var confidence_area; - if(args.show_confidence_band) { - var confidence_area = d3.svg.area() - .x(args.scalefns.xf) - .y0(function(d) { - var l = args.show_confidence_band[0]; - return args.scales.Y(d[l]); - }) - .y1(function(d) { - var u = args.show_confidence_band[1]; - return args.scales.Y(d[u]); - }) - .interpolate(args.interpolate); - } + // add missing class + svg.classed('missing', true); - //main line - var line = d3.svg.line() - .x(args.scalefns.xf) - .y(args.scalefns.yf) - .interpolate(args.interpolate); - - //for animating line on first load - var flat_line = d3.svg.line() - .x(args.scalefns.xf) - .y(function() { return args.scales.Y(data_median); }) - .interpolate(args.interpolate); - - - //for building the optional legend - var legend = ''; - var this_data; - - for(var i=args.data.length-1; i>=0; i--) { - this_data = args.data[i]; - - //override increment if we have a custom increment series - var line_id = i+1; - if(args.custom_line_color_map.length > 0) { - line_id = args.custom_line_color_map[i]; - } - - //add confidence band - if(args.show_confidence_band) { - svg.append('path') - .attr('class', 'confidence-band') - .attr('d', confidence_area(args.data[i])); - } - - //add the area - var $area = $(args.target).find('svg path.area' + (line_id) + '-color'); - if(args.area && !args.use_data_y_min && !args.y_axis_negative && args.data.length <= 1) { - //if area already exists, transition it - if($area.length > 0) { - d3.selectAll($(args.target).find('svg path.area' + (line_id) + '-color')) - .transition() - .duration(function() { - return (args.transition_on_update) ? 1000 : 0; - }) - .attr('d', area(args.data[i])); - } - else { //otherwise, add the area - svg.append('path') - .attr('class', 'main-area ' + 'area' + (line_id) + '-color') - .attr('d', area(args.data[i])); - } - } else if ($area.length > 0) { - $area.remove(); - } - - //add the line, if it already exists, transition the fine gentleman - if($(args.target).find('svg path.line' + (line_id) + '-color').length > 0) { - d3.selectAll($(args.target).find('svg path.line' + (line_id) + '-color')) - .transition() - .duration(function() { - return (args.transition_on_update) ? 1000 : 0; - }) - .attr('d', line(args.data[i])); - } - else { //otherwise... - //if we're animating on load, animate the line from its median value - if(args.animate_on_load) { - data_median = d3.median(args.data[i], function(d) { - return d[args.y_accessor]; - }) - - svg.append('path') - .attr('class', 'main-line ' + 'line' + (line_id) + '-color') - .attr('d', flat_line(args.data[i])) - .transition() - .duration(1000) - .attr('d', line(args.data[i])); - } - else { //or just add the line - svg.append('path') - .attr('class', 'main-line ' + 'line' + (line_id) + '-color') - .attr('d', line(args.data[i])); - } - } - - //build legend - if(args.legend) { - legend = "— " - + args.legend[i] + "  " + legend; - } - } + // do we need to clear the legend? + if(args.legend_target) + $(args.legend_target).html(''); - if(args.legend) { - $(args.legend_target).html(legend); - } + svg.append('rect') + .attr('class', 'missing-pane') + .attr('x', args.left) + .attr('y', args.top) + .attr('width', args.width - (args.left * 2)) + .attr('height', args.height - (args.top * 2)); - return this; - } + // add missing text + svg.selectAll('.missing_text').data([args.missing_text]) + .enter().append('text') + .attr('class', 'missing-text') + .attr('x', args.width / 2) + .attr('y', args.height / 2) + .attr('dy', '.50em') + .attr('text-anchor', 'middle') + .text(args.missing_text) + + return this; + } - this.markers = function() { - markers(args); - return this; - }; - - this.rollover = function() { - var svg = d3.select($(args.target).find('svg').get(0)); - var $svg = $($(args.target).find('svg').get(0)); - var g; - - //remove the old rollovers if they already exist - $svg.find('.transparent-rollover-rect').remove(); - $svg.find('.voronoi').remove(); - - //remove the old rollover text and circle if they already exist - $svg.find('.active_datapoint').remove(); - $svg.find('.line_rollover_circle').remove(); - - //rollover text - svg.append('text') - .attr('class', 'active_datapoint') - .classed('active-datapoint-small', args.use_small_class) - .attr('xml:space', 'preserve') - .attr('x', args.width - args.right) - .attr('y', args.top / 2) - .attr('text-anchor', 'end'); - - //append circle - svg.append('circle') - .classed('line_rollover_circle', true) - .attr('cx', 0) - .attr('cy', 0) - .attr('r', 0); - - //update our data by setting a unique line id for each series - //increment from 1... unless we have a custom increment series - var line_id = 1; - - for(var i=0;i 0) { - args.data[i][j]['line_id'] = args.custom_line_color_map[i]; - } - else { - args.data[i][j]['line_id'] = line_id; - } - } - line_id++; - } + this.init(args); + return this; + } - //for multi-line, use voronoi - if(args.data.length > 1) { - //main rollover - var voronoi = d3.geom.voronoi() - .x(function(d) { return args.scales.X(d[args.x_accessor]).toFixed(2); }) - .y(function(d) { return args.scales.Y(d[args.y_accessor]).toFixed(2); }) - .clipExtent([[args.buffer, args.buffer], [args.width - args.buffer, args.height - args.buffer]]); - - var g = svg.append('g') - .attr('class', 'voronoi') - - //we'll be using these when constructing the voronoi rollovers - var data_nested = d3.nest() - .key(function(d) { - return args.scales.X(d[args.x_accessor]) + "," - + args.scales.Y(d[args.y_accessor]); - }) - .rollup(function(v) { return v[0]; }) - .entries(d3.merge(args.data.map(function(d) { return d; }))) - .map(function(d) { return d.values; }); - - //add the voronoi rollovers - g.selectAll('path') - .data(voronoi(data_nested)) - .enter() - .append('path') - .attr("d", function(d) { return "M" + d.join("L") + "Z"; }) - .datum(function(d) { return d.point; }) //because of d3.nest, reassign d - .attr('class', function(d) { - if(args.linked) { - var v = d[args.x_accessor]; - var formatter = d3.time.format('%Y-%m-%d'); - - //only format when x-axis is date - var id = (typeof v === 'number') - ? i - : formatter(v); - - return 'line' + d['line_id'] + '-color ' + 'roll_' + id; - } - else { - return 'line' + d['line_id'] + '-color'; - } - }) - .on('mouseover', this.rolloverOn(args)) - .on('mouseout', this.rolloverOff(args)); - } - //for single line, use rects - else { - //set to 1 unless we have a custom increment series - var line_id = 1; - if(args.custom_line_color_map.length > 0) { - line_id = args.custom_line_color_map[0]; - } - - var g = svg.append('g') - .attr('class', 'transparent-rollover-rect') - - var xf = args.data[0].map(args.scalefns.xf); - - g.selectAll('.rollover-rects') - .data(args.data[0]).enter() - .append('rect') - .attr('class', function(d, i) { - if(args.linked) { - var v = d[args.x_accessor]; - var formatter = d3.time.format('%Y-%m-%d'); - - //only format when x-axis is date - var id = (typeof v === 'number') - ? i - : formatter(v); - - return 'line' + line_id + '-color ' + 'roll_' + id; - } - else { - return 'line' + line_id + '-color'; - } - }) - .attr('x', function(d, i) { - if (i == 0) { - return xf[i].toFixed(2); - } else { - return ((xf[i-1] + xf[i])/2).toFixed(2); - } - }) - .attr('y', function(d, i) { - return (args.data.length > 1) - ? args.scalefns.yf(d) - 6 //multi-line chart sensitivity - : args.top; - }) - .attr('width', function(d, i) { - if (i == 0) { - return ((xf[i+1] - xf[i]) / 2).toFixed(2); - } - else if (i == xf.length - 1) { - return ((xf[i] - xf[i-1]) / 2).toFixed(2); - } - else { - return ((xf[i+1] - xf[i-1]) / 2).toFixed(2); - } - }) - .attr('height', function(d, i) { - return (args.data.length > 1) - ? 12 //multi-line chart sensitivity - : args.height - args.bottom - args.top - args.buffer; - }) - .attr('opacity', 0) - .on('mouseover', this.rolloverOn(args)) - .on('mouseout', this.rolloverOff(args)); - } - return this; - } - this.rolloverOn = function(args) { - var svg = d3.select($(args.target).find('svg').get(0)); - var x_formatter = d3.time.format('%Y-%m-%d'); - - return function(d, i) { - //show circle on mouse-overed rect - svg.selectAll('circle.line_rollover_circle') - .attr('class', "") - .attr('class', 'area' + d['line_id'] + '-color') - .classed('line_rollover_circle', true) - .attr('cx', function() { - return args.scales.X(d[args.x_accessor]).toFixed(2); - }) - .attr('cy', function() { - return args.scales.Y(d[args.y_accessor]).toFixed(2); - }) - .attr('r', args.point_size) - .style('opacity', 1); - - //trigger mouseover on all rects for this date in .linked charts - if(args.linked && !globals.link) { - globals.link = true; - - var v = d[args.x_accessor]; - var formatter = d3.time.format('%Y-%m-%d'); - - //only format when y-axis is date - var id = (typeof v === 'number') - ? i - : formatter(v); - - //trigger mouseover on matching line in .linked charts - d3.selectAll('.line' + d['line_id'] + '-color.roll_' + id) - .each(function(d, i) { - d3.select(this).on('mouseover')(d,i); - }) - } - - svg.selectAll('text') - .filter(function(g, j) { - return d == g; - }) - .attr('opacity', 0.3); - - var fmt = d3.time.format('%b %e, %Y'); - - if (args.format == 'count') { - var num = function(d_) { - var is_float = d_ % 1 != 0; - var n = d3.format("0,000"); - d_ = is_float ? d3.round(d_, args.decimals) : d_; - return n(d_); - } - } - else { - var num = function(d_) { - var fmt_string = (args.decimals ? '.' + args.decimals : '' ) + '%'; - var n = d3.format(fmt_string); - return n(d_); - } - } - - //update rollover text - if (args.show_rollover_text) { - svg.select('.active_datapoint') - .text(function() { - if(args.time_series) { - var dd = new Date(+d[args.x_accessor]); - dd.setDate(dd.getDate()); - - return fmt(dd) + ' ' + args.yax_units - + num(d[args.y_accessor]); - } - else { - return args.x_accessor + ': ' + d[args.x_accessor] - + ', ' + args.y_accessor + ': ' + args.yax_units - + num(d[args.y_accessor]); - } - }); - } - - if(args.rollover_callback) { - args.rollover_callback(d, i); - } - } - } + function raw_data_transformation(args){ + 'use strict'; - this.rolloverOff = function(args) { - var svg = d3.select($(args.target).find('svg').get(0)); + // We need to account for a few data format cases: + // 1. [{key:__, value:__}, ...] // unnested obj-arrays + // 2. [[{key:__, value:__}, ...], [{key:__, value:__}, ...]] // nested obj-arrays + // 3. [[4323, 2343],..] // unnested 2d array + // 4. [[[4323, 2343],..] , [[4323, 2343],..]] // nested 2d array + if (args.chart_type == 'line'){ + var is_unnested_obj_array = (args.data[0] instanceof Object && !(args.data[0] instanceof Array)); + var is_unnested_array_of_arrays = ( + args.data[0] instanceof Array && + !(args.data[0][0] instanceof Object && + !(args.data[0][0] instanceof Date))); - return function(d, i) { - if(args.linked && globals.link) { - globals.link = false; + if( + is_unnested_obj_array || is_unnested_array_of_arrays){ + args.data = [args.data]; + } + } else { + if (!(args.data[0] instanceof Array)){ + args.data = [args.data]; + } + } - var v = d[args.x_accessor]; - var formatter = d3.time.format('%Y-%m-%d'); - //only format when y-axis is date - var id = (typeof v === 'number') - ? i - : formatter(v); - d3.selectAll('.roll_' + id) - .each(function(d, i) { - d3.select(this).on('mouseout')(d); - }); - } + if (args.y_accessor instanceof Array){ + args.data = args.data.map(function(_d){ + return args.y_accessor.map(function(ya){ + return _d.map(function(di){ + di = MG.clone(di); + if (di[ya]==undefined){ + return undefined; + } + di['multiline_y_accessor'] = di[ya]; + return di; + }).filter(function(di){ + return di != undefined; + }) + }) + })[0]; + + args.y_accessor = 'multiline_y_accessor'; + } - //remove active datapoint text on mouse out - svg.selectAll('circle.line_rollover_circle') - .style('opacity', 0); + //sort x-axis data + if (args.chart_type == 'line'){ + for(var i=0; i= 0 && u <= 1) { + return Math.pow(1 - Math.pow(u,w), w) + } else { + return 0 + } + } - this.rolloverOff = function(args) { - var svg = d3.select($(args.target).find('svg').get(0)); + function _bisquare_weight(u){ + return _pow_weight(u, 2); + } - return function(d, i) { - //reset active bar - d3.selectAll($(args.target).find('svg g.barplot .bar:eq(' + i + ')')) - .classed('active', false); + function _tricube_weight(u){ + return _pow_weight(u, 3); + } - //reset active data point text - svg.select('.active_datapoint') - .text(''); + function _neighborhood_width(x0, xis){ + return Array.max(xis.map(function(xi){ + return Math.abs(x0 - xi) + })) + } - if(args.rollout_callback) { - args.rollout_callback(d, i); - } - } - } + function _manhattan(x1,x2){ + return Math.abs(x1-x2) + } - this.init(args); - return this; -} - -/* -Data Tables - -Along with histograms, bars, lines, and scatters, a simple data table can take you far. -We often just want to look at numbers, organized as a table, where columns are variables, -and rows are data points. Sometimes we want a cell to have a small graphic as the main -column element, in which case we want small multiples. sometimes we want to - -var table = New data_table(data) - .target('div#data-table') - .title({accessor: 'point_name', align: 'left'}) - .description({accessor: 'description'}) - .number({accessor: ''}) - -*/ - -function data_table(args){ - 'use strict'; - this.args = args; - this.args.standard_col = {width:150, font_size:12, font_weight:'normal'}; - this.args.columns = []; - this.formatting_options = [['color', 'color'], ['font-weight', 'font_weight'], ['font-style', 'font_style'], ['font-size', 'font_size']]; - - this._strip_punctuation = function(s){ - var punctuationless = s.replace(/[^a-zA-Z0-9 _]+/g, ''); - var finalString = punctuationless.replace(/ +?/g, ""); - return finalString; - } + function _weighted_means(wxy){ + var wsum = d3.sum(wxy.map(function(wxyi){return wxyi.w})); + + return { + xbar:d3.sum(wxy.map(function(wxyi){ + return wxyi.w * wxyi.x + })) / wsum, + ybar:d3.sum(wxy.map(function(wxyi){ + return wxyi.w * wxyi.y + })) / wsum + } + } - this._format_element = function(element, value, args){ - this.formatting_options.forEach(function(fo){ - var attr = fo[0]; - var key = fo[1]; - if (args[key]) element.style(attr, - typeof args[key] == 'string' || - typeof args[key] == 'number' ? - args[key] : args[key](value)); - }); - } + function _weighted_beta(wxy, xbar, ybar){ + var num = d3.sum(wxy.map(function(wxyi){ + return Math.pow(wxyi.w, 2) * (wxyi.x - xbar) * (wxyi.y - ybar) + })) + var denom = d3.sum(wxy.map(function(wxyi){ + return Math.pow(wxyi.w, 2) * (Math.pow(wxyi.x - xbar), 2) + })) + return num / denom; + } - this._add_column = function(_args, arg_type){ - var standard_column = this.args.standard_col; - var args = merge_with_defaults(clone(_args), clone(standard_column)); - args.type=arg_type; - this.args.columns.push(args); - } - - this.target = function(){ - var target = arguments[0]; - this.args.target = target; - return this; - } - - this.title = function(){ - this._add_column(arguments[0], 'title'); - return this; - } - this.text = function(){ - this._add_column(arguments[0], 'text'); - return this; - } - this.bullet = function(){ - /* - text label - main value - comparative measure - any number of ranges - - additional args: - no title - xmin, xmax - format: percentage - xax_formatter - */ - return this; - } - this.sparkline = function(){ - - return this; - } - this.number = function(){ - this._add_column(arguments[0], 'number'); - return this; - } - - this.display = function(){ - - var this_column; - var args = this.args; - - chart_title(args); - - var target = args.target; - var table = d3.select(target).append('table').classed('data-table', true); - var colgroup = table.append('colgroup'); - var thead = table.append('thead'); - var tbody = table.append('tbody'); - - var this_column, this_title; - var tr, th, td_accessor, td_type, td_value, th_text, td_text, td; - var col; - - tr = thead.append('tr'); - - for (var h=0;h b) {return 1} + return 0 + }); + var x_max = d3.quantile(sorted_x, .98); + var x_min = d3.quantile(sorted_x, .02); - return d3.zip(x_proto, y_proto).map(function(d){ - var p = {}; - p.x = d[0]; - p.y = d[1]; - return p; - }); - -} - -function lowess(x, y, alpha, inc){ - var r = []; - for (var i = 0; i < x.length; i += 1) {r.push(1)} - var _l = _calculate_lowess_fit(x, y, alpha, inc, r); - -} - -function least_squares(x_, y_) { - var x, y, xi, yi, - _x = 0, - _y = 0, - _xy = 0, - _xx = 0; - - var n = x_.length; - if (x_[0] instanceof Date){ - x = x_.map(function(d){ - return d.getTime(); - }); - } else { - x = x_; - }; - - if (y_[0] instanceof Date){ - y = y_.map(function(d){ - return d.getTime(); - }); - } else { - y = y_; - }; - - var xhat = d3.mean(x); - var yhat = d3.mean(y); - var numerator = 0, denominator = 0; - var xi, yi; - for (var i=0; i < x.length; i++){ - xi = x[i]; - yi = y[i]; - numerator += (xi - xhat) * (yi - yhat); - denominator += (xi - xhat) * (xi - xhat) - } + var xy = d3.zip(x, y, residuals).sort(); - var beta = numerator / denominator; - var x0 = yhat - beta * xhat; - - return { - x0:x0, - beta:beta, - fit:function(x){ - return x0 + x * beta; - }} -} - -function _pow_weight(u, w){ - if (u >= 0 && u <= 1) { - return Math.pow(1 - Math.pow(u,w), w) - } else { - return 0 - } -} + var size = Math.abs(x_max - x_min) / inc; -function _bisquare_weight(u){ - return _pow_weight(u, 2); -} + var smallest = x_min// - size; + var largest = x_max// + size; + var x_proto = d3.range(smallest, largest, size); + + var xi_neighbors; + var x_i, beta_i, x0_i, delta_i, xbar, ybar; -function _tricube_weight(u){ - return _pow_weight(u, 3); -} + // for each prototype, find its fit. + var y_proto = []; -function _neighborhood_width(x0, xis){ - return Array.max(xis.map(function(xi){ - return Math.abs(x0 - xi) - })) -} + for (var i = 0; i < x_proto.length; i += 1){ -function _manhattan(x1,x2){ - return Math.abs(x1-x2) -} + x_i = x_proto[i] -function _weighted_means(wxy){ - var wsum = d3.sum(wxy.map(function(wxyi){return wxyi.w})); - - return { - xbar:d3.sum(wxy.map(function(wxyi){ - return wxyi.w * wxyi.x - })) / wsum, - ybar:d3.sum(wxy.map(function(wxyi){ - return wxyi.w * wxyi.y - })) / wsum - } -} + // get k closest neighbors. + xi_neighbors = xy.map(function(xyi){ + return [ + Math.abs(xyi[0] - x_i), + xyi[0], + xyi[1], + xyi[2]] + }).sort().slice(0, k) -function _weighted_beta(wxy, xbar, ybar){ - var num = d3.sum(wxy.map(function(wxyi){ - return Math.pow(wxyi.w, 2) * (wxyi.x - xbar) * (wxyi.y - ybar) - })) - var denom = d3.sum(wxy.map(function(wxyi){ - return Math.pow(wxyi.w, 2) * (Math.pow(wxyi.x - xbar), 2) - })) - return num / denom; -} + // Get the largest distance in the neighbor set. + delta_i = d3.max(xi_neighbors)[0] -function _weighted_least_squares(wxy){ + // Prepare the weights for mean calculation and WLS. - var ybar, xbar, beta_i, x0; + xi_neighbors = xi_neighbors.map(function(wxy){ + return { + w : _tricube_weight(wxy[0] / delta_i) * wxy[3], + x : wxy[1], + y :wxy[2] + }}) + + // Find the weighted least squares, obviously. + var _output = _weighted_least_squares(xi_neighbors) - var _wm = _weighted_means(wxy); + x0_i = _output.x0; + beta_i = _output.beta; - xbar = _wm.xbar; - ybar = _wm.ybar; + // + y_proto.push(x0_i + beta_i * x_i) + } + return {x:x_proto, y:y_proto}; + } - var beta = _weighted_beta(wxy, xbar, ybar) + //a set of helper functions, some that we've written, others that we've borrowed - return { - beta : beta, - xbar : xbar, - ybar : ybar, - x0 : ybar - beta * xbar + MG.convert = {}; + MG.convert.date = function(data, accessor, time_format){ + time_format = (typeof time_format === "undefined") ? '%Y-%m-%d' : time_format; + data = data.map(function(d) { + var fff = d3.time.format(time_format); + d[accessor] = fff.parse(d[accessor]); + return d; + }); - } - return num / denom -} + return data; + } + MG.convert.number = function(data, accessor){ + data = data.map(function(d){ + d[accessor] = Number(d[accessor]); + return d; + }); + return data; + } -function _calculate_lowess_fit(x, y, alpha, inc, residuals){ - // alpha - smoothing factor. 0 < alpha < 1/ - // - // - var k = Math.floor(x.length * alpha); - var sorted_x = x.slice(); + function modify_time_period(data, past_n_days) { + //splice time period + var data_spliced = MG.clone(data); + if(past_n_days != '') { + for(var i=0; i b) {return 1} - return 0 - }); - var x_max = d3.quantile(sorted_x, .98); - var x_min = d3.quantile(sorted_x, .02); + return data_spliced; + } - var xy = d3.zip(x, y, residuals).sort(); + function convert_dates(data, x_accessor, time_format) { - var size = Math.abs(x_max - x_min) / inc; + } - var smallest = x_min// - size; - var largest = x_max// + size; - var x_proto = d3.range(smallest, largest, size); - - var xi_neighbors; - var x_i, beta_i, x0_i, delta_i, xbar, ybar; + var each = function(obj, iterator, context) { + // yanked out of underscore + if (obj == null) return obj; + if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, length = obj.length; i < length; i++) { + if (iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var k in obj) { + if (iterator.call(context, obj[k], k, obj) === breaker) return; + } + } - // for each prototype, find its fit. - var y_proto = []; + return obj; + } - for (var i = 0; i < x_proto.length; i += 1){ + function merge_with_defaults(obj) { + // taken from underscore + each(Array.prototype.slice.call(arguments, 1), function(source) { + if (source) { + for (var prop in source) { + if (obj[prop] === void 0) obj[prop] = source[prop]; + } + } + }) - x_i = x_proto[i] + return obj; + } - // get k closest neighbors. - xi_neighbors = xy.map(function(xyi){ - return [ - Math.abs(xyi[0] - x_i), - xyi[0], - xyi[1], - xyi[2]] - }).sort().slice(0, k) + function number_of_values(data, accessor, value) { + var values = data.filter(function(d){ + return d[accessor] === value; + }) - // Get the largest distance in the neighbor set. - delta_i = d3.max(xi_neighbors)[0] + return values.length; + } - // Prepare the weights for mean calculation and WLS. + function has_values_below(data, accessor, value) { + var values = data.filter(function(d){ + return d[accessor] <= value; + }) - xi_neighbors = xi_neighbors.map(function(wxy){ - return { - w : _tricube_weight(wxy[0] / delta_i) * wxy[3], - x : wxy[1], - y :wxy[2] - }}) - - // Find the weighted least squares, obviously. - var _output = _weighted_least_squares(xi_neighbors) + return values.length > 0; + } - x0_i = _output.x0; - beta_i = _output.beta; - // - y_proto.push(x0_i + beta_i * x_i) - } - return {x:x_proto, y:y_proto}; -} - -//a set of helper functions, some that we've written, others that we've borrowed -function modify_time_period(data, past_n_days) { - //splice time period - var data_spliced = clone(data); - if(past_n_days != '') { - for(var i=0; i= zero_count; + } - return data_spliced; -} - -function convert_dates(data, x_accessor, time_format) { - time_format = (typeof time_format === "undefined") ? '%Y-%m-%d' : time_format; - data = data.map(function(d) { - var fff = d3.time.format(time_format); - d[x_accessor] = fff.parse(d[x_accessor]); - return d; - }); - - return data; -} - -var each = function(obj, iterator, context) { - // yanked out of underscore - if (obj == null) return obj; - if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, length = obj.length; i < length; i++) { - if (iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var k in obj) { - if (iterator.call(context, obj[k], k, obj) === breaker) return; + //deep copy + //http://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object + MG.clone = function(obj) { + // Handle the 3 simple types, and null or undefined + if (null == obj || "object" != typeof obj) return obj; + + // Handle Date + if (obj instanceof Date) { + var copy = new Date(); + copy.setTime(obj.getTime()); + return copy; } - } - - return obj; -} - -function merge_with_defaults(obj) { - // taken from underscore - each(Array.prototype.slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - if (obj[prop] === void 0) obj[prop] = source[prop]; - } - } - }) - - return obj; -} -function number_of_values(data, accessor, value) { - var values = data.filter(function(d){ - return d[accessor] === value; - }) - - return values.length; -} - -function has_values_below(data, accessor, value) { - var values = data.filter(function(d){ - return d[accessor] <= value; - }) - - return values.length > 0; -} + // Handle Array + if (obj instanceof Array) { + var copy = []; + for (var i = 0, len = obj.length; i < len; i++) { + copy[i] = MG.clone(obj[i]); + } + return copy; + } + // Handle Object + if (obj instanceof Object) { + var copy = {}; + for (var attr in obj) { + if (obj.hasOwnProperty(attr)) copy[attr] = MG.clone(obj[attr]); + } + return copy; + } -function has_too_many_zeros(data, accessor, zero_count) { - return number_of_values(data, accessor, 0) >= zero_count; -} + throw new Error("Unable to copy obj! Its type isn't supported."); + } -//deep copy -//http://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object -function clone(obj) { - // Handle the 3 simple types, and null or undefined - if (null == obj || "object" != typeof obj) return obj; + //give us the difference of two int arrays + //http://radu.cotescu.com/javascript-diff-function/ + function arrDiff(a,b) { + var seen = [], diff = []; + for ( var i = 0; i < b.length; i++) + seen[b[i]] = true; + for ( var i = 0; i < a.length; i++) + if (!seen[a[i]]) + diff.push(a[i]); + return diff; + } - // Handle Date - if (obj instanceof Date) { - var copy = new Date(); - copy.setTime(obj.getTime()); - return copy; - } - // Handle Array - if (obj instanceof Array) { - var copy = []; - for (var i = 0, len = obj.length; i < len; i++) { - copy[i] = clone(obj[i]); - } - return copy; - } + function warnDeprecation(message, untilVersion) { + console.warn('Deprecation: ' + message + (untilVersion ? '. This feature will be removed in ' + untilVersion + '.' : ' the near future.')); + console.trace(); + } - // Handle Object - if (obj instanceof Object) { - var copy = {}; - for (var attr in obj) { - if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); - } - return copy; - } - - throw new Error("Unable to copy obj! Its type isn't supported."); -} - -//give us the difference of two int arrays -//http://radu.cotescu.com/javascript-diff-function/ -function arrDiff(a,b) { - var seen = [], diff = []; - for ( var i = 0; i < b.length; i++) - seen[b[i]] = true; - for ( var i = 0; i < a.length; i++) - if (!seen[a[i]]) - diff.push(a[i]); - return diff; -} - -//call this to add a warning icon to a graph and log an error to the console -function error(args) { - var error = ''; - console.log('ERROR : ', args.target, ' : ', args.error); - - $(args.target).find('.chart_title').append(error); -} + //call this to add a warning icon to a graph and log an error to the console + function error(args) { + var error = ''; + console.log('ERROR : ', args.target, ' : ', args.error); + + $(args.target).find('.chart_title').append(error); + } + if (typeof define === "function" && define.amd) define(MG); + else if (typeof module === "object" && module.exports) module.exports = MG; + window.MG = MG; +})(); \ No newline at end of file diff --git a/dist/metricsgraphics.min.js b/dist/metricsgraphics.min.js index 3af1083db7..e7c3706472 100644 --- a/dist/metricsgraphics.min.js +++ b/dist/metricsgraphics.min.js @@ -1,590 +1,2 @@ - -var charts={};var globals={};globals.link=false;globals.version="1.1";function data_graphic(){'use strict';var moz={};moz.defaults={};moz.defaults.all={missing_is_zero:false,legend:'',legend_target:'',error:'',animate_on_load:false,top:40,bottom:30,right:10,left:50,buffer:8,width:350,height:220,small_height_threshold:120,small_width_threshold:160,small_text:false,xax_count:6,xax_tick_length:5,yax_count:5,yax_tick_length:5,x_extended_ticks:false,y_extended_ticks:false,y_scale_type:'linear',max_x:null,max_y:null,min_x:null,min_y:null,min_y_from_data:false,point_size:2.5,x_accessor:'date',xax_units:'',x_label:'',x_axis:true,y_axis:true,y_accessor:'value',y_label:'',yax_units:'',x_rug:false,y_rug:false,transition_on_update:true,rollover_callback:null,show_rollover_text:true,show_confidence_band:null,xax_format:function(d){var df=d3.time.format('%b %d');var pf=d3.formatPrefix(d);switch($.type(args.data[0][0][args.x_accessor])){case'date':return df(d);break;case'number':return pf.scale(d)+pf.symbol;break;default:return d;}},area:true,chart_type:'line',data:[],decimals:2,format:'count',inflator:10/9,linked:false,list:false,baselines:null,markers:null,scalefns:{},scales:{},show_years:true,target:'#viz',interpolate:'cardinal',custom_line_color_map:[],max_data_size:null} -moz.defaults.point={buffer:16,ls:false,lowess:false,point_size:2.5,size_accessor:null,color_accessor:null,size_range:null,color_range:null,size_domain:null,color_domain:null,color_type:'number'} -moz.defaults.histogram={rollover_callback:function(d,i){$('#histogram svg .active_datapoint').html('Frequency Count: '+d.y);},binned:false,bins:null,processed_x_accessor:'x',processed_y_accessor:'y',processed_dx_accessor:'dx',bar_margin:1} -moz.defaults.bar={y_accessor:'factor',x_accessor:'value',baseline_accessor:null,predictor_accessor:null,predictor_proportion:5,dodge_accessor:null,binned:true,padding_percentage:0,outer_padding_percentage:.1,height:500,top:20,bar_height:20,left:70} -moz.defaults.missing={top:0,bottom:0,right:0,left:0,legend_target:'',width:350,height:220,missing_text:'Data currently missing or unavailable'} -var args=arguments[0];if(!args){args={};} -var g='';if(args.list){args.x_accessor=0;args.y_accessor=1;} -if(args.chart_type=='missing-data'){args=merge_with_defaults(args,moz.defaults.missing);charts.missing(args);} -else if(args.chart_type=='point'){var a=merge_with_defaults(moz.defaults.point,moz.defaults.all);args=merge_with_defaults(args,a);charts.point(args).mainPlot().markers().rollover();} -else if(args.chart_type=='histogram'){var a=merge_with_defaults(moz.defaults.histogram,moz.defaults.all);args=merge_with_defaults(args,a);charts.histogram(args).mainPlot().markers().rollover();} -else if(args.chart_type=='bar'){var a=merge_with_defaults(moz.defaults.bar,moz.defaults.all);args=merge_with_defaults(args,a);charts.bar(args).mainPlot().markers().rollover();} -else{args=merge_with_defaults(args,moz.defaults.all);charts.line(args).markers().mainPlot().rollover();} -return args.data;} -if(typeof jQuery==='undefined'){throw new Error('Bootstrap\'s JavaScript requires jQuery')} -+function($){var version=$.fn.jquery.split(' ')[0].split('.') -if((version[0]<2&&version[1]<9)||(version[0]==1&&version[1]==9&&version[2]<1)){throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')}}(jQuery);+function($){'use strict';if(typeof $().tooltip=='function') -return true;var Tooltip=function(element,options){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null -this.init('tooltip',element,options)} -Tooltip.VERSION='3.3.1' -Tooltip.TRANSITION_DURATION=150 -Tooltip.DEFAULTS={animation:true,placement:'top',selector:false,template:'',trigger:'hover focus',title:'',delay:0,html:false,container:false,viewport:{selector:'body',padding:0}} -Tooltip.prototype.init=function(type,element,options){this.enabled=true -this.type=type -this.$element=$(element) -this.options=this.getOptions(options) -this.$viewport=this.options.viewport&&$(this.options.viewport.selector||this.options.viewport) -var triggers=this.options.trigger.split(' ') -for(var i=triggers.length;i--;){var trigger=triggers[i] -if(trigger=='click'){this.$element.on('click.'+this.type,this.options.selector,$.proxy(this.toggle,this))}else if(trigger!='manual'){var eventIn=trigger=='hover'?'mouseenter':'focusin' -var eventOut=trigger=='hover'?'mouseleave':'focusout' -this.$element.on(eventIn+'.'+this.type,this.options.selector,$.proxy(this.enter,this)) -this.$element.on(eventOut+'.'+this.type,this.options.selector,$.proxy(this.leave,this))}} -this.options.selector?(this._options=$.extend({},this.options,{trigger:'manual',selector:''})):this.fixTitle()} -Tooltip.prototype.getDefaults=function(){return Tooltip.DEFAULTS} -Tooltip.prototype.getOptions=function(options){options=$.extend({},this.getDefaults(),this.$element.data(),options) -if(options.delay&&typeof options.delay=='number'){options.delay={show:options.delay,hide:options.delay}} -return options} -Tooltip.prototype.getDelegateOptions=function(){var options={} -var defaults=this.getDefaults() -this._options&&$.each(this._options,function(key,value){if(defaults[key]!=value)options[key]=value}) -return options} -Tooltip.prototype.enter=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data('bs.'+this.type) -if(self&&self.$tip&&self.$tip.is(':visible')){self.hoverState='in' -return} -if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions()) -$(obj.currentTarget).data('bs.'+this.type,self)} -clearTimeout(self.timeout) -self.hoverState='in' -if(!self.options.delay||!self.options.delay.show)return self.show() -self.timeout=setTimeout(function(){if(self.hoverState=='in')self.show()},self.options.delay.show)} -Tooltip.prototype.leave=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data('bs.'+this.type) -if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions()) -$(obj.currentTarget).data('bs.'+this.type,self)} -clearTimeout(self.timeout) -self.hoverState='out' -if(!self.options.delay||!self.options.delay.hide)return self.hide() -self.timeout=setTimeout(function(){if(self.hoverState=='out')self.hide()},self.options.delay.hide)} -Tooltip.prototype.show=function(){var e=$.Event('show.bs.'+this.type) -if(this.hasContent()&&this.enabled){this.$element.trigger(e) -var inDom=$.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]) -if(e.isDefaultPrevented()||!inDom)return -var that=this -var $tip=this.tip() -var tipId=this.getUID(this.type) -this.setContent() -$tip.attr('id',tipId) -this.$element.attr('aria-describedby',tipId) -if(this.options.animation)$tip.addClass('fade') -var placement=typeof this.options.placement=='function'?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement -var autoToken=/\s?auto?\s?/i -var autoPlace=autoToken.test(placement) -if(autoPlace)placement=placement.replace(autoToken,'')||'top' -$tip.detach().css({top:0,left:0,display:'block'}).addClass(placement).data('bs.'+this.type,this) -this.options.container?$tip.appendTo(this.options.container):$tip.insertAfter(this.$element) -var pos=this.getPosition() -var actualWidth=$tip[0].offsetWidth -var actualHeight=$tip[0].offsetHeight -if(autoPlace){var orgPlacement=placement -var $container=this.options.container?$(this.options.container):this.$element.parent() -var containerDim=this.getPosition($container) -placement=placement=='bottom'&&pos.bottom+actualHeight>containerDim.bottom?'top':placement=='top'&&pos.top-actualHeightcontainerDim.width?'left':placement=='left'&&pos.left-actualWidthviewportDimensions.top+viewportDimensions.height){delta.top=viewportDimensions.top+viewportDimensions.height-bottomEdgeOffset}}else{var leftEdgeOffset=pos.left-viewportPadding -var rightEdgeOffset=pos.left+viewportPadding+actualWidth -if(leftEdgeOffsetviewportDimensions.width){delta.left=viewportDimensions.left+viewportDimensions.width-rightEdgeOffset}} -return delta} -Tooltip.prototype.getTitle=function(){var title -var $e=this.$element -var o=this.options -title=$e.attr('data-original-title')||(typeof o.title=='function'?o.title.call($e[0]):o.title) -return title} -Tooltip.prototype.getUID=function(prefix){do prefix+=~~(Math.random()*1000000) -while(document.getElementById(prefix)) -return prefix} -Tooltip.prototype.tip=function(){return(this.$tip=this.$tip||$(this.options.template))} -Tooltip.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find('.tooltip-arrow'))} -Tooltip.prototype.enable=function(){this.enabled=true} -Tooltip.prototype.disable=function(){this.enabled=false} -Tooltip.prototype.toggleEnabled=function(){this.enabled=!this.enabled} -Tooltip.prototype.toggle=function(e){var self=this -if(e){self=$(e.currentTarget).data('bs.'+this.type) -if(!self){self=new this.constructor(e.currentTarget,this.getDelegateOptions()) -$(e.currentTarget).data('bs.'+this.type,self)}} -self.tip().hasClass('in')?self.leave(self):self.enter(self)} -Tooltip.prototype.destroy=function(){var that=this -clearTimeout(this.timeout) -this.hide(function(){that.$element.off('.'+that.type).removeData('bs.'+that.type)})} -function Plugin(option){return this.each(function(){var $this=$(this) -var data=$this.data('bs.tooltip') -var options=typeof option=='object'&&option -var selector=options&&options.selector -if(!data&&option=='destroy')return -if(selector){if(!data)$this.data('bs.tooltip',(data={})) -if(!data[selector])data[selector]=new Tooltip(this,options)}else{if(!data)$this.data('bs.tooltip',(data=new Tooltip(this,options)))} -if(typeof option=='string')data[option]()})} -var old=$.fn.tooltip -$.fn.tooltip=Plugin -$.fn.tooltip.Constructor=Tooltip -$.fn.tooltip.noConflict=function(){$.fn.tooltip=old -return this}}(jQuery);+function($){'use strict';if(typeof $().popover=='function') -return true;var Popover=function(element,options){this.init('popover',element,options)} -if(!$.fn.tooltip)throw new Error('Popover requires tooltip.js') -Popover.VERSION='3.3.1' -Popover.DEFAULTS=$.extend({},$.fn.tooltip.Constructor.DEFAULTS,{placement:'right',trigger:'click',content:'',template:''}) -Popover.prototype=$.extend({},$.fn.tooltip.Constructor.prototype) -Popover.prototype.constructor=Popover -Popover.prototype.getDefaults=function(){return Popover.DEFAULTS} -Popover.prototype.setContent=function(){var $tip=this.tip() -var title=this.getTitle() -var content=this.getContent() -$tip.find('.popover-title')[this.options.html?'html':'text'](title) -$tip.find('.popover-content').children().detach().end()[this.options.html?(typeof content=='string'?'html':'append'):'text'](content) -$tip.removeClass('fade top bottom left right in') -if(!$tip.find('.popover-title').html())$tip.find('.popover-title').hide()} -Popover.prototype.hasContent=function(){return this.getTitle()||this.getContent()} -Popover.prototype.getContent=function(){var $e=this.$element -var o=this.options -return $e.attr('data-content')||(typeof o.content=='function'?o.content.call($e[0]):o.content)} -Popover.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find('.arrow'))} -Popover.prototype.tip=function(){if(!this.$tip)this.$tip=$(this.options.template) -return this.$tip} -function Plugin(option){return this.each(function(){var $this=$(this) -var data=$this.data('bs.popover') -var options=typeof option=='object'&&option -var selector=options&&options.selector -if(!data&&option=='destroy')return -if(selector){if(!data)$this.data('bs.popover',(data={})) -if(!data[selector])data[selector]=new Popover(this,options)}else{if(!data)$this.data('bs.popover',(data=new Popover(this,options)))} -if(typeof option=='string')data[option]()})} -var old=$.fn.popover -$.fn.popover=Plugin -$.fn.popover.Constructor=Popover -$.fn.popover.noConflict=function(){$.fn.popover=old -return this}}(jQuery);function chart_title(args){'use strict';var currentTitle=$(args.target).find('h2.chart_title');if(args.title&&args.title!==currentTitle.text()) -currentTitle.remove();else -return;if(args.target&&args.title){var newTitle;var optional_question_mark=(args.description)?'':'';$(args.target).prepend('

' -+args.title+optional_question_mark+'

');if(args.description){newTitle=$(args.target).find('h2.chart_title');newTitle.popover({html:true,animation:false,content:args.description,trigger:'hover',placement:'top',container:newTitle});}} -if(args.error){error(args);}} -function y_rug(args){'use strict';var svg=d3.select($(args.target).find('svg').get(0));var buffer_size=args.chart_type=='point'?args.buffer/2:args.buffer*2/3;var all_data=[];for(var i=0;i0;});} -if(a.length>0){var extent=d3.extent(a,function(d){return d[args.y_accessor];});if(!_set){min_y=extent[0];max_y=extent[1];_set=true;}else{min_y=Math.min(extent[0],min_y);max_y=Math.max(extent[1],max_y);}}} -if(min_y>=0&&!args.min_y&&!args.min_y_from_data){min_y=0;} -min_y=args.min_y?args.min_y:min_y;max_y=args.max_y?args.max_y:max_y;if(args.y_scale_type!='log'){if(min_y>=0){args.y_axis_negative=false;}else{min_y=min_y-(max_y*(args.inflator-1));args.y_axis_negative=true;}} -max_y=max_y*args.inflator;if(!args.min_y&&args.min_y_from_data){min_y=min_y/args.inflator;} -if(args.y_scale_type=='log'){if(args.chart_type=='histogram'){min_y=0.2;}else{if(min_y<=0){min_y=1;}} -args.scales.Y=d3.scale.log().domain([min_y,max_y]).range([args.height-args.bottom-args.buffer,args.top]).clamp(true);}else{args.scales.Y=d3.scale.linear().domain([min_y,max_y]).range([args.height-args.bottom-args.buffer,args.top]);} -args.scales.Y_axis=d3.scale.linear().domain([min_y,max_y]).range([args.height-args.bottom-args.buffer,args.top]);var yax_format;if(args.format=='count'){yax_format=function(f){if(f<1.0){return args.yax_units+d3.round(f,args.decimals);}else{var pf=d3.formatPrefix(f);return args.yax_units+pf.scale(f)+pf.symbol;}};} -else{yax_format=function(d_){var n=d3.format('%p');return n(d_);}} -$svg.find('.y-axis').remove();if(!args.y_axis)return this;g=svg.append('g').classed('y-axis',true).classed('y-axis-small',args.use_small_class);if(args.y_label){g.append('text').attr('class','label').attr('x',function(){return-1*(args.top+args.buffer+ -((args.height-args.bottom-args.buffer) --(args.top+args.buffer))/2);}).attr('y',function(){return args.left/2;}).attr("dy","0.4em").attr('text-anchor','middle').text(function(d){return args.y_label;}).attr("transform",function(d){return"rotate(-90)";});} -var scale_ticks=args.scales.Y.ticks(args.yax_count);function log10(val){if(val==1000){return 3;} -if(val==1000000){return 7;} -return Math.log(val)/Math.LN10;} -if(args.y_scale_type=='log'){scale_ticks=scale_ticks.filter(function(d){return Math.abs(log10(d))%1<1e-6||Math.abs(log10(d))%1>1-1e-6;});} -var number_of_ticks=args.scales.Y.ticks(args.yax_count).length;var data_is_int=true;$.each(args.data,function(i,d){$.each(d,function(i,d){if(d[args.y_accessor]%1!==0){data_is_int=false;return false;}});});if(data_is_int&&number_of_ticks>max_y&&args.format=='count'){scale_ticks=scale_ticks.filter(function(d){return d%1===0;});} -var last_i=scale_ticks.length-1;if(!args.x_extended_ticks&&!args.y_extended_ticks){g.append('line').attr('x1',args.left).attr('x2',args.left).attr('y1',args.scales.Y(scale_ticks[0]).toFixed(2)).attr('y2',args.scales.Y(scale_ticks[last_i]).toFixed(2));} -g.selectAll('.yax-ticks').data(scale_ticks).enter().append('line').classed('extended-y-ticks',args.y_extended_ticks).attr('x1',args.left).attr('x2',function(){return(args.y_extended_ticks)?args.width-args.right:args.left-args.yax_tick_length;}).attr('y1',function(d){return args.scales.Y(d).toFixed(2);}).attr('y2',function(d){return args.scales.Y(d).toFixed(2);});g.selectAll('.yax-labels').data(scale_ticks).enter().append('text').attr('x',args.left-args.yax_tick_length*3/2).attr('dx',-3).attr('y',function(d){return args.scales.Y(d).toFixed(2);}).attr('dy','.35em').attr('text-anchor','end').text(function(d,i){var o=yax_format(d);return o;}) -if(args.y_rug){y_rug(args);} -return this;} -function y_axis_categorical(args){var svg_height=args.height;if(args.chart_type=='bar'&&svg_height==null){} -args.scales.Y=d3.scale.ordinal().domain(args.categorical_variables).rangeRoundBands([args.height-args.bottom-args.buffer,args.top],args.padding_percentage,args.outer_padding_percentage);args.scalefns.yf=function(di){return args.scales.Y(di[args.y_accessor]);} -var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));$svg.find('.y-axis').remove();var g=svg.append('g').classed('y-axis',true).classed('y-axis-small',args.use_small_class);if(!args.y_axis)return this;g.selectAll('text').data(args.categorical_variables).enter().append('svg:text').attr('x',args.left).attr('y',function(d){return args.scales.Y(d)+args.scales.Y.rangeBand()/2 -+(args.buffer)*args.outer_padding_percentage;}).attr('dy','.35em').attr('text-anchor','end').text(String) -return this;} -function x_rug(args){'use strict';var buffer_size=args.chart_type=='point'?args.buffer/2:args.buffer;var svg=d3.select($(args.target).find('svg').get(0));var all_data=[];for(var i=0;i10?d3.scale.category20():d3.scale.category10());args.scales.color.domain(color_domain);} -args.scalefns.color=function(di){return args.scales.color(di[args.color_accessor]);};} -if(args.size_accessor!=null){if(args.size_domain==null){min_size=d3.min(args.data[0],function(d){return d[args.size_accessor]});max_size=d3.max(args.data[0],function(d){return d[args.size_accessor];});size_domain=[min_size,max_size];}else{size_domain=args.size_domain;} -if(args.size_range==null){size_range=[1,5];}else{size_range=args.size_range;} -args.scales.size=d3.scale.linear().domain(size_domain).range(size_range).clamp(true);args.scalefns.size=function(di){return args.scales.size(di[args.size_accessor]);};}} -var last_i;if(args.chart_type=='line'){for(var i=0;imax_x||!max_x) -max_x=args.data[i][last_i][args.x_accessor];}} -else if(args.chart_type=='point'){max_x=d3.max(args.data[0],function(d){return d[args.x_accessor]});min_x=d3.min(args.data[0],function(d){return d[args.x_accessor]});} -else if(args.chart_type=='histogram'){min_x=d3.min(args.data[0],function(d){return d[args.x_accessor]});max_x=d3.max(args.data[0],function(d){return d[args.x_accessor]});args.xax_format=function(f){if(f<1.0){return args.yax_units+d3.round(f,args.decimals);} -else{var pf=d3.formatPrefix(f);return args.xax_units+pf.scale(f)+pf.symbol;}}} -else if(args.chart_type=='bar'){min_x=0;max_x=d3.max(args.data[0],function(d){var trio=[];trio.push(d[args.x_accessor]);if(args.baseline_accessor!=null){trio.push(d[args.baseline_accessor]);};if(args.predictor_accessor!=null){trio.push(d[args.predictor_accessor]);} -return Math.max.apply(null,trio);});args.xax_format=function(f){if(f<1.0){return args.yax_units+d3.round(f,args.decimals);} -else{var pf=d3.formatPrefix(f);return args.xax_units+pf.scale(f)+pf.symbol;}}} -min_x=args.min_x?args.min_x:min_x;max_x=args.max_x?args.max_x:max_x;args.x_axis_negative=false;if(!args.time_series){if(min_x<0){min_x=min_x-(max_x*(args.inflator-1));args.x_axis_negative=true;}} -var additional_buffer;if(args.chart_type=='bar'){additional_buffer=args.buffer*5;}else{additional_buffer=0;} -args.scales.X=(args.time_series)?d3.time.scale():d3.scale.linear();args.scales.X.domain([min_x,max_x]).range([args.left+args.buffer,args.width-args.right-args.buffer-additional_buffer]);$svg.find('.x-axis').remove();if(!args.x_axis)return this;g=svg.append('g').classed('x-axis',true).classed('x-axis-small',args.use_small_class);var last_i=args.scales.X.ticks(args.xax_count).length-1;if(args.x_label){g.append('text').attr('class','label').attr('x',function(){return args.left+args.buffer -+((args.width-args.right-args.buffer) --(args.left+args.buffer))/2;}).attr('y',(args.height-args.bottom/2).toFixed(2)).attr('dy','.50em').attr('text-anchor','middle').text(function(d){return args.x_label;})} -if(args.chart_type!='bar'&&!args.x_extended_ticks&&!args.y_extended_ticks){g.append('line').attr('x1',(args.concise==false||args.xax_count==0)?args.left+args.buffer:(args.scales.X(args.scales.X.ticks(args.xax_count)[0])).toFixed(2)).attr('x2',(args.concise==false||args.xax_count==0)?args.width-args.right-args.buffer:(args.scales.X(args.scales.X.ticks(args.xax_count)[last_i])).toFixed(2)).attr('y1',args.height-args.bottom).attr('y2',args.height-args.bottom);} -g.selectAll('.xax-ticks').data(args.scales.X.ticks(args.xax_count)).enter().append('line').attr('x1',function(d){return args.scales.X(d).toFixed(2);}).attr('x2',function(d){return args.scales.X(d).toFixed(2);}).attr('y1',args.height-args.bottom).attr('y2',function(){return(args.x_extended_ticks)?args.top:args.height-args.bottom+args.xax_tick_length;}).attr('class',function(){if(args.x_extended_ticks) -return'extended-x-ticks';});g.selectAll('.xax-labels').data(args.scales.X.ticks(args.xax_count)).enter().append('text').attr('x',function(d){return args.scales.X(d).toFixed(2);}).attr('y',(args.height-args.bottom+args.xax_tick_length*7/3).toFixed(2)).attr('dy','.50em').attr('text-anchor','middle').text(function(d){return args.xax_units+args.xax_format(d);}) -if(args.time_series&&args.show_years){var min_x;var max_x;for(var i=0;imax_x||!max_x) -max_x=args.data[i][last_i][args.x_accessor];} -var years=d3.time.years(min_x,max_x);if(years.length==0){var first_tick=args.scales.X.ticks(args.xax_count)[0];years=[first_tick];} -g=g.append('g').classed('year-marker',true).classed('year-marker-small',args.use_small_class);g.selectAll('.year_marker').data(years).enter().append('line').attr('x1',function(d){return args.scales.X(d).toFixed(2);}).attr('x2',function(d){return args.scales.X(d).toFixed(2);}).attr('y1',args.top).attr('y2',args.height-args.bottom);var yformat=d3.time.format('%Y');g.selectAll('.year_marker').data(years).enter().append('text').attr('x',function(d){return args.scales.X(d).toFixed(2);}).attr('y',(args.height-args.bottom+args.xax_tick_length*7/1.3).toFixed(2)).attr('dy',args.use_small_class?-3:0).attr('text-anchor','middle').text(function(d){return yformat(d);});};if(args.x_rug){x_rug(args);} -return this;} -function init(args){'use strict';var defaults={target:null,title:null,description:null};var args=arguments[0];if(!args){args={};} -args=merge_with_defaults(args,defaults);if($.type(args.data[0][0][args.x_accessor])=='date'){args.time_series=true;} -else{args.time_series=false;} -var linked;var svg_width=args.width;var svg_height=args.height;if(args.chart_type=='bar'&&svg_height==null){svg_height=args.height=args.data[0].length*args.bar_height+args.top+args.bottom;} -var svg=$(args.target).find('svg');if((svg.find('.main-line').length>0&&args.chart_type!='line')||(svg.find('.points').length>0&&args.chart_type!='point')||(svg.find('.histogram').length>0&&args.chart_type!='histogram')||(svg.find('.barplot').length>0&&args.chart_type!='bar')){$(args.target).empty();} -if($.trim($(args.target).html())==''){d3.select(args.target).append('svg').classed('linked',args.linked).attr('width',svg_width).attr('height',svg_height);} -var svg=d3.select(args.target).selectAll('svg');if(args.width!=Number(svg.attr('width'))) -svg.attr('width',args.width) -if(args.height!=Number(svg.attr('height'))) -svg.attr('height',args.height) -svg.classed('missing',false);svg.selectAll('.missing-text').remove();chart_title(args);args.use_small_class=args.height-args.top-args.bottom-args.buffer<=args.small_height_threshold&&args.width-args.left-args.right-args.buffer*2<=args.small_width_threshold||args.small_text;if(args.data.length<$(args.target).find('svg .main-line').length){if(args.custom_line_color_map.length>0){var array_full_series=function(len){var arr=new Array(len);for(var i=0;inum_of_new;i--){$(args.target).find('svg .main-line.line'+i+'-color').remove();}}} -return this;} -function markers(args){'use strict';var svg=d3.select($(args.target).find('svg').get(0));var gm;var gb;if(args.markers){$(args.target).find('svg .markers').remove();gm=svg.append('g').attr('class','markers');gm.selectAll('.markers').data(args.markers.filter(function(d){return(args.scales.X(d[args.x_accessor])>args.buffer+args.left)&&(args.scales.X(d[args.x_accessor])args.buffer+args.left)&&(args.scales.X(d[args.x_accessor])').insertAfter($(this)).on('click',clearMenus)} -var relatedTarget={relatedTarget:this} -$parent.trigger(e=$.Event('show.bs.dropdown',relatedTarget)) -if(e.isDefaultPrevented())return -$this.trigger('focus').attr('aria-expanded','true') -$parent.toggleClass('open').trigger('shown.bs.dropdown',relatedTarget)} -return false} -Dropdown.prototype.keydown=function(e){if(!/(38|40|27|32)/.test(e.which)||/input|textarea/i.test(e.target.tagName))return -var $this=$(this) -e.preventDefault() -e.stopPropagation() -if($this.is('.disabled, :disabled'))return -var $parent=getParent($this) -var isActive=$parent.hasClass('open') -if((!isActive&&e.which!=27)||(isActive&&e.which==27)){if(e.which==27)$parent.find(toggle).trigger('focus') -return $this.trigger('click')} -var desc=' li:not(.divider):visible a' -var $items=$parent.find('[role="menu"]'+desc+', [role="listbox"]'+desc) -if(!$items.length)return -var index=$items.index(e.target) -if(e.which==38&&index>0)index-- -if(e.which==40&&index<$items.length-1)index++ -if(!~index)index=0 -$items.eq(index).trigger('focus')} -function clearMenus(e){if(e&&e.which===3)return -$(backdrop).remove() -$(toggle).each(function(){var $this=$(this) -var $parent=getParent($this) -var relatedTarget={relatedTarget:this} -if(!$parent.hasClass('open'))return -$parent.trigger(e=$.Event('hide.bs.dropdown',relatedTarget)) -if(e.isDefaultPrevented())return -$this.attr('aria-expanded','false') -$parent.removeClass('open').trigger('hidden.bs.dropdown',relatedTarget)})} -function getParent($this){var selector=$this.attr('data-target') -if(!selector){selector=$this.attr('href') -selector=selector&&/#[A-Za-z]/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,'')} -var $parent=selector&&$(selector) -return $parent&&$parent.length?$parent:$this.parent()} -function Plugin(option){return this.each(function(){var $this=$(this) -var data=$this.data('bs.dropdown') -if(!data)$this.data('bs.dropdown',(data=new Dropdown(this))) -if(typeof option=='string')data[option].call($this)})} -var old=$.fn.dropdown -$.fn.dropdown=Plugin -$.fn.dropdown.Constructor=Dropdown -$.fn.dropdown.noConflict=function(){$.fn.dropdown=old -return this} -$(document).on('click.bs.dropdown.data-api',clearMenus).on('click.bs.dropdown.data-api','.dropdown form',function(e){e.stopPropagation()}).on('click.bs.dropdown.data-api',toggle,Dropdown.prototype.toggle).on('keydown.bs.dropdown.data-api',toggle,Dropdown.prototype.keydown).on('keydown.bs.dropdown.data-api','[role="menu"]',Dropdown.prototype.keydown).on('keydown.bs.dropdown.data-api','[role="listbox"]',Dropdown.prototype.keydown)}(jQuery);var button_layout=function(target){'use strict';this.target=target;this.feature_set={};this.public_name={};this.sorters={};this.manual=[];this.manual_map={};this.manual_callback={};this._strip_punctuation=function(s){var punctuationless=s.replace(/[^a-zA-Z0-9 _]+/g,'');var finalString=punctuationless.replace(/ +?/g,"");return finalString;} -this.data=function(data){this._data=data;return this;} -this.manual_button=function(feature,feature_set,callback){this.feature_set[feature]=feature_set;this.manual_map[this._strip_punctuation(feature)]=feature;this.manual_callback[feature]=callback;return this;} -this.button=function(feature){var sorter,the_label;if(arguments.length>1){this.public_name[feature]=arguments[1];} -if(arguments.length>2){this.sorters[feature]=arguments[2];} -this.feature_set[feature]=[];return this;} -this.callback=function(callback){this._callback=callback;return this;} -this.display=function(){var callback=this._callback;var manual_callback=this.manual_callback;var manual_map=this.manual_map;var d,f,features,feat;features=Object.keys(this.feature_set);for(var i=0;i");var the_string='';for(var feature in this.feature_set){features=this.feature_set[feature];$(this.target+' div.segments').append('
'+''+'' -+'
');for(var i=0;i' -+features[i]+'');}} -$('.'+this._strip_punctuation(feature)+'-btns .dropdown-menu li a').on('click',function(){var k=$(this).data('key');var feature=$(this).data('feature');var manual_feature;$('.'+this._strip_punctuation(feature)+'-btns button.btn span.title').html(k);if(!manual_map.hasOwnProperty(feature)){callback(feature,k);}else{manual_feature=manual_map[feature];manual_callback[manual_feature](k);} -return false;})} -return this;} -return this} -charts.line=function(args){'use strict';this.args=args;this.init=function(args){raw_data_transformation(args);process_line(args);init(args);x_axis(args);y_axis(args);return this;} -this.mainPlot=function(){var svg=d3.select($(args.target).find('svg').get(0));var g;var data_median=0;var area=d3.svg.area().x(args.scalefns.xf).y0(args.scales.Y.range()[0]).y1(args.scalefns.yf).interpolate(args.interpolate);var confidence_area;if(args.show_confidence_band){var confidence_area=d3.svg.area().x(args.scalefns.xf).y0(function(d){var l=args.show_confidence_band[0];return args.scales.Y(d[l]);}).y1(function(d){var u=args.show_confidence_band[1];return args.scales.Y(d[u]);}).interpolate(args.interpolate);} -var line=d3.svg.line().x(args.scalefns.xf).y(args.scalefns.yf).interpolate(args.interpolate);var flat_line=d3.svg.line().x(args.scalefns.xf).y(function(){return args.scales.Y(data_median);}).interpolate(args.interpolate);var legend='';var this_data;for(var i=args.data.length-1;i>=0;i--){this_data=args.data[i];var line_id=i+1;if(args.custom_line_color_map.length>0){line_id=args.custom_line_color_map[i];} -if(args.show_confidence_band){svg.append('path').attr('class','confidence-band').attr('d',confidence_area(args.data[i]));} -var $area=$(args.target).find('svg path.area'+(line_id)+'-color');if(args.area&&!args.use_data_y_min&&!args.y_axis_negative&&args.data.length<=1){if($area.length>0){d3.selectAll($(args.target).find('svg path.area'+(line_id)+'-color')).transition().duration(function(){return(args.transition_on_update)?1000:0;}).attr('d',area(args.data[i]));} -else{svg.append('path').attr('class','main-area '+'area'+(line_id)+'-color').attr('d',area(args.data[i]));}}else if($area.length>0){$area.remove();} -if($(args.target).find('svg path.line'+(line_id)+'-color').length>0){d3.selectAll($(args.target).find('svg path.line'+(line_id)+'-color')).transition().duration(function(){return(args.transition_on_update)?1000:0;}).attr('d',line(args.data[i]));} -else{if(args.animate_on_load){data_median=d3.median(args.data[i],function(d){return d[args.y_accessor];}) -svg.append('path').attr('class','main-line '+'line'+(line_id)+'-color').attr('d',flat_line(args.data[i])).transition().duration(1000).attr('d',line(args.data[i]));} -else{svg.append('path').attr('class','main-line '+'line'+(line_id)+'-color').attr('d',line(args.data[i]));}} -if(args.legend){legend="— " -+args.legend[i]+"  "+legend;}} -if(args.legend){$(args.legend_target).html(legend);} -return this;} -this.markers=function(){markers(args);return this;};this.rollover=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));var g;$svg.find('.transparent-rollover-rect').remove();$svg.find('.voronoi').remove();$svg.find('.active_datapoint').remove();$svg.find('.line_rollover_circle').remove();svg.append('text').attr('class','active_datapoint').classed('active-datapoint-small',args.use_small_class).attr('xml:space','preserve').attr('x',args.width-args.right).attr('y',args.top/2).attr('text-anchor','end');svg.append('circle').classed('line_rollover_circle',true).attr('cx',0).attr('cy',0).attr('r',0);var line_id=1;for(var i=0;i0){args.data[i][j]['line_id']=args.custom_line_color_map[i];} -else{args.data[i][j]['line_id']=line_id;}} -line_id++;} -if(args.data.length>1){var voronoi=d3.geom.voronoi().x(function(d){return args.scales.X(d[args.x_accessor]).toFixed(2);}).y(function(d){return args.scales.Y(d[args.y_accessor]).toFixed(2);}).clipExtent([[args.buffer,args.buffer],[args.width-args.buffer,args.height-args.buffer]]);var g=svg.append('g').attr('class','voronoi') -var data_nested=d3.nest().key(function(d){return args.scales.X(d[args.x_accessor])+"," -+args.scales.Y(d[args.y_accessor]);}).rollup(function(v){return v[0];}).entries(d3.merge(args.data.map(function(d){return d;}))).map(function(d){return d.values;});g.selectAll('path').data(voronoi(data_nested)).enter().append('path').attr("d",function(d){return"M"+d.join("L")+"Z";}).datum(function(d){return d.point;}).attr('class',function(d){if(args.linked){var v=d[args.x_accessor];var formatter=d3.time.format('%Y-%m-%d');var id=(typeof v==='number')?i:formatter(v);return'line'+d['line_id']+'-color '+'roll_'+id;} -else{return'line'+d['line_id']+'-color';}}).on('mouseover',this.rolloverOn(args)).on('mouseout',this.rolloverOff(args));} -else{var line_id=1;if(args.custom_line_color_map.length>0){line_id=args.custom_line_color_map[0];} -var g=svg.append('g').attr('class','transparent-rollover-rect') -var xf=args.data[0].map(args.scalefns.xf);g.selectAll('.rollover-rects').data(args.data[0]).enter().append('rect').attr('class',function(d,i){if(args.linked){var v=d[args.x_accessor];var formatter=d3.time.format('%Y-%m-%d');var id=(typeof v==='number')?i:formatter(v);return'line'+line_id+'-color '+'roll_'+id;} -else{return'line'+line_id+'-color';}}).attr('x',function(d,i){if(i==0){return xf[i].toFixed(2);}else{return((xf[i-1]+xf[i])/2).toFixed(2);}}).attr('y',function(d,i){return(args.data.length>1)?args.scalefns.yf(d)-6:args.top;}).attr('width',function(d,i){if(i==0){return((xf[i+1]-xf[i])/2).toFixed(2);} -else if(i==xf.length-1){return((xf[i]-xf[i-1])/2).toFixed(2);} -else{return((xf[i+1]-xf[i-1])/2).toFixed(2);}}).attr('height',function(d,i){return(args.data.length>1)?12:args.height-args.bottom-args.top-args.buffer;}).attr('opacity',0).on('mouseover',this.rolloverOn(args)).on('mouseout',this.rolloverOff(args));} -return this;} -this.rolloverOn=function(args){var svg=d3.select($(args.target).find('svg').get(0));var x_formatter=d3.time.format('%Y-%m-%d');return function(d,i){svg.selectAll('circle.line_rollover_circle').attr('class',"").attr('class','area'+d['line_id']+'-color').classed('line_rollover_circle',true).attr('cx',function(){return args.scales.X(d[args.x_accessor]).toFixed(2);}).attr('cy',function(){return args.scales.Y(d[args.y_accessor]).toFixed(2);}).attr('r',args.point_size).style('opacity',1);if(args.linked&&!globals.link){globals.link=true;var v=d[args.x_accessor];var formatter=d3.time.format('%Y-%m-%d');var id=(typeof v==='number')?i:formatter(v);d3.selectAll('.line'+d['line_id']+'-color.roll_'+id).each(function(d,i){d3.select(this).on('mouseover')(d,i);})} -svg.selectAll('text').filter(function(g,j){return d==g;}).attr('opacity',0.3);var fmt=d3.time.format('%b %e, %Y');if(args.format=='count'){var num=function(d_){var is_float=d_%1!=0;var n=d3.format("0,000");d_=is_float?d3.round(d_,args.decimals):d_;return n(d_);}} -else{var num=function(d_){var fmt_string=(args.decimals?'.'+args.decimals:'')+'%';var n=d3.format(fmt_string);return n(d_);}} -if(args.show_rollover_text){svg.select('.active_datapoint').text(function(){if(args.time_series){var dd=new Date(+d[args.x_accessor]);dd.setDate(dd.getDate());return fmt(dd)+' '+args.yax_units -+num(d[args.y_accessor]);} -else{return args.x_accessor+': '+d[args.x_accessor] -+', '+args.y_accessor+': '+args.yax_units -+num(d[args.y_accessor]);}});} -if(args.rollover_callback){args.rollover_callback(d,i);}}} -this.rolloverOff=function(args){var svg=d3.select($(args.target).find('svg').get(0));return function(d,i){if(args.linked&&globals.link){globals.link=false;var v=d[args.x_accessor];var formatter=d3.time.format('%Y-%m-%d');var id=(typeof v==='number')?i:formatter(v);d3.selectAll('.roll_'+id).each(function(d,i){d3.select(this).on('mouseout')(d);});} -svg.selectAll('circle.line_rollover_circle').style('opacity',0);svg.select('.active_datapoint').text('');if(args.rollout_callback){args.rollout_callback(d,i);}}} -this.init(args);return this;} -charts.histogram=function(args){'use strict';this.args=args;this.init=function(args){raw_data_transformation(args);process_histogram(args);init(args);x_axis(args);y_axis(args);return this;} -this.mainPlot=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));var g;$svg.find('.histogram').remove();var g=svg.append("g").attr("class","histogram");var bar=g.selectAll(".bar").data(args.data[0]).enter().append("g").attr("class","bar").attr("transform",function(d){return"translate("+args.scales.X(d[args.x_accessor]).toFixed(2) -+","+args.scales.Y(d[args.y_accessor]).toFixed(2)+")";});bar.append("rect").attr("x",1).attr("width",function(d,i){return(args.scalefns.xf(args.data[0][1]) --args.scalefns.xf(args.data[0][0]) --args.bar_margin).toFixed(2);}).attr("height",function(d){if(d[args.y_accessor]==0) -return 0;return(args.height-args.bottom-args.buffer --args.scales.Y(d[args.y_accessor])).toFixed(2);});return this;} -this.markers=function(){markers(args);return this;};this.rollover=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));var g;$svg.find('.transparent-rollover-rect').remove();$svg.find('.active_datapoint').remove();svg.append('text').attr('class','active_datapoint').attr('xml:space','preserve').attr('x',args.width-args.right).attr('y',args.top/2).attr('text-anchor','end');var g=svg.append('g').attr('class','transparent-rollover-rect') -var bar=g.selectAll(".bar").data(args.data[0]).enter().append("g").attr("class","rollover-rects").attr("transform",function(d){return"translate("+(args.scales.X(d[args.x_accessor]))+","+0+")";});bar.append("rect").attr("x",1).attr("y",0).attr("width",function(d,i){if(i!=args.data[0].length-1){return(args.scalefns.xf(args.data[0][i+1]) --args.scalefns.xf(d)).toFixed(2);} -else{return(args.scalefns.xf(args.data[0][1]) --args.scalefns.xf(args.data[0][0])).toFixed(2);}}).attr("height",function(d){return args.height;}).attr('opacity',0).on('mouseover',this.rolloverOn(args)).on('mouseout',this.rolloverOff(args));} -this.rolloverOn=function(args){var svg=d3.select($(args.target).find('svg').get(0));var x_formatter=d3.time.format('%Y-%m-%d');return function(d,i){svg.selectAll('text').filter(function(g,j){return d==g;}).attr('opacity',0.3);var fmt=d3.time.format('%b %e, %Y');if(args.format=='count'){var num=function(d_){var is_float=d_%1!=0;var n=d3.format("0,000");d_=is_float?d3.round(d_,args.decimals):d_;return n(d_);}} -else{var num=function(d_){var fmt_string=(args.decimals?'.'+args.decimals:'')+'%';var n=d3.format(fmt_string);return n(d_);}} -d3.selectAll($(args.target).find(' svg .bar :eq('+i+')')).classed('active',true);if(args.show_rollover_text){svg.select('.active_datapoint').text(function(){if(args.time_series){var dd=new Date(+d[args.x_accessor]);dd.setDate(dd.getDate());return fmt(dd)+' '+args.yax_units -+num(d[args.y_accessor]);} -else{return args.x_accessor+': '+num(d[args.x_accessor]) -+', '+args.y_accessor+': '+args.yax_units -+num(d[args.y_accessor]);}});} -if(args.rollover_callback){args.rollover_callback(d,i);}}} -this.rolloverOff=function(args){var svg=d3.select($(args.target).find('svg').get(0));return function(d,i){d3.selectAll($(args.target).find('svg .bar :eq('+i+')')).classed('active',false);svg.select('.active_datapoint').text('');if(args.rollout_callback){args.rollout_callback(d,i);}}} -this.init(args);return this;} -charts.point=function(args){'use strict';this.args=args;this.init=function(args){raw_data_transformation(args);process_point(args);init(args);x_axis(args);y_axis(args);return this;} -this.markers=function(){markers(args);if(args.least_squares){add_ls(args);} -return this} -this.mainPlot=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));var g;$svg.find('.points').remove();g=svg.append('g').classed('points',true);var pts=g.selectAll('circle').data(args.data[0]).enter().append('svg:circle').attr('class',function(d,i){return'path-'+i;}).attr('cx',args.scalefns.xf).attr('cy',args.scalefns.yf);if(args.color_accessor!=null){pts.attr('fill',args.scalefns.color);pts.attr('stroke',args.scalefns.color);} -else{pts.classed('points-mono',true);} -if(args.size_accessor!=null){pts.attr('r',args.scalefns.size);} -else{pts.attr('r',args.point_size);} -return this;} -this.rollover=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));$svg.find('.voronoi').remove();$svg.find('.active_datapoint').remove();svg.append('text').attr('class','active_datapoint').attr('xml:space','preserve').attr('x',args.width-args.right).attr('y',args.top/2).attr('text-anchor','end');var voronoi=d3.geom.voronoi().x(args.scalefns.xf).y(args.scalefns.yf).clipExtent([[args.buffer,args.buffer],[args.width-args.buffer,args.height-args.buffer]]);var paths=svg.append('g').attr('class','voronoi');paths.selectAll('path').data(voronoi(args.data[0])).enter().append('path').attr('d',function(d){if(d==undefined)return;return'M'+d.join(',')+'Z';}).attr('class',function(d,i){return'path-'+i;}).style('fill-opacity',0).on('mouseover',this.rolloverOn(args)).on('mouseout',this.rolloverOff(args));return this;} -this.rolloverOn=function(args){var svg=d3.select($(args.target).find('svg').get(0));return function(d,i){svg.selectAll('.points circle').classed('selected',false);var pts=svg.selectAll('.points circle.path-'+i).classed('selected',true);if(args.size_accessor){pts.attr('r',function(di){return args.scalefns.size(di)+1});}else{pts.attr('r',args.point_size);} -if(args.linked&&!globals.link){globals.link=true;d3.selectAll('.voronoi .path-'+i).each(function(){d3.select(this).on('mouseover')(d,i);})} -var fmt=d3.time.format('%b %e, %Y');if(args.format=='count'){var num=function(d_){var is_float=d_%1!=0;var n=d3.format("0,000");d_=is_float?d3.round(d_,args.decimals):d_;return n(d_);}} -else{var num=function(d_){var fmt_string=(args.decimals?'.'+args.decimals:'')+'%';var n=d3.format(fmt_string);return n(d_);}} -if(args.show_rollover_text){svg.select('.active_datapoint').text(function(){if(args.time_series){var dd=new Date(+d['point'][args.x_accessor]);dd.setDate(dd.getDate());return fmt(dd)+' '+args.yax_units -+num(d['point'][args.y_accessor]);} -else{return args.x_accessor+': '+num(d['point'][args.x_accessor]) -+', '+args.y_accessor+': '+args.yax_units -+num(d['point'][args.y_accessor]);}});} -if(args.rollover_callback){args.rollover_callback(d,i);}}} -this.rolloverOff=function(args){var svg=d3.select($(args.target).find('svg').get(0));return function(d,i){if(args.linked&&globals.link){globals.link=false;d3.selectAll('.voronoi .path-'+i).each(function(){d3.select(this).on('mouseout')(d,i);})} -var pts=svg.selectAll('.points circle').classed('unselected',false).classed('selected',false);if(args.size_accessor){pts.attr('r',args.scalefns.size);} -else{pts.attr('r',args.point_size);} -svg.select('.active_datapoint').text('');if(args.rollout_callback){args.rollout_callback(d,i);}}} -this.update=function(args){return this;} -this.init(args);return this;} -charts.bar=function(args){'use strict';this.args=args;this.init=function(args){raw_data_transformation(args);process_categorical_variables(args);init(args);x_axis(args);y_axis_categorical(args);return this;} -this.mainPlot=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));var g;$svg.find('.barplot').remove();var data=args.data[0];var g=svg.append('g').classed('barplot',true);var appropriate_height=args.scales.Y.rangeBand()/1.5;g.selectAll('.bar').data(data).enter().append('rect').classed('bar',true).attr('x',args.scales.X(0)).attr('y',function(d){return args.scalefns.yf(d)+appropriate_height/2;}).attr('height',appropriate_height).attr('width',function(d){return args.scalefns.xf(d)-args.scales.X(0)});if(args.predictor_accessor){var pp=args.predictor_proportion;var pp0=pp-1;g.selectAll('.prediction').data(data).enter().append("rect").attr('class','bar-prediction').attr('x',args.scales.X(0)).attr('y',function(d){return args.scalefns.yf(d)+pp0*appropriate_height/(pp*2)+appropriate_height/2;}).attr('height',appropriate_height/pp).attr('width',function(d){return args.scales.X(d[args.predictor_accessor])-args.scales.X(0);});} -if(args.baseline_accessor){g.selectAll('.baseline').data(data).enter().append("line").attr('class','bar-baseline').attr('x1',function(d){return args.scales.X(d[args.baseline_accessor])}).attr('x2',function(d){return args.scales.X(d[args.baseline_accessor])}).attr('y1',function(d){return args.scalefns.yf(d)+appropriate_height/2-appropriate_height/pp+appropriate_height/2;}).attr('y2',function(d){return args.scalefns.yf(d)+appropriate_height/2+appropriate_height/pp+appropriate_height/2;});} -return this;} -this.markers=function(){markers(args);return this;};this.rollover=function(){var svg=d3.select($(args.target).find('svg').get(0));var $svg=$($(args.target).find('svg').get(0));var g;$svg.find('.transparent-rollover-rect').remove();$svg.find('.active_datapoint').remove();svg.append('text').attr('class','active_datapoint').attr('xml:space','preserve').attr('x',args.width-args.right).attr('y',args.top/2).attr('dy','.35em').attr('text-anchor','end');var g=svg.append('g').attr('class','transparent-rollover-rect') -var bar=g.selectAll(".bar").data(args.data[0]).enter().append("rect").attr("x",args.scales.X(0)).attr("y",args.scalefns.yf).attr('width',args.width).attr('height',args.scales.Y.rangeBand()+2).attr('opacity',0).on('mouseover',this.rolloverOn(args)).on('mouseout',this.rolloverOff(args));} -this.rolloverOn=function(args){var svg=d3.select($(args.target).find('svg').get(0));var x_formatter=d3.time.format('%Y-%m-%d');return function(d,i){svg.selectAll('text').filter(function(g,j){return d==g;}).attr('opacity',0.3);var fmt=d3.time.format('%b %e, %Y');if(args.format=='count'){var num=function(d_){var is_float=d_%1!=0;var n=d3.format("0,000");d_=is_float?d3.round(d_,args.decimals):d_;return n(d_);}} -else{var num=function(d_){var fmt_string=(args.decimals?'.'+args.decimals:'')+'%';var n=d3.format(fmt_string);return n(d_);}} -d3.selectAll($(args.target+' svg g.barplot .bar:eq('+i+')')).classed('active',true);if(args.show_rollover_text){svg.select('.active_datapoint').text(function(){if(args.time_series){var dd=new Date(+d[args.x_accessor]);dd.setDate(dd.getDate());return fmt(dd)+' '+args.yax_units -+num(d[args.y_accessor]);} -else{return d[args.y_accessor]+': '+num(d[args.x_accessor]);}});} -if(args.rollover_callback){args.rollover_callback(d,i);}}} -this.rolloverOff=function(args){var svg=d3.select($(args.target).find('svg').get(0));return function(d,i){d3.selectAll($(args.target).find('svg g.barplot .bar:eq('+i+')')).classed('active',false);svg.select('.active_datapoint').text('');if(args.rollout_callback){args.rollout_callback(d,i);}}} -this.init(args);return this;} -function data_table(args){'use strict';this.args=args;this.args.standard_col={width:150,font_size:12,font_weight:'normal'};this.args.columns=[];this.formatting_options=[['color','color'],['font-weight','font_weight'],['font-style','font_style'],['font-size','font_size']];this._strip_punctuation=function(s){var punctuationless=s.replace(/[^a-zA-Z0-9 _]+/g,'');var finalString=punctuationless.replace(/ +?/g,"");return finalString;} -this._format_element=function(element,value,args){this.formatting_options.forEach(function(fo){var attr=fo[0];var key=fo[1];if(args[key])element.style(attr,typeof args[key]=='string'||typeof args[key]=='number'?args[key]:args[key](value));});} -this._add_column=function(_args,arg_type){var standard_column=this.args.standard_col;var args=merge_with_defaults(clone(_args),clone(standard_column));args.type=arg_type;this.args.columns.push(args);} -this.target=function(){var target=arguments[0];this.args.target=target;return this;} -this.title=function(){this._add_column(arguments[0],'title');return this;} -this.text=function(){this._add_column(arguments[0],'text');return this;} -this.bullet=function(){return this;} -this.sparkline=function(){return this;} -this.number=function(){this._add_column(arguments[0],'number');return this;} -this.display=function(){var this_column;var args=this.args;chart_title(args);var target=args.target;var table=d3.select(target).append('table').classed('data-table',true);var colgroup=table.append('colgroup');var thead=table.append('thead');var tbody=table.append('tbody');var this_column,this_title;var tr,th,td_accessor,td_type,td_value,th_text,td_text,td;var col;tr=thead.append('tr');for(var h=0;h=0&&u<=1){return Math.pow(1-Math.pow(u,w),w)}else{return 0}} -function _bisquare_weight(u){return _pow_weight(u,2);} -function _tricube_weight(u){return _pow_weight(u,3);} -function _neighborhood_width(x0,xis){return Array.max(xis.map(function(xi){return Math.abs(x0-xi)}))} -function _manhattan(x1,x2){return Math.abs(x1-x2)} -function _weighted_means(wxy){var wsum=d3.sum(wxy.map(function(wxyi){return wxyi.w}));return{xbar:d3.sum(wxy.map(function(wxyi){return wxyi.w*wxyi.x}))/wsum,ybar:d3.sum(wxy.map(function(wxyi){return wxyi.w*wxyi.y}))/wsum}} -function _weighted_beta(wxy,xbar,ybar){var num=d3.sum(wxy.map(function(wxyi){return Math.pow(wxyi.w,2)*(wxyi.x-xbar)*(wxyi.y-ybar)})) -var denom=d3.sum(wxy.map(function(wxyi){return Math.pow(wxyi.w,2)*(Math.pow(wxyi.x-xbar),2)})) -return num/denom;} -function _weighted_least_squares(wxy){var ybar,xbar,beta_i,x0;var _wm=_weighted_means(wxy);xbar=_wm.xbar;ybar=_wm.ybar;var beta=_weighted_beta(wxy,xbar,ybar) -return{beta:beta,xbar:xbar,ybar:ybar,x0:ybar-beta*xbar} -return num/denom} -function _calculate_lowess_fit(x,y,alpha,inc,residuals){var k=Math.floor(x.length*alpha);var sorted_x=x.slice();sorted_x.sort(function(a,b){if(ab){return 1} -return 0});var x_max=d3.quantile(sorted_x,.98);var x_min=d3.quantile(sorted_x,.02);var xy=d3.zip(x,y,residuals).sort();var size=Math.abs(x_max-x_min)/inc;var smallest=x_min -var largest=x_max -var x_proto=d3.range(smallest,largest,size);var xi_neighbors;var x_i,beta_i,x0_i,delta_i,xbar,ybar;var y_proto=[];for(var i=0;i0;} -function has_too_many_zeros(data,accessor,zero_count){return number_of_values(data,accessor,0)>=zero_count;} -function clone(obj){if(null==obj||"object"!=typeof obj)return obj;if(obj instanceof Date){var copy=new Date();copy.setTime(obj.getTime());return copy;} -if(obj instanceof Array){var copy=[];for(var i=0,len=obj.length;i':"";$(t.target).prepend('

'+t.title+a+"

"),t.description&&(r=$(t.target).find("h2.chart_title"),r.popover({html:!0,animation:!1,content:t.description,trigger:"hover",placement:"top",container:r}))}t.error&&v(t)}}function e(t){for(var e=d3.select($(t.target).find("svg").get(0)),r="point"==t.chart_type?t.buffer/2:2*t.buffer/3,a=[],n=0;n0})),d.length>0){var u=d3.extent(d,function(e){return e[t.y_accessor]});l?(n=Math.min(u[0],n),o=Math.max(u[1],o)):(n=u[0],o=u[1],l=!0)}}n>=0&&!t.min_y&&!t.min_y_from_data&&(n=0),n=t.min_y?t.min_y:n,o=t.max_y?t.max_y:o,"log"!=t.y_scale_type&&(n>=0?t.y_axis_negative=!1:(n-=o*(t.inflator-1),t.y_axis_negative=!0)),o*=t.inflator,!t.min_y&&t.min_y_from_data&&(n/=t.inflator),"log"==t.y_scale_type?("histogram"==t.chart_type?n=.2:0>=n&&(n=1),t.scales.Y=d3.scale.log().domain([n,o]).range([t.height-t.bottom-t.buffer,t.top]).clamp(!0)):t.scales.Y=d3.scale.linear().domain([n,o]).range([t.height-t.bottom-t.buffer,t.top]),t.scales.Y_axis=d3.scale.linear().domain([n,o]).range([t.height-t.bottom-t.buffer,t.top]);var f;if(f="count"==t.format?function(e){if(1>e)return t.yax_units+d3.round(e,t.decimals);var r=d3.formatPrefix(e);return t.yax_units+r.scale(e)+r.symbol}:function(t){var e=d3.format("%p");return e(t)},i.find(".y-axis").remove(),!t.y_axis)return this;a=s.append("g").classed("y-axis",!0).classed("y-axis-small",t.use_small_class),t.y_label&&a.append("text").attr("class","label").attr("x",function(){return-1*(t.top+t.buffer+(t.height-t.bottom-t.buffer-(t.top+t.buffer))/2)}).attr("y",function(){return t.left/2}).attr("dy","0.4em").attr("text-anchor","middle").text(function(){return t.y_label}).attr("transform",function(){return"rotate(-90)"});var p=t.scales.Y.ticks(t.yax_count);"log"==t.y_scale_type&&(p=p.filter(function(t){return Math.abs(r(t))%1<1e-6||Math.abs(r(t))%1>1-1e-6}));var h=t.scales.Y.ticks(t.yax_count).length,g=!0;$.each(t.data,function(e,r){$.each(r,function(e,r){return r[t.y_accessor]%1!==0?(g=!1,!1):void 0})}),g&&h>o&&"count"==t.format&&(p=p.filter(function(t){return t%1===0}));var m=p.length-1;return t.x_extended_ticks||t.y_extended_ticks||a.append("line").attr("x1",t.left).attr("x2",t.left).attr("y1",t.scales.Y(p[0]).toFixed(2)).attr("y2",t.scales.Y(p[m]).toFixed(2)),a.selectAll(".yax-ticks").data(p).enter().append("line").classed("extended-y-ticks",t.y_extended_ticks).attr("x1",t.left).attr("x2",function(){return t.y_extended_ticks?t.width-t.right:t.left-t.yax_tick_length}).attr("y1",function(e){return t.scales.Y(e).toFixed(2)}).attr("y2",function(e){return t.scales.Y(e).toFixed(2)}),a.selectAll(".yax-labels").data(p).enter().append("text").attr("x",t.left-3*t.yax_tick_length/2).attr("dx",-3).attr("y",function(e){return t.scales.Y(e).toFixed(2)}).attr("dy",".35em").attr("text-anchor","end").text(function(t){var e=f(t);return e}),t.y_rug&&e(t),this}function a(t){var e=t.height;"bar"==t.chart_type&&null==e,t.scales.Y=d3.scale.ordinal().domain(t.categorical_variables).rangeRoundBands([t.height-t.bottom-t.buffer,t.top],t.padding_percentage,t.outer_padding_percentage),t.scalefns.yf=function(e){return t.scales.Y(e[t.y_accessor])};var r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".y-axis").remove();var n=r.append("g").classed("y-axis",!0).classed("y-axis-small",t.use_small_class);return t.y_axis?(n.selectAll("text").data(t.categorical_variables).enter().append("svg:text").attr("x",t.left).attr("y",function(e){return t.scales.Y(e)+t.scales.Y.rangeBand()/2+t.buffer*t.outer_padding_percentage}).attr("dy",".35em").attr("text-anchor","end").text(String),this):this}function n(t){for(var e="point"==t.chart_type?t.buffer/2:t.buffer,r=d3.select($(t.target).find("svg").get(0)),a=[],n=0;n10?d3.scale.category20():d3.scale.category10(),t.scales.color.domain(h)),t.scalefns.color=function(e){return t.scales.color(e[t.color_accessor])}),null!=t.size_accessor&&(null==t.size_domain?(i=d3.min(t.data[0],function(e){return e[t.size_accessor]}),l=d3.max(t.data[0],function(e){return e[t.size_accessor]}),p=[i,l]):p=t.size_domain,u=null==t.size_range?[1,5]:t.size_range,t.scales.size=d3.scale.linear().domain(p).range(u).clamp(!0),t.scalefns.size=function(e){return t.scales.size(e[t.size_accessor])})}var g;if("line"==t.chart_type)for(var m=0;ma||!a)&&(a=t.data[m][g][t.x_accessor]);else"point"==t.chart_type?(a=d3.max(t.data[0],function(e){return e[t.x_accessor]}),r=d3.min(t.data[0],function(e){return e[t.x_accessor]})):"histogram"==t.chart_type?(r=d3.min(t.data[0],function(e){return e[t.x_accessor]}),a=d3.max(t.data[0],function(e){return e[t.x_accessor]}),t.xax_format=function(e){if(1>e)return t.yax_units+d3.round(e,t.decimals);var r=d3.formatPrefix(e);return t.xax_units+r.scale(e)+r.symbol}):"bar"==t.chart_type&&(r=0,a=d3.max(t.data[0],function(e){var r=[];return r.push(e[t.x_accessor]),null!=t.baseline_accessor&&r.push(e[t.baseline_accessor]),null!=t.predictor_accessor&&r.push(e[t.predictor_accessor]),Math.max.apply(null,r)}),t.xax_format=function(e){if(1>e)return t.yax_units+d3.round(e,t.decimals);var r=d3.formatPrefix(e);return t.xax_units+r.scale(e)+r.symbol});r=t.min_x?t.min_x:r,a=t.max_x?t.max_x:a,t.x_axis_negative=!1,t.time_series||0>r&&(r-=a*(t.inflator-1),t.x_axis_negative=!0);var _;if(_="bar"==t.chart_type?5*t.buffer:0,t.scales.X=t.time_series?d3.time.scale():d3.scale.linear(),t.scales.X.domain([r,a]).range([t.left+t.buffer,t.width-t.right-t.buffer-_]),s.find(".x-axis").remove(),!t.x_axis)return this;e=o.append("g").classed("x-axis",!0).classed("x-axis-small",t.use_small_class);var g=t.scales.X.ticks(t.xax_count).length-1;if(t.x_label&&e.append("text").attr("class","label").attr("x",function(){return t.left+t.buffer+(t.width-t.right-t.buffer-(t.left+t.buffer))/2}).attr("y",(t.height-t.bottom/2).toFixed(2)).attr("dy",".50em").attr("text-anchor","middle").text(function(){return t.x_label}),"bar"==t.chart_type||t.x_extended_ticks||t.y_extended_ticks||e.append("line").attr("x1",0==t.concise||0==t.xax_count?t.left+t.buffer:t.scales.X(t.scales.X.ticks(t.xax_count)[0]).toFixed(2)).attr("x2",0==t.concise||0==t.xax_count?t.width-t.right-t.buffer:t.scales.X(t.scales.X.ticks(t.xax_count)[g]).toFixed(2)).attr("y1",t.height-t.bottom).attr("y2",t.height-t.bottom),e.selectAll(".xax-ticks").data(t.scales.X.ticks(t.xax_count)).enter().append("line").attr("x1",function(e){return t.scales.X(e).toFixed(2)}).attr("x2",function(e){return t.scales.X(e).toFixed(2)}).attr("y1",t.height-t.bottom).attr("y2",function(){return t.x_extended_ticks?t.top:t.height-t.bottom+t.xax_tick_length}).attr("class",function(){return t.x_extended_ticks?"extended-x-ticks":void 0}),e.selectAll(".xax-labels").data(t.scales.X.ticks(t.xax_count)).enter().append("text").attr("x",function(e){return t.scales.X(e).toFixed(2)}).attr("y",(t.height-t.bottom+7*t.xax_tick_length/3).toFixed(2)).attr("dy",".50em").attr("text-anchor","middle").text(function(e){return t.xax_units+t.xax_format(e)}),t.time_series&&t.show_years){for(var r,a,m=0;ma||!a)&&(a=t.data[m][g][t.x_accessor]);var v=d3.time.years(r,a);if(0==v.length){var y=t.scales.X.ticks(t.xax_count)[0];v=[y]}e=e.append("g").classed("year-marker",!0).classed("year-marker-small",t.use_small_class),e.selectAll(".year_marker").data(v).enter().append("line").attr("x1",function(e){return t.scales.X(e).toFixed(2)}).attr("x2",function(e){return t.scales.X(e).toFixed(2)}).attr("y1",t.top).attr("y2",t.height-t.bottom);var x=d3.time.format("%Y");e.selectAll(".year_marker").data(v).enter().append("text").attr("x",function(e){return t.scales.X(e).toFixed(2)}).attr("y",(t.height-t.bottom+7*t.xax_tick_length/1.3).toFixed(2)).attr("dy",t.use_small_class?-3:0).attr("text-anchor","middle").text(function(t){return x(t)})}return t.x_rug&&n(t),this}function s(e){var r={target:null,title:null,description:null},e=arguments[0];e||(e={}),e=g(e,r),e.time_series="date"==$.type(e.data[0][0][e.x_accessor])?!0:!1;var a=e.width,n=e.height;"bar"==e.chart_type&&null==n&&(n=e.height=e.data[0].length*e.bar_height+e.top+e.bottom);var o=$(e.target).find("svg");(o.find(".main-line").length>0&&"line"!=e.chart_type||o.find(".points").length>0&&"point"!=e.chart_type||o.find(".histogram").length>0&&"histogram"!=e.chart_type||o.find(".barplot").length>0&&"bar"!=e.chart_type)&&$(e.target).empty(),""==$.trim($(e.target).html())&&d3.select(e.target).append("svg").classed("linked",e.linked).attr("width",a).attr("height",n);var o=d3.select(e.target).selectAll("svg");if(e.width!=Number(o.attr("width"))&&o.attr("width",e.width),e.height!=Number(o.attr("height"))&&o.attr("height",e.height),o.classed("missing",!1),o.selectAll(".missing-text").remove(),t(e),e.use_small_class=e.height-e.top-e.bottom-e.buffer<=e.small_height_threshold&&e.width-e.left-e.right-2*e.buffer<=e.small_width_threshold||e.small_text,e.data.length<$(e.target).find("svg .main-line").length)if(e.custom_line_color_map.length>0)for(var s=function(t){for(var e=new Array(t),r=0;rc;l--)$(e.target).find("svg .main-line.line"+l+"-color").remove();return this}function i(t){var e,r,a=d3.select($(t.target).find("svg").get(0));return t.markers&&($(t.target).find("svg .markers").remove(),e=a.append("g").attr("class","markers"),e.selectAll(".markers").data(t.markers.filter(function(e){return t.scales.X(e[t.x_accessor])>t.buffer+t.left&&t.scales.X(e[t.x_accessor])t.buffer+t.left&&t.scales.X(e[t.x_accessor])=c;c.setDate(c.getDate()+1)){var d={};c.setHours(0,0,0,0),Date.parse(c)==Date.parse(new Date(s))&&o.push(y.clone(t.data[r][0]));var u=null;$.each(t.data[r],function(t,e){return Date.parse(e.date)==Date.parse(new Date(c))?(u=e,!1):void 0}),u?o.push(u):(d[t.x_accessor]=new Date(c),d[t.y_accessor]=0,o.push(d)),Date.parse(c)==Date.parse(new Date(n[t.x_accessor]))&&o.push(n)}t.data[r]=o}return this}function d(t){var e,r=t.data[0];if(0==t.binned){if("object"==typeof r[0])e=r.map(function(e){return e[t.x_accessor]});else{if("number"!=typeof r[0])return void console.log("TypeError: expected an array of numbers, found "+typeof r[0]);e=r}var a=d3.layout.histogram();t.bins&&(a=a.bins(t.bins)),t.processed_data=a(e).map(function(t){return{x:t.x,y:t.y,dx:t.dx}})}else{t.processed_data=r.map(function(e){return{x:e[t.x_accessor],y:e[t.y_accessor]}});for(var n,o,s=0;s
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},r.prototype.init=function(e,r,a){this.enabled=!0,this.type=e,this.$element=t(r),this.options=this.getOptions(a),this.$viewport=this.options.viewport&&t(this.options.viewport.selector||this.options.viewport);for(var n=this.options.trigger.split(" "),o=n.length;o--;){var s=n[o];if("click"==s)this.$element.on("click."+this.type,this.options.selector,t.proxy(this.toggle,this));else if("manual"!=s){var i="hover"==s?"mouseenter":"focusin",l="hover"==s?"mouseleave":"focusout";this.$element.on(i+"."+this.type,this.options.selector,t.proxy(this.enter,this)),this.$element.on(l+"."+this.type,this.options.selector,t.proxy(this.leave,this))}}this.options.selector?this._options=t.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},r.prototype.getDefaults=function(){return r.DEFAULTS},r.prototype.getOptions=function(e){return e=t.extend({},this.getDefaults(),this.$element.data(),e),e.delay&&"number"==typeof e.delay&&(e.delay={show:e.delay,hide:e.delay}),e},r.prototype.getDelegateOptions=function(){var e={},r=this.getDefaults();return this._options&&t.each(this._options,function(t,a){r[t]!=a&&(e[t]=a)}),e},r.prototype.enter=function(e){var r=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return r&&r.$tip&&r.$tip.is(":visible")?void(r.hoverState="in"):(r||(r=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,r)),clearTimeout(r.timeout),r.hoverState="in",r.options.delay&&r.options.delay.show?void(r.timeout=setTimeout(function(){"in"==r.hoverState&&r.show()},r.options.delay.show)):r.show())},r.prototype.leave=function(e){var r=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return r||(r=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,r)),clearTimeout(r.timeout),r.hoverState="out",r.options.delay&&r.options.delay.hide?void(r.timeout=setTimeout(function(){"out"==r.hoverState&&r.hide()},r.options.delay.hide)):r.hide()},r.prototype.show=function(){var e=t.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var a=t.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!a)return;var n=this,o=this.tip(),s=this.getUID(this.type);this.setContent(),o.attr("id",s),this.$element.attr("aria-describedby",s),this.options.animation&&o.addClass("fade");var i="function"==typeof this.options.placement?this.options.placement.call(this,o[0],this.$element[0]):this.options.placement,l=/\s?auto?\s?/i,c=l.test(i);c&&(i=i.replace(l,"")||"top"),o.detach().css({top:0,left:0,display:"block"}).addClass(i).data("bs."+this.type,this),this.options.container?o.appendTo(this.options.container):o.insertAfter(this.$element);var d=this.getPosition(),u=o[0].offsetWidth,f=o[0].offsetHeight;if(c){var p=i,h=this.options.container?t(this.options.container):this.$element.parent(),g=this.getPosition(h);i="bottom"==i&&d.bottom+f>g.bottom?"top":"top"==i&&d.top-fg.width?"left":"left"==i&&d.left-us.top+s.height&&(n.top=s.top+s.height-l)}else{var c=e.left-o,d=e.left+o+r;cs.width&&(n.left=s.left+s.width-d)}return n},r.prototype.getTitle=function(){var t,e=this.$element,r=this.options;return t=e.attr("data-original-title")||("function"==typeof r.title?r.title.call(e[0]):r.title)},r.prototype.getUID=function(t){do t+=~~(1e6*Math.random());while(document.getElementById(t));return t},r.prototype.tip=function(){return this.$tip=this.$tip||t(this.options.template)},r.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},r.prototype.enable=function(){this.enabled=!0},r.prototype.disable=function(){this.enabled=!1},r.prototype.toggleEnabled=function(){this.enabled=!this.enabled},r.prototype.toggle=function(e){var r=this;e&&(r=t(e.currentTarget).data("bs."+this.type),r||(r=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,r))),r.tip().hasClass("in")?r.leave(r):r.enter(r)},r.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type)})};var a=t.fn.tooltip;t.fn.tooltip=e,t.fn.tooltip.Constructor=r,t.fn.tooltip.noConflict=function(){return t.fn.tooltip=a,this}}(jQuery),+function(t){function e(e){return this.each(function(){var a=t(this),n=a.data("bs.popover"),o="object"==typeof e&&e,s=o&&o.selector;(n||"destroy"!=e)&&(s?(n||a.data("bs.popover",n={}),n[s]||(n[s]=new r(this,o))):n||a.data("bs.popover",n=new r(this,o)),"string"==typeof e&&n[e]())})}if("function"==typeof t().popover)return!0;var r=function(t,e){this.init("popover",t,e)};if(!t.fn.tooltip)throw new Error("Popover requires tooltip.js");r.VERSION="3.3.1",r.DEFAULTS=t.extend({},t.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),r.prototype=t.extend({},t.fn.tooltip.Constructor.prototype),r.prototype.constructor=r,r.prototype.getDefaults=function(){return r.DEFAULTS},r.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),r=this.getContent();t.find(".popover-title")[this.options.html?"html":"text"](e),t.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof r?"html":"append":"text"](r),t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},r.prototype.hasContent=function(){return this.getTitle()||this.getContent()},r.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},r.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},r.prototype.tip=function(){return this.$tip||(this.$tip=t(this.options.template)),this.$tip};var a=t.fn.popover;t.fn.popover=e,t.fn.popover.Constructor=r,t.fn.popover.noConflict=function(){return t.fn.popover=a,this}}(jQuery),"undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(t){var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(t){function e(e){e&&3===e.which||(t(n).remove(),t(o).each(function(){var a=t(this),n=r(a),o={relatedTarget:this};n.hasClass("open")&&(n.trigger(e=t.Event("hide.bs.dropdown",o)),e.isDefaultPrevented()||(a.attr("aria-expanded","false"),n.removeClass("open").trigger("hidden.bs.dropdown",o)))}))}function r(e){var r=e.attr("data-target");r||(r=e.attr("href"),r=r&&/#[A-Za-z]/.test(r)&&r.replace(/.*(?=#[^\s]*$)/,""));var a=r&&t(r);return a&&a.length?a:e.parent()}function a(e){return this.each(function(){var r=t(this),a=r.data("bs.dropdown");a||r.data("bs.dropdown",a=new s(this)),"string"==typeof e&&a[e].call(r)})}if("function"==typeof t().dropdown)return!0;var n=".dropdown-backdrop",o='[data-toggle="dropdown"]',s=function(e){t(e).on("click.bs.dropdown",this.toggle)};s.VERSION="3.3.1",s.prototype.toggle=function(a){var n=t(this);if(!n.is(".disabled, :disabled")){var o=r(n),s=o.hasClass("open");if(e(),!s){"ontouchstart"in document.documentElement&&!o.closest(".navbar-nav").length&&t('");for(var c in this.feature_set){r=this.feature_set[c],$(this.target+" div.segments").append('
");for(var i=0;i'+r[i]+"");$("."+this._strip_punctuation(c)+"-btns .dropdown-menu li a").on("click",function(){var t,e=$(this).data("key"),r=$(this).data("feature");return $("."+r+"-btns button.btn span.title").html(e),s.hasOwnProperty(r)?(t=s[r],o[t](e)):n(r,e),!1})}return this},this},x.line=function(t){return this.args=t,this.init=function(t){return l(t),c(t),s(t),o(t),r(t),this},this.mainPlot=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=0,n=d3.svg.area().x(t.scalefns.xf).y0(t.scales.Y.range()[0]).y1(t.scalefns.yf).interpolate(t.interpolate);if(t.show_confidence_band)var e=d3.svg.area().x(t.scalefns.xf).y0(function(e){var r=t.show_confidence_band[0];return t.scales.Y(e[r])}).y1(function(e){var r=t.show_confidence_band[1];return t.scales.Y(e[r])}).interpolate(t.interpolate);for(var o,s=d3.svg.line().x(t.scalefns.xf).y(t.scalefns.yf).interpolate(t.interpolate),i=d3.svg.line().x(t.scalefns.xf).y(function(){return t.scales.Y(a)}).interpolate(t.interpolate),l="",c=t.data.length-1;c>=0;c--){o=t.data[c];var d=c+1;t.custom_line_color_map.length>0&&(d=t.custom_line_color_map[c]),t.show_confidence_band&&r.append("path").attr("class","confidence-band").attr("d",e(t.data[c]));var u=$(t.target).find("svg path.area"+d+"-color");t.area&&!t.use_data_y_min&&!t.y_axis_negative&&t.data.length<=1?u.length>0?($(r.node()).find(".y-axis").after(u.detach()),d3.select(u.get(0)).transition().duration(function(){return t.transition_on_update?1e3:0}).attr("d",n(t.data[c]))):r.append("path").attr("class","main-area area"+d+"-color").attr("d",n(t.data[c])):u.length>0&&u.remove();var f=$(t.target).find("svg path.main-line.line"+d+"-color").first();f.length>0?($(r.node()).find(".y-axis").after(f.detach()),d3.select(f.get(0)).transition().duration(function(){return t.transition_on_update?1e3:0}).attr("d",s(t.data[c]))):t.animate_on_load?(a=d3.median(t.data[c],function(e){return e[t.y_accessor]}),r.append("path").attr("class","main-line line"+d+"-color").attr("d",i(t.data[c])).transition().duration(1e3).attr("d",s(t.data[c]))):r.append("path").attr("class","main-line line"+d+"-color").attr("d",s(t.data[c])),t.legend&&(l="— "+t.legend[c]+"  "+l)}return t.legend&&$(t.legend_target).html(l),this},this.markers=function(){return i(t),this},this.rollover=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".transparent-rollover-rect").remove(),a.find(".voronoi").remove(),a.find(".active_datapoint").remove(),a.find(".line_rollover_circle").remove(),r.append("text").attr("class","active_datapoint").classed("active-datapoint-small",t.use_small_class).attr("xml:space","preserve").attr("x",t.width-t.right).attr("y",t.top/2).attr("text-anchor","end"),r.append("circle").classed("line_rollover_circle",!0).attr("cx",0).attr("cy",0).attr("r",0);for(var n=1,o=0;o0?t.custom_line_color_map[o]:n;n++}if(t.data.length>1){var i=d3.geom.voronoi().x(function(e){return t.scales.X(e[t.x_accessor]).toFixed(2)}).y(function(e){return t.scales.Y(e[t.y_accessor]).toFixed(2)}).clipExtent([[t.buffer,t.buffer],[t.width-t.buffer,t.height-t.buffer]]),e=r.append("g").attr("class","voronoi"),l=d3.nest().key(function(e){return t.scales.X(e[t.x_accessor])+","+t.scales.Y(e[t.y_accessor])}).rollup(function(t){return t[0]}).entries(d3.merge(t.data.map(function(t){return t}))).map(function(t){return t.values});e.selectAll("path").data(i(l)).enter().append("path").attr("d",function(t){return"M"+t.join("L")+"Z"}).datum(function(t){return t.point}).attr("class",function(e){if(t.linked){var r=e[t.x_accessor],a=d3.time.format("%Y-%m-%d"),n="number"==typeof r?o:a(r);return"line"+e.line_id+"-color roll_"+n}return"line"+e.line_id+"-color"}).on("mouseover",this.rolloverOn(t)).on("mouseout",this.rolloverOff(t))}else{var n=1;t.custom_line_color_map.length>0&&(n=t.custom_line_color_map[0]);var e=r.append("g").attr("class","transparent-rollover-rect"),c=t.data[0].map(t.scalefns.xf);e.selectAll(".rollover-rects").data(t.data[0]).enter().append("rect").attr("class",function(e,r){if(t.linked){var a=e[t.x_accessor],o=d3.time.format("%Y-%m-%d"),s="number"==typeof a?r:o(a);return"line"+n+"-color roll_"+s}return"line"+n+"-color"}).attr("x",function(t,e){return 0==e?c[e].toFixed(2):((c[e-1]+c[e])/2).toFixed(2)}).attr("y",function(e){return t.data.length>1?t.scalefns.yf(e)-6:t.top}).attr("width",function(t,e){return 0==e?((c[e+1]-c[e])/2).toFixed(2):e==c.length-1?((c[e]-c[e-1])/2).toFixed(2):((c[e+1]-c[e-1])/2).toFixed(2)}).attr("height",function(){return t.data.length>1?12:t.height-t.bottom-t.top-t.buffer}).attr("opacity",0).on("mouseover",this.rolloverOn(t)).on("mouseout",this.rolloverOff(t)).on("mousemove",this.rolloverMove(t))}return this},this.rolloverOn=function(t){{var e=d3.select($(t.target).find("svg").get(0));d3.time.format("%Y-%m-%d")}return function(r,a){if(e.selectAll("circle.line_rollover_circle").attr("class","").attr("class","area"+r.line_id+"-color").classed("line_rollover_circle",!0).attr("cx",function(){return t.scales.X(r[t.x_accessor]).toFixed(2)}).attr("cy",function(){return t.scales.Y(r[t.y_accessor]).toFixed(2)}).attr("r",t.point_size).style("opacity",1),t.linked&&!y.globals.link){y.globals.link=!0;var n=r[t.x_accessor],o=d3.time.format("%Y-%m-%d"),s="number"==typeof n?a:o(n);d3.selectAll(".line"+r.line_id+"-color.roll_"+s).each(function(t,e){d3.select(this).on("mouseover")(t,e)})}e.selectAll("text").filter(function(t){return r==t}).attr("opacity",.3);var i=d3.time.format("%b %e, %Y");if("count"==t.format)var l=function(e){var r=e%1!=0,a=d3.format("0,000");return e=r?d3.round(e,t.decimals):e,a(e)};else var l=function(e){var r=(t.decimals?"."+t.decimals:"")+"%",a=d3.format(r);return a(e)};t.show_rollover_text&&e.select(".active_datapoint").text(function(){if(t.time_series){var e=new Date(+r[t.x_accessor]);return e.setDate(e.getDate()),i(e)+" "+t.yax_units+l(r[t.y_accessor])}return t.x_accessor+": "+r[t.x_accessor]+", "+t.y_accessor+": "+t.yax_units+l(r[t.y_accessor])}),t.mouseover&&t.mouseover(r,a)}},this.rolloverOff=function(t){var e=d3.select($(t.target).find("svg").get(0));return function(r,a){if(t.linked&&y.globals.link){y.globals.link=!1;var n=r[t.x_accessor],o=d3.time.format("%Y-%m-%d"),s="number"==typeof n?a:o(n);d3.selectAll(".roll_"+s).each(function(t){d3.select(this).on("mouseout")(t)})}e.selectAll("circle.line_rollover_circle").style("opacity",0),e.select(".active_datapoint").text(""),t.mouseout&&t.mouseout(r,a)}},this.rolloverMove=function(t){return function(e,r){t.mousemove&&t.mousemove(e,r)}},this.init(t),this},x.histogram=function(t){return this.args=t,this.init=function(t){return l(t),d(t),s(t),o(t),r(t),this},this.mainPlot=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".histogram").remove();var e=r.append("g").attr("class","histogram"),n=e.selectAll(".bar").data(t.data[0]).enter().append("g").attr("class","bar").attr("transform",function(e){return"translate("+t.scales.X(e[t.x_accessor]).toFixed(2)+","+t.scales.Y(e[t.y_accessor]).toFixed(2)+")"});return n.append("rect").attr("x",1).attr("width",function(){return(t.scalefns.xf(t.data[0][1])-t.scalefns.xf(t.data[0][0])-t.bar_margin).toFixed(2)}).attr("height",function(e){return 0==e[t.y_accessor]?0:(t.height-t.bottom-t.buffer-t.scales.Y(e[t.y_accessor])).toFixed(2)}),this},this.markers=function(){return i(t),this},this.rollover=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".transparent-rollover-rect").remove(),a.find(".active_datapoint").remove(),r.append("text").attr("class","active_datapoint").attr("xml:space","preserve").attr("x",t.width-t.right).attr("y",t.top/2).attr("text-anchor","end");var e=r.append("g").attr("class","transparent-rollover-rect"),n=e.selectAll(".bar").data(t.data[0]).enter().append("g").attr("class","rollover-rects").attr("transform",function(e){return"translate("+t.scales.X(e[t.x_accessor])+",0)"});n.append("rect").attr("x",1).attr("y",0).attr("width",function(e,r){return r!=t.data[0].length-1?(t.scalefns.xf(t.data[0][r+1])-t.scalefns.xf(e)).toFixed(2):(t.scalefns.xf(t.data[0][1])-t.scalefns.xf(t.data[0][0])).toFixed(2)}).attr("height",function(){return t.height}).attr("opacity",0).on("mouseover",this.rolloverOn(t)).on("mouseout",this.rolloverOff(t)).on("mousemove",this.rolloverMove(t))},this.rolloverOn=function(t){{var e=d3.select($(t.target).find("svg").get(0));d3.time.format("%Y-%m-%d")}return function(r,a){e.selectAll("text").filter(function(t){return r==t}).attr("opacity",.3);var n=d3.time.format("%b %e, %Y");if("count"==t.format)var o=function(e){var r=e%1!=0,a=d3.format("0,000");return e=r?d3.round(e,t.decimals):e,a(e)};else var o=function(e){var r=(t.decimals?"."+t.decimals:"")+"%",a=d3.format(r);return a(e)};d3.selectAll($(t.target).find(" svg .bar :eq("+a+")")).classed("active",!0),t.show_rollover_text&&e.select(".active_datapoint").text(function(){if(t.time_series){var e=new Date(+r[t.x_accessor]);return e.setDate(e.getDate()),n(e)+" "+t.yax_units+o(r[t.y_accessor])}return t.x_accessor+": "+o(r[t.x_accessor])+", "+t.y_accessor+": "+t.yax_units+o(r[t.y_accessor])}),t.mouseover&&t.mouseover(r,a)}},this.rolloverOff=function(t){var e=d3.select($(t.target).find("svg").get(0));return function(r,a){d3.selectAll($(t.target).find("svg .bar :eq("+a+")")).classed("active",!1),e.select(".active_datapoint").text(""),t.mouseout&&t.mouseout(r,a)}},this.rolloverMove=function(t){return function(e,r){t.mousemove&&t.mousemove(e,r)}},this.init(t),this},x.point=function(t){return this.args=t,this.init=function(t){return l(t),f(t),s(t),o(t),r(t),this},this.markers=function(){return i(t),t.least_squares&&p(t),this},this.mainPlot=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".points").remove(),e=r.append("g").classed("points",!0);var n=e.selectAll("circle").data(t.data[0]).enter().append("svg:circle").attr("class",function(t,e){return"path-"+e}).attr("cx",t.scalefns.xf).attr("cy",t.scalefns.yf);return null!=t.color_accessor?(n.attr("fill",t.scalefns.color),n.attr("stroke",t.scalefns.color)):n.classed("points-mono",!0),null!=t.size_accessor?n.attr("r",t.scalefns.size):n.attr("r",t.point_size),this},this.rollover=function(){var e=d3.select($(t.target).find("svg").get(0)),r=$($(t.target).find("svg").get(0));r.find(".voronoi").remove(),r.find(".active_datapoint").remove(),e.append("text").attr("class","active_datapoint").attr("xml:space","preserve").attr("x",t.width-t.right).attr("y",t.top/2).attr("text-anchor","end");var a=d3.geom.voronoi().x(t.scalefns.xf).y(t.scalefns.yf).clipExtent([[t.buffer,t.buffer],[t.width-t.buffer,t.height-t.buffer]]),n=e.append("g").attr("class","voronoi");return n.selectAll("path").data(a(t.data[0])).enter().append("path").attr("d",function(t){return void 0!=t?"M"+t.join(",")+"Z":void 0}).attr("class",function(t,e){return"path-"+e}).style("fill-opacity",0).on("mouseover",this.rolloverOn(t)).on("mouseout",this.rolloverOff(t)).on("mousemove",this.rolloverMove(t)),this},this.rolloverOn=function(t){var e=d3.select($(t.target).find("svg").get(0));return function(r,a){e.selectAll(".points circle").classed("selected",!1);var n=e.selectAll(".points circle.path-"+a).classed("selected",!0);t.size_accessor?n.attr("r",function(e){return t.scalefns.size(e)+1}):n.attr("r",t.point_size),t.linked&&!globals.link&&(globals.link=!0,d3.selectAll(".voronoi .path-"+a).each(function(){d3.select(this).on("mouseover")(r,a)}));var o=d3.time.format("%b %e, %Y");if("count"==t.format)var s=function(e){var r=e%1!=0,a=d3.format("0,000");return e=r?d3.round(e,t.decimals):e,a(e)};else var s=function(e){var r=(t.decimals?"."+t.decimals:"")+"%",a=d3.format(r);return a(e)};t.show_rollover_text&&e.select(".active_datapoint").text(function(){if(t.time_series){var e=new Date(+r.point[t.x_accessor]);return e.setDate(e.getDate()),o(e)+" "+t.yax_units+s(r.point[t.y_accessor])}return t.x_accessor+": "+s(r.point[t.x_accessor])+", "+t.y_accessor+": "+t.yax_units+s(r.point[t.y_accessor])}),t.mouseover&&t.mouseover(r,a)}},this.rolloverOff=function(t){var e=d3.select($(t.target).find("svg").get(0));return function(r,a){t.linked&&globals.link&&(globals.link=!1,d3.selectAll(".voronoi .path-"+a).each(function(){d3.select(this).on("mouseout")(r,a)}));var n=e.selectAll(".points circle").classed("unselected",!1).classed("selected",!1);t.size_accessor?n.attr("r",t.scalefns.size):n.attr("r",t.point_size),e.select(".active_datapoint").text(""),t.mouseout&&t.mouseout(r,a)}},this.rolloverMove=function(t){return function(e,r){t.mousemove&&t.mousemove(e,r)}},this.update=function(){return this},this.init(t),this},x.bar=function(t){return this.args=t,this.init=function(t){return l(t),u(t),s(t),o(t),a(t),this},this.mainPlot=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".barplot").remove();var n=t.data[0],e=r.append("g").classed("barplot",!0),o=t.scales.Y.rangeBand()/1.5;if(e.selectAll(".bar").data(n).enter().append("rect").classed("bar",!0).attr("x",t.scales.X(0)).attr("y",function(e){return t.scalefns.yf(e)+o/2}).attr("height",o).attr("width",function(e){return t.scalefns.xf(e)-t.scales.X(0)}),t.predictor_accessor){var s=t.predictor_proportion,i=s-1;e.selectAll(".prediction").data(n).enter().append("rect").attr("class","bar-prediction").attr("x",t.scales.X(0)).attr("y",function(e){return t.scalefns.yf(e)+i*o/(2*s)+o/2}).attr("height",o/s).attr("width",function(e){return t.scales.X(e[t.predictor_accessor])-t.scales.X(0)})}return t.baseline_accessor&&e.selectAll(".baseline").data(n).enter().append("line").attr("class","bar-baseline").attr("x1",function(e){return t.scales.X(e[t.baseline_accessor])}).attr("x2",function(e){return t.scales.X(e[t.baseline_accessor])}).attr("y1",function(e){return t.scalefns.yf(e)+o/2-o/s+o/2}).attr("y2",function(e){return t.scalefns.yf(e)+o/2+o/s+o/2}),this},this.markers=function(){return i(t),this},this.rollover=function(){var e,r=d3.select($(t.target).find("svg").get(0)),a=$($(t.target).find("svg").get(0));a.find(".transparent-rollover-rect").remove(),a.find(".active_datapoint").remove(),r.append("text").attr("class","active_datapoint").attr("xml:space","preserve").attr("x",t.width-t.right).attr("y",t.top/2).attr("dy",".35em").attr("text-anchor","end");{var e=r.append("g").attr("class","transparent-rollover-rect");e.selectAll(".bar").data(t.data[0]).enter().append("rect").attr("class","bar-rollover").attr("x",t.scales.X(0)).attr("y",t.scalefns.yf).attr("width",t.width).attr("height",t.scales.Y.rangeBand()+2).attr("opacity",0).on("mouseover",this.rolloverOn(t)).on("mouseout",this.rolloverOff(t)).on("mousemove",this.rolloverMove(t))}},this.rolloverOn=function(t){{var e=d3.select($(t.target).find("svg").get(0));d3.time.format("%Y-%m-%d")}return function(r,a){e.selectAll("text").filter(function(t){return r==t}).attr("opacity",.3);var n=d3.time.format("%b %e, %Y");if("count"==t.format)var o=function(e){var r=e%1!=0,a=d3.format("0,000");return e=r?d3.round(e,t.decimals):e,a(e)};else var o=function(e){var r=(t.decimals?"."+t.decimals:"")+"%",a=d3.format(r);return a(e)};d3.selectAll($(t.target+" svg g.barplot .bar:eq("+a+")")).classed("active",!0),t.show_rollover_text&&e.select(".active_datapoint").text(function(){if(t.time_series){var e=new Date(+r[t.x_accessor]);return e.setDate(e.getDate()),n(e)+" "+t.yax_units+o(r[t.y_accessor])}return r[t.y_accessor]+": "+o(r[t.x_accessor])}),t.mouseover&&t.mouseover(r,a)}},this.rolloverOff=function(t){var e=d3.select($(t.target).find("svg").get(0));return function(r,a){d3.selectAll($(t.target).find("svg g.barplot .bar:eq("+a+")")).classed("active",!1),e.select(".active_datapoint").text(""),t.mouseout&&t.mouseout(r,a)}},this.rolloverMove=function(t){return function(e,r){t.mousemove&&t.mousemove(e,r)}},this.init(t),this},y.data_table=function(e){return this.args=e,this.args.standard_col={width:150,font_size:12,font_weight:"normal"},this.args.columns=[],this.formatting_options=[["color","color"],["font-weight","font_weight"],["font-style","font_style"],["font-size","font_size"]],this._strip_punctuation=function(t){var e=t.replace(/[^a-zA-Z0-9 _]+/g,""),r=e.replace(/ +?/g,"");return r},this._format_element=function(t,e,r){this.formatting_options.forEach(function(a){var n=a[0],o=a[1];r[o]&&t.style(n,"string"==typeof r[o]||"number"==typeof r[o]?r[o]:r[o](e))})},this._add_column=function(t,e){var r=this.args.standard_col,a=g(y.clone(t),y.clone(r));a.type=e,this.args.columns.push(a)},this.target=function(){var t=arguments[0];return this.args.target=t,this},this.title=function(){return this._add_column(arguments[0],"title"),this},this.text=function(){return this._add_column(arguments[0],"text"),this},this.bullet=function(){return this},this.sparkline=function(){return this},this.number=function(){return this._add_column(arguments[0],"number"),this},this.display=function(){var e,r=this.args;t(r);var e,a,n,o,s,i,l,c,d,u,f,p=r.target,h=d3.select(p).append("table").classed("data-table",!0),g=h.append("colgroup"),m=h.append("thead"),_=h.append("tbody");n=m.append("tr");for(var v=0;va;a++)if(e.call(r,t[a],a,t)===breaker)return}else for(var o in t)if(e.call(r,t[o],o,t)===breaker)return;return t};y.clone=function(t){if(null==t||"object"!=typeof t)return t;if(t instanceof Date){var e=new Date;return e.setTime(t.getTime()),e}if(t instanceof Array){for(var e=[],r=0,a=t.length;a>r;r++)e[r]=y.clone(t[r]);return e}if(t instanceof Object){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=y.clone(t[n]));return e}throw new Error("Unable to copy obj! Its type isn't supported.")},"function"==typeof define&&define.amd?define(y):"object"==typeof module&&module.exports&&(module.exports=y),window.MG=y}(); \ No newline at end of file diff --git a/examples/dev.htm b/examples/dev.htm index 417ada0c03..ff91e3775a 100644 --- a/examples/dev.htm +++ b/examples/dev.htm @@ -28,6 +28,7 @@ + diff --git a/examples/examples.htm b/examples/examples.htm index b8c5b5f4f0..76a6fcfd6f 100644 --- a/examples/examples.htm +++ b/examples/examples.htm @@ -25,7 +25,7 @@ - +