/** * The entire dc.js library is scoped under the **dc** name space. It does not introduce * anything else into the global name space. * * Most `dc` functions are designed to allow function chaining, meaning they return the current chart * instance whenever it is appropriate. The getter forms of functions do not participate in function * chaining because they return values that are not the chart, although some, * such as {@link dc.baseMixin#svg .svg} and {@link dc.coordinateGridMixin#xAxis .xAxis}, * return values that are themselves chainable d3 objects. * @namespace dc * @version <%= conf.pkg.version %> * @example * // Example chaining * chart.width(300) * .height(300) * .filter('sunday'); */ /*jshint -W079*/ var dc = { version: '<%= conf.pkg.version %>', constants: { CHART_CLASS: 'dc-chart', DEBUG_GROUP_CLASS: 'debug', STACK_CLASS: 'stack', DESELECTED_CLASS: 'deselected', SELECTED_CLASS: 'selected', NODE_INDEX_NAME: '__index__', GROUP_INDEX_NAME: '__group_index__', DEFAULT_CHART_GROUP: '__default_chart_group__', EVENT_DELAY: 40, NEGLIGIBLE_NUMBER: 1e-10 }, _renderlet: null }; /*jshint +W079*/ /** * The dc.chartRegistry object maintains sets of all instantiated dc.js charts under named groups * and the default group. * * A chart group often corresponds to a crossfilter instance. It specifies * the set of charts which should be updated when a filter changes on one of the charts or when the * global functions {@link dc.filterAll dc.filterAll}, {@link dc.refocusAll dc.refocusAll}, * {@link dc.renderAll dc.renderAll}, {@link dc.redrawAll dc.redrawAll}, or chart functions * {@link dc.baseMixin#renderGroup baseMixin.renderGroup}, * {@link dc.baseMixin#redrawGroup baseMixin.redrawGroup} are called. * * @namespace chartRegistry * @memberof dc * @type {{has, register, deregister, clear, list}} */ dc.chartRegistry = (function () { // chartGroup:string => charts:array var _chartMap = {}; function initializeChartGroup (group) { if (!group) { group = dc.constants.DEFAULT_CHART_GROUP; } if (!_chartMap[group]) { _chartMap[group] = []; } return group; } return { /** * Determine if a given chart instance resides in any group in the registry. * @method has * @memberof dc.chartRegistry * @param {Object} chart dc.js chart instance * @returns {Boolean} */ has: function (chart) { for (var e in _chartMap) { if (_chartMap[e].indexOf(chart) >= 0) { return true; } } return false; }, /** * Add given chart instance to the given group, creating the group if necessary. * If no group is provided, the default group `dc.constants.DEFAULT_CHART_GROUP` will be used. * @method register * @memberof dc.chartRegistry * @param {Object} chart dc.js chart instance * @param {String} [group] Group name */ register: function (chart, group) { group = initializeChartGroup(group); _chartMap[group].push(chart); }, /** * Remove given chart instance from the given group, creating the group if necessary. * If no group is provided, the default group `dc.constants.DEFAULT_CHART_GROUP` will be used. * @method deregister * @memberof dc.chartRegistry * @param {Object} chart dc.js chart instance * @param {String} [group] Group name */ deregister: function (chart, group) { group = initializeChartGroup(group); for (var i = 0; i < _chartMap[group].length; i++) { if (_chartMap[group][i].anchorName() === chart.anchorName()) { _chartMap[group].splice(i, 1); break; } } }, /** * Clear given group if one is provided, otherwise clears all groups. * @method clear * @memberof dc.chartRegistry * @param {String} group Group name */ clear: function (group) { if (group) { delete _chartMap[group]; } else { _chartMap = {}; } }, /** * Get an array of each chart instance in the given group. * If no group is provided, the charts in the default group are returned. * @method list * @memberof dc.chartRegistry * @param {String} [group] Group name * @returns {Array} */ list: function (group) { group = initializeChartGroup(group); return _chartMap[group]; } }; })(); /** * Add given chart instance to the given group, creating the group if necessary. * If no group is provided, the default group `dc.constants.DEFAULT_CHART_GROUP` will be used. * @memberof dc * @method registerChart * @param {Object} chart dc.js chart instance * @param {String} [group] Group name */ dc.registerChart = function (chart, group) { dc.chartRegistry.register(chart, group); }; /** * Remove given chart instance from the given group, creating the group if necessary. * If no group is provided, the default group `dc.constants.DEFAULT_CHART_GROUP` will be used. * @memberof dc * @method deregisterChart * @param {Object} chart dc.js chart instance * @param {String} [group] Group name */ dc.deregisterChart = function (chart, group) { dc.chartRegistry.deregister(chart, group); }; /** * Determine if a given chart instance resides in any group in the registry. * @memberof dc * @method hasChart * @param {Object} chart dc.js chart instance * @returns {Boolean} */ dc.hasChart = function (chart) { return dc.chartRegistry.has(chart); }; /** * Clear given group if one is provided, otherwise clears all groups. * @memberof dc * @method deregisterAllCharts * @param {String} group Group name */ dc.deregisterAllCharts = function (group) { dc.chartRegistry.clear(group); }; /** * Clear all filters on all charts within the given chart group. If the chart group is not given then * only charts that belong to the default chart group will be reset. * @memberof dc * @method filterAll * @param {String} [group] */ dc.filterAll = function (group) { var charts = dc.chartRegistry.list(group); for (var i = 0; i < charts.length; ++i) { charts[i].filterAll(); } }; /** * Reset zoom level / focus on all charts that belong to the given chart group. If the chart group is * not given then only charts that belong to the default chart group will be reset. * @memberof dc * @method refocusAll * @param {String} [group] */ dc.refocusAll = function (group) { var charts = dc.chartRegistry.list(group); for (var i = 0; i < charts.length; ++i) { if (charts[i].focus) { charts[i].focus(); } } }; /** * Re-render all charts belong to the given chart group. If the chart group is not given then only * charts that belong to the default chart group will be re-rendered. * @memberof dc * @method renderAll * @param {String} [group] */ dc.renderAll = function (group) { var charts = dc.chartRegistry.list(group); for (var i = 0; i < charts.length; ++i) { charts[i].render(); } if (dc._renderlet !== null) { dc._renderlet(group); } }; /** * Redraw all charts belong to the given chart group. If the chart group is not given then only charts * that belong to the default chart group will be re-drawn. Redraw is different from re-render since * when redrawing dc tries to update the graphic incrementally, using transitions, instead of starting * from scratch. * @memberof dc * @method redrawAll * @param {String} [group] */ dc.redrawAll = function (group) { var charts = dc.chartRegistry.list(group); for (var i = 0; i < charts.length; ++i) { charts[i].redraw(); } if (dc._renderlet !== null) { dc._renderlet(group); } }; /** * If this boolean is set truthy, all transitions will be disabled, and changes to the charts will happen * immediately * @memberof dc * @method disableTransitions * @type {Boolean} * @default false */ dc.disableTransitions = false; dc.transition = function (selections, duration, callback, name) { if (duration <= 0 || duration === undefined || dc.disableTransitions) { return selections; } var s = selections .transition(name) .duration(duration); if (typeof(callback) === 'function') { callback(s); } return s; }; /* somewhat silly, but to avoid duplicating logic */ dc.optionalTransition = function (enable, duration, callback, name) { if (enable) { return function (selection) { return dc.transition(selection, duration, callback, name); }; } else { return function (selection) { return selection; }; } }; // See http://stackoverflow.com/a/20773846 dc.afterTransition = function (transition, callback) { if (transition.empty() || !transition.duration) { callback.call(transition); } else { var n = 0; transition .each(function () { ++n; }) .each('end', function () { if (!--n) { callback.call(transition); } }); } }; /** * @namespace units * @memberof dc * @type {{}} */ dc.units = {}; /** * The default value for {@link dc.coordinateGridMixin#xUnits .xUnits} for the * {@link dc.coordinateGridMixin Coordinate Grid Chart} and should * be used when the x values are a sequence of integers. * It is a function that counts the number of integers in the range supplied in its start and end parameters. * @method integers * @memberof dc.units * @see {@link dc.coordinateGridMixin#xUnits coordinateGridMixin.xUnits} * @example * chart.xUnits(dc.units.integers) // already the default * @param {Number} start * @param {Number} end * @return {Number} */ dc.units.integers = function (start, end) { return Math.abs(end - start); }; /** * This argument can be passed to the {@link dc.coordinateGridMixin#xUnits .xUnits} function of the to * specify ordinal units for the x axis. Usually this parameter is used in combination with passing * {@link https://github.com/mbostock/d3/wiki/Ordinal-Scales d3.scale.ordinal} to * {@link dc.coordinateGridMixin#x .x}. * It just returns the domain passed to it, which for ordinal charts is an array of all values. * @method ordinal * @memberof dc.units * @see {@link https://github.com/mbostock/d3/wiki/Ordinal-Scales d3.scale.ordinal} * @see {@link dc.coordinateGridMixin#xUnits coordinateGridMixin.xUnits} * @see {@link dc.coordinateGridMixin#x coordinateGridMixin.x} * @example * chart.xUnits(dc.units.ordinal) * .x(d3.scale.ordinal()) * @param {*} start * @param {*} end * @param {Array} domain * @return {Array} */ dc.units.ordinal = function (start, end, domain) { return domain; }; /** * @namespace fp * @memberof dc.units * @type {{}} */ dc.units.fp = {}; /** * This function generates an argument for the {@link dc.coordinateGridMixin Coordinate Grid Chart} * {@link dc.coordinateGridMixin#xUnits .xUnits} function specifying that the x values are floating-point * numbers with the given precision. * The returned function determines how many values at the given precision will fit into the range * supplied in its start and end parameters. * @method precision * @memberof dc.units.fp * @see {@link dc.coordinateGridMixin#xUnits coordinateGridMixin.xUnits} * @example * // specify values (and ticks) every 0.1 units * chart.xUnits(dc.units.fp.precision(0.1) * // there are 500 units between 0.5 and 1 if the precision is 0.001 * var thousandths = dc.units.fp.precision(0.001); * thousandths(0.5, 1.0) // returns 500 * @param {Number} precision * @return {Function} start-end unit function */ dc.units.fp.precision = function (precision) { var _f = function (s, e) { var d = Math.abs((e - s) / _f.resolution); if (dc.utils.isNegligible(d - Math.floor(d))) { return Math.floor(d); } else { return Math.ceil(d); } }; _f.resolution = precision; return _f; }; dc.round = {}; dc.round.floor = function (n) { return Math.floor(n); }; dc.round.ceil = function (n) { return Math.ceil(n); }; dc.round.round = function (n) { return Math.round(n); }; dc.override = function (obj, functionName, newFunction) { var existingFunction = obj[functionName]; obj['_' + functionName] = existingFunction; obj[functionName] = newFunction; }; dc.renderlet = function (_) { if (!arguments.length) { return dc._renderlet; } dc._renderlet = _; return dc; }; dc.instanceOfChart = function (o) { return o instanceof Object && o.__dcFlag__ && true; };