Source: muze-axis/src/scale-creator.js

import { scales, colorSchemes } from 'muze-utils';

import {
    SEQUENTIAL,
    ORDINAL,
    LINEAR,
    CONTINOUS,
    THRESHOLD,
    QUANTIZE
} from './enums/constants';

import * as ScaleType from './enums/scale-type';

const {
    scaleLinear,
    scaleThreshold,
    scaleLog,
    scalePow,
    scaleIdentity,
    scaleOrdinal,
    scaleSequential,
    scaleQuantize,
    scaleQuantile,
    schemeCategory10,
    schemeCategory20,
    schemeCategory20b,
    scaleBand,
    scaleTime
} = scales;
export const scaleMap = {
    [ScaleType.LINEAR]: scaleLinear,
    [ScaleType.BAND]: scaleBand,
    [ScaleType.QUANTIZE]: scaleQuantize,
    [ScaleType.QUANTILE]: scaleQuantile,
    [ScaleType.THRESHOLD]: scaleThreshold,
    [ScaleType.SEQUENTIAL]: scaleSequential,
    [ScaleType.LOG]: scaleLog,
    [ScaleType.POW]: scalePow,
    [ScaleType.IDENTITY]: scaleIdentity,
    [ScaleType.TIME]: scaleTime,
    [ScaleType.COLOR]: scaleLinear,
    [ScaleType.ORDINAL]: scaleOrdinal
};
export const SCHEMES = {
    SCHEME1: schemeCategory10,
    SCHEME2: schemeCategory20,
    SCHEME3: schemeCategory20b
};

/**
 * Accepts a scheme in a string format and returns the scale from d3-scale-chromatic
 *
 * @export
 * @param {string} scheme a string representing the kind of scheme for the color axis
 * @return {Object} The corresponding scale from a scheme type from d3 chromatic scale
 */
export function getScheme (scheme) {
    if (scheme[0] === 'i') {
        return scaleSequential(colorSchemes[scheme]);
    }
    return scaleOrdinal(colorSchemes[scheme]);
}

/**
 *
 *
 * @export
 * @param {*} scheme
 *
 */
export function getSchemeType (scheme) {
    let schemeType = '';
    if (scheme && typeof (scheme) === 'string') {
        schemeType = scheme[0] === 'i' ? SEQUENTIAL : ORDINAL;
    } else {
        schemeType = ORDINAL;
    }
    return schemeType;
}

/**
 * This function is used to create a scale that is assigned to
 * an instance of axis.
 *
 * @export
 * @param {Object} params the input parameters to create a Scale object
 * @param {string} params.type the type of scale
 * @param {Array} params.range the range of scale
 * @return {Object} instance of scale
 */
export function createScale (params) {
    if (!params.type || !scaleMap[params.type]) {
        throw new Error(`${params.type} is not a valid scale type`);
    }
    if (!Array.isArray(params.range)) {
        throw new Error('range parameter must be an array');
    }
    let scaleFactory = null;
    const range = params.range;
    // @todo: do it using scale decorator
    if (params.type === LINEAR && params.interpolator) {
        scaleFactory = scaleMap[params.interpolator];
        if (params.interpolator === ScaleType.POW) {
            return scaleFactory().range(range).exponent(params.exponent);
        } else if (params.interpolator === ScaleType.LOG) {
            return scaleFactory().range(range).base([params.base]);
        }
    } else {
        scaleFactory = scaleMap[params.type];
    }

    if (params.type === QUANTIZE) {
        scaleFactory().nice();
    }
    return scaleFactory().range(range);
}

/**
 * This method is used to update the range of a scale
 * so that the core module can remain agnostic of the d3
 * scale api.
 *
 * @export
 * @param {Scale} scale Instance of d3 Scale.
 * @param {Array} range new range of the scale.
 * @return {Scale} Updated scale.
 */
export function updateScaleRange (scale, range) {
    return scale.range(range);
}

/**
 *
 *
 * @export
 * @param {*} domainType
 * @param {*} rangeType
 * @param {*} steps
 *
 */
export function getScaleType (domainType, rangeType, steps) {
    if (rangeType === CONTINOUS) {
        return LINEAR;
    }
    if (domainType === CONTINOUS) {
        if (steps instanceof Array) {
            return THRESHOLD;
        }
        return QUANTIZE;
    }
    return ORDINAL;
}