nagix/chartjs-plugin-datasource

View on GitHub
src/datasources/datasource.json.js

Summary

Maintainability
D
2 days
Test Coverage
'use strict';

import Chart from 'chart.js';
import DataSource from '../core/core.datasource';
import datasourceHelpers from '../helpers/helpers.datasource';

var helpers = Chart.helpers;

function query(obj, expr) {
    var regex = /(?:,|^)\s*(?:"([^"]*)"|'([^']*)'|([^,\s]*))/gi;
    var result = [];
    var matches, bracketKey, dotKey, nextExprWithDot, nextExpr, quotedKey, subset, i, ilen, keys;

    if (obj === undefined || expr === undefined) {
        return obj;
    }

    // Allow up to two levels of [] nesting
    matches = expr.match(/(?:\[((?:\[[^\]]*\]|[^\]])*)\]|([^.[]*))(\.?(.*))/);
    if (!matches) {
        return;
    }
    bracketKey = matches[1];
    dotKey = matches[2];
    nextExprWithDot = matches[3];
    nextExpr = nextExprWithDot ? matches[4] : undefined;

    // If the wildcard is used, return an array
    if (dotKey === '*' || bracketKey === '*') {
        if (helpers.isArray(obj)) {
            for (i = 0, ilen = obj.length; i < ilen; ++i) {
                result.push(query(obj[i], nextExpr));
            }
        } else if (datasourceHelpers.isObject(obj)) {
            keys = result._labels = Object.keys(obj);
            for (i = 0, ilen = keys.length; i < ilen; ++i) {
                result.push(query(obj[keys[i]], nextExpr));
            }
        }
        return result;
    }

    // If the dot notation is used, return a single value
    if (dotKey !== undefined) {
        return query(obj[dotKey], nextExpr);
    }

    // If the bracket notation is used, process the list and return an array or a single value
    keys = result._labels = [];
    while ((matches = regex.exec(bracketKey))) {
        quotedKey = datasourceHelpers.valueOrDefault(matches[1], matches[2]);
        if (quotedKey !== undefined) {
            subset = query(obj[quotedKey], nextExpr);
        } else {
            subset = query(obj, matches[3] + nextExprWithDot);
        }
        result.push(subset);
        keys.push(datasourceHelpers.valueOrDefault(quotedKey, matches[3]));
    }
    return result.length > 1 ? result : result[0];
}

function getSecondLevelLabels(data) {
    var dataLen = data.length;
    var array = [];
    var newArray, labels, labelLen, i, j;

    for (i = 0; i < dataLen; ++i) {
        Array.prototype.push.apply(array, data[i]._labels);
    }
    labels = datasourceHelpers.dedup(array);
    labelLen = labels.length;
    for (i = 0; i < dataLen; ++i) {
        array = data[i];
        newArray = [];
        for (j = 0; j < labelLen; ++j) {
            newArray.push(array[array._labels.indexOf(labels[j])]);
        }
        data[i] = newArray;
    }
    return labels;
}

function getLabels(arrays, value) {
    var result = [];
    var array, labels, i, ilen;

    for (i = 0, ilen = arrays.length; i < ilen; ++i) {
        array = arrays[i];
        labels = array._labels;
        result.push(arrays[i][labels ? labels.indexOf(value) : value]);
    }
    return datasourceHelpers.dedup(result);
}

function getPointData(arrays, datasetLabels, datapointLabelMapping) {
    var keys = Object.keys(datapointLabelMapping);
    var datapointLabelLookup = {};
    var datasetLabelLookup = {};
    var result = [];
    var array, labels, obj, key, datapointLabel, datapointValue, i, j, ilen, jlen;

    for (i = 0, ilen = keys.length; i < ilen; ++i) {
        key = keys[i];
        if (key !== '_index') {
            datapointLabelLookup[datapointLabelMapping[key]] = key;
        }
    }
    for (i = 0, ilen = datasetLabels.length; i < ilen; ++i) {
        datasetLabelLookup[datasetLabels[i]] = i;
        result[i] = [];
    }
    for (i = 0, ilen = arrays.length; i < ilen; ++i) {
        array = arrays[i];
        labels = array._labels;
        obj = {};
        for (j = 0, jlen = array.length; j < jlen; ++j) {
            key = labels ? labels[j] : j;
            datapointLabel = datasourceHelpers.valueOrDefault(datapointLabelLookup[key], key);
            datapointValue = array[j];
            if (datapointLabel === '_dataset') {
                result[datasetLabelLookup[datapointValue]].push(obj);
            } else {
                obj[datapointLabel] = datapointValue;
            }
        }
    }
    return result;
}

var JsonDataSource = DataSource.extend({
    _defaultConfig: {
        type: 'json',
        rowMapping: 'dataset',
        datapointLabelMapping: {
            _dataset: '_dataset',
            _index: 'x'
        }
    },

    _responseType: 'json',

    convert: function(input) {
        var me = this;
        var options = me._options;
        var datasets = [];
        var datasetLabels, indexLabels, data, arrays, i, ilen;

        if (options.data) {
            arrays = query(input, options.data);
        }

        switch (options.rowMapping) {
        default:
            if (options.datasetLabels) {
                datasetLabels = query(input, options.datasetLabels);
            } else if (arrays) {
                datasetLabels = arrays._labels;
            }
            if (options.indexLabels) {
                indexLabels = query(input, options.indexLabels);
            } else if (arrays) {
                indexLabels = getSecondLevelLabels(arrays);
            }
            data = arrays;
            break;
        case 'index':
            if (options.datasetLabels) {
                datasetLabels = query(input, options.datasetLabels);
            } else if (arrays) {
                datasetLabels = getSecondLevelLabels(arrays);
            }
            if (options.indexLabels) {
                indexLabels = query(input, options.indexLabels);
            } else if (arrays) {
                indexLabels = arrays._labels;
            }
            if (arrays) {
                data = datasourceHelpers.transpose(arrays);
            }
            break;
        case 'datapoint':
            if (arrays) {
                datasetLabels = getLabels(arrays, options.datapointLabelMapping._dataset);
                indexLabels = getLabels(arrays, options.datapointLabelMapping._index);
                data = getPointData(arrays, datasetLabels, options.datapointLabelMapping);
            }
            break;
        }

        datasetLabels = datasetLabels || [];
        data = data || [];
        for (i = 0, ilen = Math.max(datasetLabels.length, data.length); i < ilen; ++i) {
            datasets.push({
                label: datasetLabels[i],
                data: data[i]
            });
        }

        return {
            labels: indexLabels,
            datasets: datasets
        };
    }
});

JsonDataSource._extensions = ['json'];

export default JsonDataSource;