From 53b0cf721385a96333ad1a082acb92374b3c40e5 Mon Sep 17 00:00:00 2001 From: almossawi Date: Wed, 25 Mar 2015 09:36:42 -0700 Subject: [PATCH] Update files for issue #358 --- dist/metricsgraphics.js | 5050 ----------------------------------- dist/metricsgraphics.min.js | 3 - 2 files changed, 5053 deletions(-) delete mode 100644 dist/metricsgraphics.js delete mode 100644 dist/metricsgraphics.min.js diff --git a/dist/metricsgraphics.js b/dist/metricsgraphics.js deleted file mode 100644 index 246f4a30cc..0000000000 --- a/dist/metricsgraphics.js +++ /dev/null @@ -1,5050 +0,0 @@ -(function() { - "use strict"; - (function(root, factory) { - if (typeof define === 'function' && define.amd) { - define(['d3', 'jquery'], factory); - } else if (typeof exports === 'object') { - module.exports = factory(require('d3'), require('jquery')); - } else { - root.MG = factory(root.d3, root.jQuery); - } - }(this, function(d3, $) { - window.MG = {version: '2.2.1'}; - - var charts = {}; - - MG.globals = {}; - MG.deprecations = { - rollover_callback: { replacement: 'mouseover', version: '2.0' }, - rollout_callback: { replacement: 'mouseout', version: '2.0' }, - show_years: { replacement: 'show_secondary_x_label', version: '2.1' } - }; - 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 - missing_is_hidden: false, // if true, missing values will appear as broken segments - 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 - full_width: false, // sets the graphic width to be the width of the parent element and resizes dynamically - full_height: false, // sets the graphic width to be the width of the parent element and resizes dynamically - 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 - xax_start_at_min: false, - 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: null, // xax_format is a function that formats the labels for the x axis. - 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 - linked_format: '%Y-%m-%d', // What granularity to link on for graphs. Default is at day - list: false, - baselines: null, // sets the baseline lines - markers: null, // sets the marker lines - scalefns: {}, - scales: {}, - show_year_marker: false, - show_secondary_x_label: true, - target: '#viz', - interpolate: 'cardinal', // interpolation method to use when rendering lines - interpolate_tension: 0.7, // its range is from 0 to 1; increase if your data is irregular and you notice artifacts - 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 - aggregate_rollover: false, // links the lines in a multi-line chart - show_tooltips: true // if enabled, a chart's description will appear in a tooltip (requires jquery) - }; - - 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) { - d3.select('#histogram svg .mg-active-datapoint') - .text('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: 0.1, - height: 500, - top: 20, - bar_height: 20, - left: 70 - }; - - defaults.missing = { - top: 40, // the size of the top margin - bottom: 30, // the size of the bottom margin - right: 10, // size of the right margin - left: 10, // size of the left margin - buffer: 8, // the buffer between the actual chart area and the margins - legend_target: '', - width: 350, - height: 220, - missing_text: 'Data currently missing or unavailable', - scalefns: {}, - scales: {}, - show_missing_background: true, - interpolate: 'cardinal' - }; - - var args = arguments[0]; - if (!args) { args = {}; } - - if (args.list) { - args.x_accessor = 0; - args.y_accessor = 1; - } - - // 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 - var a; - if (args.chart_type === 'missing-data') { - args = merge_with_defaults(args, defaults.missing); - charts.missing(args); - } - else if (args.chart_type === 'point') { - a = merge_with_defaults(defaults.point, defaults.all); - args = merge_with_defaults(args, a); - charts.point(args).mainPlot().markers().rollover().windowListeners(); - } - else if (args.chart_type === 'histogram') { - a = merge_with_defaults(defaults.histogram, defaults.all); - args = merge_with_defaults(args, a); - charts.histogram(args).mainPlot().markers().rollover().windowListeners(); - } - else if (args.chart_type === 'bar') { - a = merge_with_defaults(defaults.bar, defaults.all); - args = merge_with_defaults(args, a); - charts.bar(args).mainPlot().markers().rollover().windowListeners(); - } - else { - args = merge_with_defaults(args, defaults.all); - charts.line(args).markers().mainPlot().rollover().windowListeners(); - } - - return args.data; - }; - - if (typeof jQuery !== 'undefined') { - /*! - * 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 - */ - - /* ======================================================================== - * 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.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 - actualHeight < containerDim.top ? 'bottom' : - placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' : - placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' : - placement; - - $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); - }; - - $.support.transition && this.$tip.hasClass('fade') ? - $tip - .one('bsTransitionEnd', complete) - .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : - complete(); - } - }; - - Tooltip.prototype.applyPlacement = function (offset, placement) { - var $tip = this.tip(); - var width = $tip[0].offsetWidth; - var height = $tip[0].offsetHeight; - - // manually read margins because getBoundingClientRect includes difference - var marginTop = parseInt($tip.css('margin-top'), 10); - var marginLeft = parseInt($tip.css('margin-left'), 10); - - // we must check for NaN for ie 8/9 - if (isNaN(marginTop)) marginTop = 0; - if (isNaN(marginLeft)) marginLeft = 0; - - offset.top = offset.top + marginTop; - offset.left = offset.left + marginLeft; - - // $.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); - - $tip.addClass('in'); - - // 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 (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; - - var isVertical = /top|bottom/.test(placement); - var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight; - var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'; - - $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(); - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title); - $tip.removeClass('fade in top bottom left right'); - }; - - 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.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.hasContent = function () { - return this.getTitle(); - }; - - Tooltip.prototype.getPosition = function ($element) { - $element = $element || this.$element; - - var el = $element[0]; - var isBody = el.tagName == 'BODY'; - - 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 }); - } - 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.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; - } - } - - 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); - }); - }; - - - // 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; - - 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; - - - // TOOLTIP NO CONFLICT - // =================== - - $.fn.tooltip.noConflict = function () { - $.fn.tooltip = old; - return this; - }; - - }(jQuery); - - /* ======================================================================== - * 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) - * ======================================================================== */ - - - +function ($) { - 'use strict'; - - if(typeof $().popover == 'function') - return true; - - // POPOVER PUBLIC CLASS DEFINITION - // =============================== - - 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: '' - }); - - - // NOTE: POPOVER EXTENDS tooltip.js - // ================================ - - 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()[ // we use append for html objects to maintain js events - this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' - ](content); - - $tip.removeClass('fade top bottom left right in'); - - // 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(); - }; - - 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; - }; - - - // POPOVER PLUGIN DEFINITION - // ========================= - - 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; - - - // POPOVER NO CONFLICT - // =================== - - $.fn.popover.noConflict = function () { - $.fn.popover = old; - return this; - }; - - }(jQuery); - } - function chart_title(args) { - 'use strict'; - - var container = d3.select(args.target); - - // remove the current title if it exists - container.select('.mg-chart-title').remove(); - - if (args.target && args.title) { - //only show question mark if there's a description - var optional_question_mark = (args.show_tooltips && args.description) - ? '' - : ''; - - container.insert('h2', ':first-child') - .attr('class', 'mg-chart-title') - .html(args.title + optional_question_mark); - - //activate the question mark if we have a description - if (args.show_tooltips && args.description) { - var $newTitle = $(container.node()).find('h2.mg-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 = mg_get_svg_child_of(args.target); - - var buffer_size = args.chart_type === 'point' - ? args.buffer / 2 - : args.buffer * 2 / 3; - - var all_data = []; - for (var i = 0; i < args.data.length; i++) { - for (var j = 0; j < args.data[i].length; j++) { - all_data.push(args.data[i][j]); - } - } - - var rug = svg.selectAll('line.mg-y-rug').data(all_data); - - //set the attributes that do not change after initialization, per - //D3's general update pattern - rug.enter().append('svg:line') - .attr('class', 'mg-y-rug') - .attr('opacity', 0.3); - - //remove rug elements that are no longer in use - rug.exit().remove(); - - //set coordinates of new rug elements - rug.exit().remove(); - - rug.attr('x1', args.left + 1) - .attr('x2', args.left+buffer_size) - .attr('y1', args.scalefns.yf) - .attr('y2', args.scalefns.yf); - - if (args.color_accessor) { - rug.attr('stroke', args.scalefns.color); - rug.classed('mg-y-rug-mono', false); - } else { - rug.attr('stroke', null); - rug.classed('mg-y-rug-mono', true); - } - } - - function y_axis(args) { - if (!args.processed) { - args.processed = {}; - } - - var svg = mg_get_svg_child_of(args.target); - - var g; - - var min_y, - max_y; - - args.scalefns.yf = function(di) { - //since we want to show actual zeros when missing_is_hidden is on - if(args.missing_is_hidden && di['missing']) { - return args.scales.Y(di[args.y_accessor]) + 42.1234; - } - - return args.scales.Y(di[args.y_accessor]); - }; - - var _set = false, - gtZeroFilter = function(d) { return d[args.y_accessor] > 0; }, - mapToY = function(d) { return d[args.y_accessor]; }; - for (var i = 0; i < args.data.length; i++) { - var a = args.data[i]; - - if (args.y_scale_type === 'log') { - // filter positive values - a = a.filter(gtZeroFilter); - } - - if (a.length > 0) { // get min/max in one pass - var extent = d3.extent(a, mapToY); - - 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); - } - } - } - - // the default case is for the y-axis to start at 0, unless we explicitly want it - // to start at an arbitrary number or from the data's minimum value - if (min_y >= 0 && !args.min_y && !args.min_y_from_data) { - min_y = 0; - } - - if (args.chart_type === 'bar') { - min_y = 0; - max_y = d3.max(args.data[0], function(d) { - var trio = []; - trio.push(d[args.y_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); - }); - } - //if a min_y or max_y have been set, use those instead - min_y = args.min_y !== null ? args.min_y : min_y; - max_y = args.max_y !== null ? args.max_y : max_y * args.inflator; - 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; - } - } - - 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') { - // 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]); - } - args.processed.min_y = min_y; - args.processed.max_y = max_y; - //used for ticks and such, and designed to be paired with log or linear - args.scales.Y_axis = d3.scale.linear() - .domain([args.processed.min_y, args.processed.max_y]) - .range([args.height - args.bottom - args.buffer, args.top]); - - var yax_format = args.yax_format; - if (!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 { //percentage - yax_format = function(d_) { - var n = d3.format('%p'); - return n(d_); - }; - } - } - - //remove the old y-axis, add new one - svg.selectAll('.mg-y-axis').remove(); - - if (!args.y_axis) { - return this; - } - - //y axis - g = svg.append('g') - .classed('mg-y-axis', true) - .classed('mg-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)"; - }); - } - - 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') { - // get out only whole logs - scale_ticks = scale_ticks.filter(function(d) { - return Math.abs(log10(d)) % 1 < 1e-6 || Math.abs(log10(d)) % 1 > 1-1e-6; - }); - } - - //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; - args.data.forEach(function(d, i) { - d.forEach(function(d, i) { - 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; - }); - } - - 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)); - } - - //add y ticks - g.selectAll('.mg-yax-ticks') - .data(scale_ticks).enter() - .append('line') - .classed('mg-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('.mg-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) { - var o = yax_format(d); - return o; - }); - - if (args.y_rug) { - y_rug(args); - } - - return this; - } - - function y_axis_categorical(args) { - // first, come up with y_axis - 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 = mg_get_svg_child_of(args.target); - - //remove the old y-axis, add new one - svg.selectAll('.mg-y-axis').remove(); - - var g = svg.append('g') - .classed('mg-y-axis', true) - .classed('mg-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 = mg_get_svg_child_of(args.target); - - 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]); - }; - } - } - - function mg_point_add_size_scale(args) { - var min_size, max_size, size_domain, size_range; - 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]); - }; - } - } - - function mg_add_x_label(g, args) { - g.append('text') - .attr('class', 'label') - .attr('x', function() { - return (args.left + args.width - args.right) / 2; - }) - .attr('y', (args.height - args.bottom / 2).toFixed(2)) - .attr('dy', '.50em') - .attr('text-anchor', 'middle') - .text(function(d) { - return args.x_label; - }); - } - - function mg_default_bar_xax_format(args) { - if (args.xax_format) { - return args.xax_format; - } - - return function(f) { - if (f < 1.0) { - //don't scale tiny values - return args.xax_units + d3.round(f, args.decimals); - } else { - var pf = d3.formatPrefix(f); - return args.xax_units + pf.scale(f) + pf.symbol; - } - }; - } - - function mg_default_xax_format(args) { - if (args.xax_format) { - return args.xax_format; - } - - var diff, - main_time_format, - time_frame; - - if (args.time_series) { - diff = (args.processed.max_x - args.processed.min_x) / 1000; - - if (diff < 60) { - main_time_format = d3.time.format('%M:%S'); - time_frame = 'seconds'; - } else if (diff / (60 * 60) <= 24) { - main_time_format = d3.time.format('%H:%M'); - time_frame = 'less-than-a-day'; - } else if (diff / (60 * 60) <= 24 * 4) { - main_time_format = d3.time.format('%H:%M'); - time_frame = 'four-days'; - } else { - main_time_format = d3.time.format('%b %d'); - time_frame = 'default'; - } - } - - args.processed.main_x_time_format = main_time_format; - args.processed.x_time_frame = time_frame; - - return 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 - if(args.data[0][0][args.x_accessor] instanceof Date) { - return args.processed.main_x_time_format(d); - } else if (typeof args.data[0][0][args.x_accessor] === 'number') { - if (d < 1.0) { - //don't scale tiny values - return args.xax_units + d3.round(d, args.decimals); - } else { - pf = d3.formatPrefix(d); - return args.xax_units + pf.scale(d) + pf.symbol; - } - } else { - return d; - } - }; - } - - function mg_add_x_ticks(g, args) { - var last_i = args.scales.X.ticks(args.xax_count).length - 1; - var ticks = args.scales.X.ticks(args.xax_count); - - //force min to be the first tick rather than the first element in ticks - if(args.xax_start_at_min) { - ticks[0] = args.processed.min_x; - } - - 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', function() { - //start the axis line from the beginning, domain's min, or the auto-generated - //ticks' first element, depending on whether xax_count is set to 0 or - //xax_start_at_min is set to true - if (args.xax_count === 0) { - return args.left + args.buffer; - } - else if (args.xax_start_at_min) { - return args.scales.X(args.processed.min_x).toFixed(2) - } - else { - return (args.scales.X(args.scales.X.ticks(args.xax_count)[0])).toFixed(2); - } - }) - .attr('x2', - (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('.mg-xax-ticks') - .data(ticks).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 'mg-extended-x-ticks'; - } - }); - } - - function mg_add_x_tick_labels(g, args) { - var ticks = args.scales.X.ticks(args.xax_count); - - //force min to be the first tick rather than the first element in ticks - if(args.xax_start_at_min) { - ticks[0] = args.processed.min_x; - } - - g.selectAll('.mg-xax-labels') - .data(ticks).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 || args.show_secondary_x_label)) { - var secondary_marks, - secondary_function, yformat; - - var time_frame = args.processed.x_time_frame; - - switch(time_frame) { - case 'seconds': - secondary_function = d3.time.days; - yformat = d3.time.format('%I %p'); - break; - case 'less-than-a-day': - secondary_function = d3.time.days; - yformat = d3.time.format('%b %d'); - break; - case 'four-days': - secondary_function = d3.time.days; - yformat = d3.time.format('%b %d'); - break; - default: - secondary_function = d3.time.years; - yformat = d3.time.format('%Y'); - } - - var years = secondary_function(args.processed.min_x, args.processed.max_x); - - //if xax_start_at_min is set - if (args.xax_start_at_min && years.length === 0) { - var first_tick = ticks[0]; - years = [first_tick]; - } else 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('mg-year-marker', true) - .classed('mg-year-marker-small', args.use_small_class); - - if (time_frame === 'default' && args.show_year_marker) { - g.selectAll('.mg-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); - } - - g.selectAll('.mg-year-marker') - .data(years).enter() - .append('text') - .attr('x', function(d, i) { - if (args.xax_start_at_min && i == 0) { - d = ticks[0]; - } - - 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); - }); - } - } - - function mg_find_min_max_x(args) { - var last_i, - extent_x = [], - min_x, - max_x, - all_data = [].concat.apply([], args.data), - mapDtoX = function(d) { return d[args.x_accessor]; }; - - // clear the cached xax_format in case we need to recalculate - if(args.xax_format === null) { - delete args.xax_format; - } - - if (args.chart_type === 'line' || args.chart_type === 'point' || args.chart_type === 'histogram') { - extent_x = d3.extent(all_data, mapDtoX); - min_x = extent_x[0]; - max_x = extent_x[1]; - - } else if (args.chart_type === 'bar') { - min_x = 0; - max_x = d3.max(all_data, function(d) { - var trio = [ - d[args.x_accessor], - (d[args.baseline_accessor]) ? d[args.baseline_accessor] : 0, - (d[args.predictor_accessor]) ? d[args.predictor_accessor] : 0 - ]; - return Math.max.apply(null, trio); - }); - } - //if data set is of length 1, expand the range so that we can build the x-axis - //of course, a line chart doesn't make sense in this case, so the preferred - //method would be to check for said object's length and, if appropriate, - //change the chart type to 'point' - if (min_x === max_x) { - if (min_x instanceof Date) { - var yesterday = MG.clone(min_x).setDate(min_x.getDate() - 1); - var tomorrow = MG.clone(min_x).setDate(min_x.getDate() + 1); - - min_x = yesterday; - max_x = tomorrow; - } else if (typeof min_x === 'number') { - min_x = min_x - 1; - max_x = max_x + 1; - } else if (typeof min_x === 'string') { - min_x = Number(min_x) - 1; - max_x = Number(max_x) + 1; - } - - //force xax_count to be 2 - args.xax_count = 2; - } - - 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; - - args.processed.min_x = min_x; - args.processed.max_x = max_x; - - mg_select_xax_format(args); - - if (!args.time_series) { - if (args.processed.min_x < 0) { - args.processed.min_x = args.processed.min_x - (args.processed.max_x * (args.inflator - 1)); - args.x_axis_negative = true; - } - } - - if (args.chart_type === 'bar') { - args.additional_buffer = args.buffer * 5; - } else { - args.additional_buffer = 0; - } - } - - function mg_select_xax_format(args) { - if (!args.xax_format && args.chart_type === 'line') args.xax_format = mg_default_xax_format(args); - if (!args.xax_format && args.chart_type === 'point') args.xax_format = mg_default_xax_format(args); - if (!args.xax_format && args.chart_type === 'histogram') args.xax_format = mg_default_xax_format(args); - if (!args.xax_format && args.chart_type === 'bar') args.xax_format = mg_default_bar_xax_format(args); - } - - function init(args) { - 'use strict'; - var defaults = { - target: null, - title: null, - description: null - }; - - // If you pass in a dom element for args.target, the expectation - // of a string elsewhere will break. - - args = arguments[0]; - if (!args) { args = {}; } - args = merge_with_defaults(args, defaults); - - if (d3.select(args.target).empty()) { - console.warn('The specified target element "' + args.target + '" could not be found in the page. The chart will not be rendered.'); - return; - } - - var container = d3.select(args.target); - var svg = container.selectAll('svg'); - - //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 (args.data[0][0][args.x_accessor] instanceof Date) { - args.time_series = true; - } else { - args.time_series = false; - } - - var svg_width = args.width; - var svg_height = args.height; - - //are we setting the aspect ratio - if (args.full_width) { - // get parent element - svg_width = get_width(args.target); - } - - if (args.full_height) { - svg_height = get_height(args.target); - } - - 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 - if ((!svg.selectAll('.mg-main-line').empty() && args.chart_type !== 'line') - || (!svg.selectAll('.mg-points').empty() && args.chart_type !== 'point') - || (!svg.selectAll('.mg-histogram').empty() && args.chart_type !== 'histogram') - || (!svg.selectAll('.mg-barplot').empty() && args.chart_type !== 'bar') - ) { - svg.remove(); - } - - //add svg if it doesn't already exist - //using trim on html rather than :empty to ignore white spaces if they exist - if (mg_get_svg_child_of(args.target).empty()) { - //add svg - svg = d3.select(args.target) - .append('svg') - .classed('linked', args.linked) - .attr('width', svg_width) - .attr('height', svg_height); - } - - args.width = svg_width; - args.height = svg_height; - - // add clip path element to svg - svg.selectAll('.mg-clip-path').remove(); - - svg.append('defs') - .attr('class', 'mg-clip-path') - .append('clipPath') - .attr('id', 'mg-plot-window-' + mg_strip_punctuation(args.target)) - .append('svg:rect') - .attr('x', args.left) - .attr('y', args.top) - .attr('width', args.width - args.left - args.right - args.buffer) - .attr('height', args.height - args.top - args.bottom - args.buffer + 1); - - //has the width or height changed? - if (svg_width !== Number(svg.attr('width'))) { - svg.attr('width', svg_width); - } - - if (svg_height !== Number(svg.attr('height'))) { - svg.attr('height', svg_height); - } - - // This is an unfinished feature. Need to reconsider how we handle automatic scaling. - svg.attr('viewBox', '0 0 ' + svg_width + ' ' + svg_height); - - if (args.full_width || args.full_height) { - svg.attr('preserveAspectRatio', 'xMinYMin meet'); - } - - // remove missing class - svg.classed('mg-missing', false); - - // remove missing text - svg.selectAll('.mg-missing-text').remove(); - svg.selectAll('.mg-missing-pane').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 - - var i = 0; - if (args.data.length < svg.selectAll('.mg-main-line')[0].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; i < arr.length; i++) { arr[i] = i + 1; } - return arr; - }; - - //get an array of lines ids to remove - var lines_to_remove = arrDiff( - array_full_series(args.max_data_size), - args.custom_line_color_map); - - for (i = 0; i < lines_to_remove.length; i++) { - svg.selectAll('.mg-main-line.mg-line' + lines_to_remove[i] + '-color') - .remove(); - } - } - //if we don't have a customer line-color map, just remove the lines from the end - else { - var num_of_new = args.data.length; - var num_of_existing = svg.selectAll('.mg-main-line')[0].length; - - for (i = num_of_existing; i > num_of_new; i--) { - svg.selectAll('.mg-main-line.mg-line' + i + '-color') - .remove(); - } - } - } - - return this; - } - - function markers(args) { - 'use strict'; - var svg = mg_get_svg_child_of(args.target); - var gm; - var gb; - - //remove existing markers and baselines - svg.selectAll('.mg-markers').remove(); - svg.selectAll('.mg-baselines').remove(); - - if (args.markers) { - gm = svg.append('g') - .attr('class', 'mg-markers'); - - gm.selectAll('.mg-markers') - .data(args.markers.filter(inRange)) - .enter() - .append('line') - .attr('x1', xPositionFixed) - .attr('x2', xPositionFixed) - .attr('y1', args.top) - .attr('y2', function() { - return args.height - args.bottom - args.buffer; - }) - .attr('stroke-dasharray', '3,1'); - - gm.selectAll('.mg-markers') - .data(args.markers.filter(inRange)) - .enter() - .append('text') - .attr('class', 'mg-marker-text') - .attr('x', xPosition) - .attr('y', args.top - 8) - .attr('text-anchor', 'middle') - .text(function(d) { - return d.label; - }); - - preventOverlap(gm.selectAll('.mg-marker-text')[0]); - } - - if (args.baselines) { - gb = svg.append('g') - .attr('class', 'mg-baselines'); - - gb.selectAll('.mg-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('.mg-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; - }); - } - - function preventOverlap(labels) { - if (!labels || labels.length == 1) { - return; - } - - //see if each of our labels overlaps any of the other labels - for (var i = 0; i < labels.length; i++) { - //if so, nudge it up a bit, if the label it intersects hasn't already been nudged - if (isOverlapping(labels[i], labels)) { - var node = d3.select(labels[i]); - var newY = +node.attr('y'); - if (newY + 8 == args.top) { - newY = args.top - 16; - } - node.attr('y', newY); - } - } - } - - function isOverlapping(element, labels) { - var element_bbox = element.getBoundingClientRect(); - - for (var i = 0; i < labels.length; i++) { - if (labels[i] == element) { - continue; - } - - //check to see if this label overlaps with any of the other labels - var sibling_bbox = labels[i].getBoundingClientRect(); - if (element_bbox.top === sibling_bbox.top && - !(sibling_bbox.left > element_bbox.right || sibling_bbox.right < element_bbox.left) - ) { - return true; - } - } - return false; - } - - function xPosition(d) { - return args.scales.X(d[args.x_accessor]); - } - - function xPositionFixed(d) { - return xPosition(d).toFixed(2); - } - - function inRange(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); - } - - return this; - } - - function mg_window_listeners(args){ - mg_if_aspect_ratio_resize_svg(args); - } - - function mg_if_aspect_ratio_resize_svg(args){ - // If we've asked the svg to fill a div, resize with div. - if (args.full_width || args.full_height){ - window.addEventListener('resize', function(){ - var svg = d3.select(args.target).select('svg'); - var aspect = svg.attr('height') / svg.attr('width'); - var newWidth = get_width(args.target); - - svg.attr('width', newWidth); - svg.attr('height', aspect * newWidth); - }, true); - } - - } - if (typeof jQuery !== 'undefined') { - /*! - * 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 - */ - - /* ======================================================================== - * 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 ($) { - 'use strict'; - - if(typeof $().dropdown == 'function') - return true; - - // DROPDOWN CLASS DEFINITION - // ========================= - - var backdrop = '.dropdown-backdrop'; - var toggle = '[data-toggle="dropdown"]'; - var Dropdown = function (element) { - $(element).on('click.bs.dropdown', this.toggle); - }; - - 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 - $('