// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ // ┃ Copyright (c) 2017, the Perspective Authors. ┃ // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃ // ┃ This file is part of the Perspective library, distributed under the terms ┃ // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ import { Settings } from "../types"; import { splitterLabels } from "./splitterLabels"; export interface AxisSplitter { (selection: any): void; color(): d3.ScaleOrdinal; color(nextColor: d3.ScaleOrdinal): AxisSplitter; haveSplit: () => boolean; data(): any[]; data(nextData: any[]): AxisSplitter; altData(): any[]; altData(nextData: any[]): AxisSplitter; } export const axisSplitter = ( settings: Settings, sourceData, splitFn = dataSplitFunction, ): AxisSplitter => { let color: d3.ScaleOrdinal | undefined = undefined; let data; let altData; // splitMainValues is an array of main-value names to put into the alt-axis const splitMainValues = settings.splitMainValues || []; const altValue = (name) => { const split = name.split("|"); return splitMainValues.includes(split[split.length - 1]); }; const haveSplit: boolean = settings["mainValues"].some((m) => altValue(m.name), ); // Split the data into main and alt displays data = haveSplit ? splitFn(sourceData, (key) => !altValue(key)) : sourceData; altData = haveSplit ? splitFn(sourceData, altValue) : null; // Renderer to show the special controls for moving between axes const splitter: any = (selection) => { if (settings["mainValues"].length === 1) return; const labelsInfo = settings["mainValues"].map((v, i) => ({ index: i, name: v.name, })); const mainLabels = labelsInfo.filter((v) => !altValue(v.name)); const altLabels = labelsInfo.filter((v) => altValue(v.name)); const labeller = () => splitterLabels(settings).color(color); selection .select(".y-label.left-label") .call(labeller().labels(mainLabels)); selection .select(".y-label.right-label") .call(labeller().labels(altLabels).alt(true)); }; splitter.color = (...args: d3.ScaleOrdinal[]): any => { if (!args.length) { return color; } color = args[0]; return splitter; }; splitter.haveSplit = (): boolean => haveSplit; splitter.data = (...args: any[][]): any => { if (!args.length) { return data; } data = args[0]; return splitter; }; splitter.altData = (...args: any[][]): any => { if (!args.length) { return altData; } altData = args[0]; return splitter; }; return splitter; }; export const dataSplitFunction = (sourceData, isIncludedFn) => { return sourceData.map((d) => d.filter((v) => isIncludedFn(v.key))); }; export const dataBlankFunction = (sourceData, isIncludedFn) => { return sourceData.map((series) => { if (!isIncludedFn(series.key)) { // Blank this data return series.map((v) => Object.assign({}, v, { mainValue: null })); } return series; }); }; export const groupedBlankFunction = (sourceData, isIncludedFn) => { return sourceData.map((group) => dataBlankFunction(group, isIncludedFn)); };