Source: core/chart-registry.js

import {constants} from './constants';
import {config} from './config';

/**
 * The ChartRegistry maintains sets of all instantiated dc.js charts under named groups
 * and the default group. There is a single global ChartRegistry object named `chartRegistry`
 *
 * 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 filterAll filterAll}, {@link refocusAll refocusAll},
 * {@link renderAll renderAll}, {@link redrawAll redrawAll}, or chart functions
 * {@link baseMixin#renderGroup baseMixin.renderGroup},
 * {@link baseMixin#redrawGroup baseMixin.redrawGroup} are called.
 */
class ChartRegistry {
    constructor () {
        // chartGroup:string => charts:array
        this._chartMap = {};
    }

    _initializeChartGroup (group) {
        if (!group) {
            group = constants.DEFAULT_CHART_GROUP;
        }

        if (!(this._chartMap)[group]) {
            (this._chartMap)[group] = [];
        }

        return group;
    }

    /**
     * Determine if a given chart instance resides in any group in the registry.
     * @param {Object} chart dc.js chart instance
     * @returns {Boolean}
     */
    has (chart) {
        for (const e in this._chartMap) {
            if ((this._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 `constants.DEFAULT_CHART_GROUP` will be used.
     * @param {Object} chart dc.js chart instance
     * @param {String} [group] Group name
     * @return {undefined}
     */
    register (chart, group) {
        const _chartMap = this._chartMap;
        group = this._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 `constants.DEFAULT_CHART_GROUP` will be used.
     * @param {Object} chart dc.js chart instance
     * @param {String} [group] Group name
     * @return {undefined}
     */
    deregister (chart, group) {
        group = this._initializeChartGroup(group);
        for (let i = 0; i < (this._chartMap)[group].length; i++) {
            if ((this._chartMap)[group][i].anchorName() === chart.anchorName()) {
                (this._chartMap)[group].splice(i, 1);
                break;
            }
        }
    }

    /**
     * Clear given group if one is provided, otherwise clears all groups.
     * @param {String} group Group name
     * @return {undefined}
     */
    clear (group) {
        if (group) {
            delete (this._chartMap)[group];
        } else {
            this._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.
     * @param {String} [group] Group name
     * @returns {Array<Object>}
     */
    list (group) {
        group = this._initializeChartGroup(group);
        return (this._chartMap)[group];
    }
}

/**
 * The chartRegistry object maintains sets of all instantiated dc.js charts under named groups
 * and the default group. See {@link ChartRegistry ChartRegistry} for its methods.
 */
export const chartRegistry = new ChartRegistry();

/**
 * Add given chart instance to the given group, creating the group if necessary.
 * If no group is provided, the default group `constants.DEFAULT_CHART_GROUP` will be used.
 * @function registerChart
 * @param {Object} chart dc.js chart instance
 * @param {String} [group] Group name
 * @return {undefined}
 */
export const registerChart = function (chart, group) {
    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 `constants.DEFAULT_CHART_GROUP` will be used.
 * @function deregisterChart
 * @param {Object} chart dc.js chart instance
 * @param {String} [group] Group name
 * @return {undefined}
 */
export const deregisterChart = function (chart, group) {
    chartRegistry.deregister(chart, group);
};

/**
 * Determine if a given chart instance resides in any group in the registry.
 * @function hasChart
 * @param {Object} chart dc.js chart instance
 * @returns {Boolean}
 */
export const hasChart = function (chart) {
    return chartRegistry.has(chart);
};

/**
 * Clear given group if one is provided, otherwise clears all groups.
 * @function deregisterAllCharts
 * @param {String} group Group name
 * @return {undefined}
 */
export const deregisterAllCharts = function (group) {
    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.
 * @function filterAll
 * @param {String} [group]
 * @return {undefined}
 */
export const filterAll = function (group) {
    const charts = chartRegistry.list(group);
    for (let 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.
 * @function refocusAll
 * @param {String} [group]
 * @return {undefined}
 */
export const refocusAll = function (group) {
    const charts = chartRegistry.list(group);
    for (let 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.
 * @function renderAll
 * @param {String} [group]
 * @return {undefined}
 */
export const renderAll = function (group) {
    const charts = chartRegistry.list(group);
    for (let i = 0; i < charts.length; ++i) {
        charts[i].render();
    }

    if (config._renderlet !== null) {
        config._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.
 * @function redrawAll
 * @param {String} [group]
 * @return {undefined}
 */
export const redrawAll = function (group) {
    const charts = chartRegistry.list(group);
    for (let i = 0; i < charts.length; ++i) {
        charts[i].redraw();
    }

    if (config._renderlet !== null) {
        config._renderlet(group);
    }
};