nagix/chartjs-plugin-colorschemes

View on GitHub
src/plugins/plugin.colorschemes.js

Summary

Maintainability
D
1 day
Test Coverage
B
83%
'use strict';

import Chart from 'chart.js';

var helpers = Chart.helpers;

// Element models are always reset when hovering in Chart.js 2.7.2 or earlier
var hoverReset = Chart.DatasetController.prototype.removeHoverStyle.length === 2;

var EXPANDO_KEY = '$colorschemes';

// pluginBase snippet fixes the chartjs 3 incompatibility, and is backwards-compatible
// by Github user gebrits (https://github.com/gebrits/chartjs-plugin-colorschemes)
//
// Chartjs 2 => Chart.defaults.global
// Chartjs 3 => Chart.defaults
const pluginBase = Chart.defaults.global || Chart.defaults;
pluginBase.plugins.colorschemes = {
    scheme: 'brewer.Paired12',
    fillAlpha: 0.5,
    reverse: false,
    override: false
};

function getScheme(scheme) {
    var colorschemes, matches, arr, category;

    if (helpers.isArray(scheme)) {
        return scheme;
    } else if (typeof scheme === 'string') {
        colorschemes = Chart.colorschemes || {};

        // For backward compatibility
        matches = scheme.match(/^(brewer\.\w+)([1-3])-(\d+)$/);
        if (matches) {
            scheme = matches[1] + ['One', 'Two', 'Three'][matches[2] - 1] + matches[3];
        } else if (scheme === 'office.Office2007-2010-6') {
            scheme = 'office.OfficeClassic6';
        }

        arr = scheme.split('.');
        category = colorschemes[arr[0]];
        if (category) {
            return category[arr[1]];
        }
    }
}

var ColorSchemesPlugin = {
    id: 'colorschemes',

    beforeUpdate: function(chart, args, options) {
        // Please note that in v3, the args argument was added. It was not used before it was added,
        // so we just check if it is not actually our options object
        if (options === undefined) {
            options = args;
        }

        var scheme = getScheme(options.scheme);
        var fillAlpha = options.fillAlpha;
        var reverse = options.reverse;
        var override = options.override;
        var custom = options.custom;
        var schemeClone, customResult, length, colorIndex, color;

        if (scheme) {

            if (typeof custom === 'function') {
                // clone the original scheme
                schemeClone = scheme.slice();

                // Execute own custom color function
                customResult = custom(schemeClone);

                // check if we really received a filled array; otherwise we keep and use the original scheme
                if (helpers.isArray(customResult) && customResult.length) {
                    scheme = customResult;
                } else if (helpers.isArray(schemeClone) && schemeClone.length) {
                    scheme = schemeClone;
                }
            }

            length = scheme.length;

            // Set scheme colors
            chart.config.data.datasets.forEach(function(dataset, datasetIndex) {
                colorIndex = datasetIndex % length;
                color = scheme[reverse ? length - colorIndex - 1 : colorIndex];

                // Object to store which color option is set
                dataset[EXPANDO_KEY] = {};

                switch (dataset.type || chart.config.type) {
                // For line, radar and scatter chart, borderColor and backgroundColor (50% transparent) are set
                case 'line':
                case 'radar':
                case 'scatter':
                    if (typeof dataset.backgroundColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].backgroundColor = dataset.backgroundColor;
                        dataset.backgroundColor = helpers.color(color).alpha(fillAlpha).rgbString();
                    }
                    if (typeof dataset.borderColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].borderColor = dataset.borderColor;
                        dataset.borderColor = color;
                    }
                    if (typeof dataset.pointBackgroundColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].pointBackgroundColor = dataset.pointBackgroundColor;
                        dataset.pointBackgroundColor = helpers.color(color).alpha(fillAlpha).rgbString();
                    }
                    if (typeof dataset.pointBorderColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].pointBorderColor = dataset.pointBorderColor;
                        dataset.pointBorderColor = color;
                    }
                    break;
                // For doughnut and pie chart, backgroundColor is set to an array of colors
                case 'doughnut':
                case 'pie':
                case 'polarArea':
                    if (typeof dataset.backgroundColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].backgroundColor = dataset.backgroundColor;
                        dataset.backgroundColor = dataset.data.map(function(data, dataIndex) {
                            colorIndex = dataIndex % length;
                            return scheme[reverse ? length - colorIndex - 1 : colorIndex];
                        });
                    }
                    break;
                // For bar chart backgroundColor (including fillAlpha) and borderColor are set
                case 'bar':
                    if (typeof dataset.backgroundColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].backgroundColor = dataset.backgroundColor;
                        dataset.backgroundColor = helpers.color(color).alpha(fillAlpha).rgbString();
                    }
                    if (typeof dataset.borderColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].borderColor = dataset.borderColor;
                        dataset.borderColor = color;
                    }
                    break;
                // For the other chart, only backgroundColor is set
                default:
                    if (typeof dataset.backgroundColor === 'undefined' || override) {
                        dataset[EXPANDO_KEY].backgroundColor = dataset.backgroundColor;
                        dataset.backgroundColor = color;
                    }
                    break;
                }
            });
        }
    },

    afterUpdate: function(chart) {
        // Unset colors
        chart.config.data.datasets.forEach(function(dataset) {
            if (dataset[EXPANDO_KEY]) {
                if (dataset[EXPANDO_KEY].hasOwnProperty('backgroundColor')) {
                    dataset.backgroundColor = dataset[EXPANDO_KEY].backgroundColor;
                }
                if (dataset[EXPANDO_KEY].hasOwnProperty('borderColor')) {
                    dataset.borderColor = dataset[EXPANDO_KEY].borderColor;
                }
                if (dataset[EXPANDO_KEY].hasOwnProperty('pointBackgroundColor')) {
                    dataset.pointBackgroundColor = dataset[EXPANDO_KEY].pointBackgroundColor;
                }
                if (dataset[EXPANDO_KEY].hasOwnProperty('pointBorderColor')) {
                    dataset.pointBorderColor = dataset[EXPANDO_KEY].pointBorderColor;
                }
                delete dataset[EXPANDO_KEY];
            }
        });
    },

    beforeEvent: function(chart, event, options) {
        if (hoverReset) {
            this.beforeUpdate(chart, options);
        }
    },

    afterEvent: function(chart) {
        if (hoverReset) {
            this.afterUpdate(chart);
        }
    }
};

Chart.plugins.register(ColorSchemesPlugin);

export default ColorSchemesPlugin;