Source: visual-group/src/encoder/encoder-helper.js

import { mergeRecursive } from 'muze-utils';
import { AxisOrientation } from '@chartshq/muze-axis';
import { scaleMaps } from '../enums/scale-maps';
import { getAxisType, getAxisKey } from '../group-helper';
import { dataTypeScaleMap } from '../data-type-scale-map';
import { CATEGORICAL, TEMPORAL, BAR, LINE, POINT, BOTH, Y } from '../enums/constants';

/**
 *
 *
 * @param {*} axisInfo
 * @param {*} field
 * @param {*} axesCreators
 *
 */
const getAxisConfig = (axisInfo, field, axesCreators) => {
    let axisOrientation;
    const { index, axisIndex, axisType } = axisInfo;
    const { config, position } = axesCreators;
    const userAxisConfig = config.axes ? (config.axes[axisType] || {}) : {};
    const {
        LEFT,
        RIGHT,
        TOP,
        BOTTOM
    } = AxisOrientation;
    const allOrientations = axisType === Y ? [LEFT, RIGHT] : [TOP, BOTTOM];

    if (position === BOTH) {
        axisOrientation = allOrientations[axisIndex];
    } else {
        axisOrientation = position;
    }
    const axisConfig = {
        id: `${axisType}-${index}-${axisIndex}`,
        name: field.toString(),
        field: field.toString(),
        labels: { rotation: 0 },
        numberFormat: field.numberFormat(),
        orientation: axisOrientation,
        type: dataTypeScaleMap[field.subtype()]
    };
    userAxisConfig.tickValues = field.format(userAxisConfig.tickValues);
    userAxisConfig.domain = field.format(userAxisConfig.domain);

    return mergeRecursive(axisConfig, userAxisConfig);
};

/**
 *
 *
 * @param {*} axisInfo
 * @param {*} field
 * @param {*} axesCreators
 *
 */
const createSimpleAxis = (axisConfig, field, axesCreators) => {
    const { labelManager } = axesCreators;
    const Cls = scaleMaps[dataTypeScaleMap[field.subtype()]];
    const simpleAxis = new Cls(axisConfig, { labelManager });
    return simpleAxis;
};

/**
 *
 *
 * @param {*} axisType
 * @param {*} fieldInfo
 * @param {*} axesCreators
 * @param {*} groupAxes
 *
 */
export const generateAxisFromMap = (axisType, fieldInfo, axesCreators, groupAxes) => {
    let axisKey;
    const currentAxes = [];
    const { fields, index } = fieldInfo;
    const { cacheMaps } = axesCreators;
    const map = cacheMaps[`${axisType}AxesMap`];

    fields.forEach((field, axisIndex) => {
        axisKey = getAxisKey(axisType, index, dataTypeScaleMap[field.subtype()]);
        const axisConfig = getAxisConfig({ index, axisIndex, axisType }, field, axesCreators);

        if (!map.has(axisKey)) {
            const xAxis = createSimpleAxis(axisConfig, field, axesCreators);
            currentAxes.push(xAxis);
        } else {
            const axes = map.get(axisKey);
            axes[axisIndex] = axes[axisIndex] ? axes[axisIndex] : createSimpleAxis(axisConfig, field, axesCreators);
            axes[axisIndex]._rotationLock = false;
            axes[axisIndex] && axes[axisIndex].config(axisConfig).domain(axisConfig.domain || []);
        }
    });

    if (currentAxes.length) {
        map.set(axisKey, currentAxes);
    }

    for (const [key] of map.entries()) {
        if (key === axisKey) {
            groupAxes.add(axisKey);
        }
    }
    return map.get(axisKey);
};

/**
 *
 *
 * @memberof MatrixResolver
 */
export const mutateAxesFromMap = (cacheMaps, axes) => {
    const {
        xAxesMap,
        yAxesMap
    } = cacheMaps;
    const {
        x: xAxisSet,
        y: yAxisSet
    } = axes;
    const xAxes = [];
    const yAxes = [];

    xAxisSet.forEach((axisId) => {
        const xAxis = xAxesMap.get(axisId);
        xAxes.push(xAxis);
    });
    yAxisSet.forEach((axisId) => {
        const yAxis = yAxesMap.get(axisId);
        yAxes.push(yAxis);
    });
    return {
        xAxes, yAxes
    };
};

/**
 * return a default mark based on predefined set of rules of type and subtype of the fields
 *
 * @param {string} colFieldType dimension/measure - temporal/ordinal/nominal
 * @param {string} rowFieldType dimension/measure - temporal/ordinal/nominal
 * @return {Object} return mark type
 */
export const getDefaultMark = (colFieldType, rowFieldType) => {
    let mark;

    if (colFieldType === CATEGORICAL || rowFieldType === CATEGORICAL) {
        mark = BAR;
    } else if (colFieldType === TEMPORAL || rowFieldType === TEMPORAL) {
        mark = LINE;
    } else {
        mark = POINT;
    }

    return mark;
};

/**
 *
 *
 * @param {*} axesCreators
 * @param {*} [fieldInfo=[]]
 *
 */
export const createRetinalAxis = (axesCreators, fieldProps = {}) => {
    const { axisType, fieldsConfig } = axesCreators;
    const field = fieldProps.field;
    const axis = [];
    const Cls = scaleMaps[axisType];

    fieldProps.type = fieldProps.type ? fieldProps.type : getAxisType(fieldsConfig, field || null);
    axis.push(new Cls(fieldProps));
    return axis;
};

/**
 *
 *
 * @param {*} arr
 * @param {*} val
 *
 */
export const getIndex = (arr, val) => {
    let i = 0;
    let arrIndex = -1;

    while (arrIndex === -1 && i < arr.length) {
        if (arr[i].toString() === val.toString()) {
            arrIndex = i;
        }
        i++;
    }
    return arrIndex;
};

/**
 *
 *
 * @param {*} colFields
 * @param {*} rowFields
 * @param {*} userLayerConfig
 *
 * @memberof CartesianEncoder
 */
export const getLayerConfFromFields = (colFields, rowFields, userLayerConfig) => userLayerConfig.filter((conf) => {
    const userConf = conf instanceof Array ? conf : [conf];
    const encodingArr = [].concat(...userConf.map(d => d.encoding).filter(d => d !== undefined));

    if (!encodingArr.length) {
        return true;
    }

    const xFields = [].concat(...encodingArr.map(d => [d.x && d.x.field, d.x0 && d.x0.field]))
                .filter(d => d !== undefined && d !== null);
    const yFields = [].concat(...encodingArr.map(d => [d.y && d.y.field, d.y0 && d.y0.field]))
                .filter(d => d !== undefined && d !== null);

    if (!xFields.length && !yFields.length) {
        return true;
    }

    const colFieldExist = xFields.length ? xFields.every(d => colFields.indexOf(d) !== -1) : false;
    const rowFieldExist = yFields.length ? yFields.every(d => rowFields.indexOf(d) !== -1) : false;
    if (xFields.length && yFields.length) {
        return colFieldExist && rowFieldExist;
    }
    return colFieldExist || rowFieldExist;
});