| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import {each, isString} from 'zrender/src/core/util'; |
| import SeriesDimensionDefine from '../SeriesDimensionDefine'; |
| import SeriesModel from '../../model/Series'; |
| import SeriesData, { DataCalculationInfo } from '../SeriesData'; |
| import type { SeriesOption, SeriesStackOptionMixin, DimensionName } from '../../util/types'; |
| import { isSeriesDataSchema, SeriesDataSchema } from './SeriesDataSchema'; |
| import DataStore from '../DataStore'; |
| |
| type EnableDataStackDimensionsInput = { |
| schema: SeriesDataSchema; |
| // If given, stack dimension will be ensured on this store. |
| // Otherwise, stack dimension will be appended at the tail, and should not |
| // be used on a shared store, but should create a brand new storage later. |
| store?: DataStore; |
| }; |
| type EnableDataStackDimensionsInputLegacy = (SeriesDimensionDefine | string)[]; |
| |
| /** |
| * Note that it is too complicated to support 3d stack by value |
| * (have to create two-dimension inverted index), so in 3d case |
| * we just support that stacked by index. |
| * |
| * @param seriesModel |
| * @param dimensionsInput The same as the input of <module:echarts/data/SeriesData>. |
| * The input will be modified. |
| * @param opt |
| * @param opt.stackedCoordDimension Specify a coord dimension if needed. |
| * @param opt.byIndex=false |
| * @return calculationInfo |
| * { |
| * stackedDimension: string |
| * stackedByDimension: string |
| * isStackedByIndex: boolean |
| * stackedOverDimension: string |
| * stackResultDimension: string |
| * } |
| */ |
| export function enableDataStack( |
| seriesModel: SeriesModel<SeriesOption & SeriesStackOptionMixin>, |
| dimensionsInput: EnableDataStackDimensionsInput | EnableDataStackDimensionsInputLegacy, |
| opt?: { |
| // Backward compat |
| stackedCoordDimension?: string |
| byIndex?: boolean |
| } |
| ): Pick< |
| DataCalculationInfo<unknown>, |
| 'stackedDimension' |
| | 'stackedByDimension' |
| | 'isStackedByIndex' |
| | 'stackedOverDimension' |
| | 'stackResultDimension' |
| > { |
| opt = opt || {}; |
| let byIndex = opt.byIndex; |
| const stackedCoordDimension = opt.stackedCoordDimension; |
| |
| let dimensionDefineList: EnableDataStackDimensionsInputLegacy; |
| let schema: SeriesDataSchema; |
| let store: DataStore; |
| |
| if (isLegacyDimensionsInput(dimensionsInput)) { |
| dimensionDefineList = dimensionsInput; |
| } |
| else { |
| schema = dimensionsInput.schema; |
| dimensionDefineList = schema.dimensions; |
| store = dimensionsInput.store; |
| } |
| |
| // Compatibal: when `stack` is set as '', do not stack. |
| const mayStack = !!(seriesModel && seriesModel.get('stack')); |
| let stackedByDimInfo: SeriesDimensionDefine; |
| let stackedDimInfo: SeriesDimensionDefine; |
| let stackResultDimension: string; |
| let stackedOverDimension: string; |
| |
| each(dimensionDefineList, function (dimensionInfo, index) { |
| if (isString(dimensionInfo)) { |
| dimensionDefineList[index] = dimensionInfo = { |
| name: dimensionInfo as string |
| } as SeriesDimensionDefine; |
| } |
| |
| if (mayStack && !dimensionInfo.isExtraCoord) { |
| // Find the first ordinal dimension as the stackedByDimInfo. |
| if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) { |
| stackedByDimInfo = dimensionInfo; |
| } |
| // Find the first stackable dimension as the stackedDimInfo. |
| if (!stackedDimInfo |
| && dimensionInfo.type !== 'ordinal' |
| && dimensionInfo.type !== 'time' |
| && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim) |
| ) { |
| stackedDimInfo = dimensionInfo; |
| } |
| } |
| }); |
| |
| if (stackedDimInfo && !byIndex && !stackedByDimInfo) { |
| // Compatible with previous design, value axis (time axis) only stack by index. |
| // It may make sense if the user provides elaborately constructed data. |
| byIndex = true; |
| } |
| |
| // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`. |
| // That put stack logic in List is for using conveniently in echarts extensions, but it |
| // might not be a good way. |
| if (stackedDimInfo) { |
| // Use a weird name that not duplicated with other names. |
| // Also need to use seriesModel.id as postfix because different |
| // series may share same data store. The stack dimension needs to be distinguished. |
| stackResultDimension = '__\0ecstackresult_' + seriesModel.id; |
| stackedOverDimension = '__\0ecstackedover_' + seriesModel.id; |
| |
| // Create inverted index to fast query index by value. |
| if (stackedByDimInfo) { |
| stackedByDimInfo.createInvertedIndices = true; |
| } |
| |
| const stackedDimCoordDim = stackedDimInfo.coordDim; |
| const stackedDimType = stackedDimInfo.type; |
| let stackedDimCoordIndex = 0; |
| |
| each(dimensionDefineList, function (dimensionInfo: SeriesDimensionDefine) { |
| if (dimensionInfo.coordDim === stackedDimCoordDim) { |
| stackedDimCoordIndex++; |
| } |
| }); |
| |
| const stackedOverDimensionDefine: SeriesDimensionDefine = { |
| name: stackResultDimension, |
| coordDim: stackedDimCoordDim, |
| coordDimIndex: stackedDimCoordIndex, |
| type: stackedDimType, |
| isExtraCoord: true, |
| isCalculationCoord: true, |
| storeDimIndex: dimensionDefineList.length |
| }; |
| |
| const stackResultDimensionDefine: SeriesDimensionDefine = { |
| name: stackedOverDimension, |
| // This dimension contains stack base (generally, 0), so do not set it as |
| // `stackedDimCoordDim` to avoid extent calculation, consider log scale. |
| coordDim: stackedOverDimension, |
| coordDimIndex: stackedDimCoordIndex + 1, |
| type: stackedDimType, |
| isExtraCoord: true, |
| isCalculationCoord: true, |
| storeDimIndex: dimensionDefineList.length + 1 |
| }; |
| |
| if (schema) { |
| if (store) { |
| stackedOverDimensionDefine.storeDimIndex = |
| store.ensureCalculationDimension(stackedOverDimension, stackedDimType); |
| stackResultDimensionDefine.storeDimIndex = |
| store.ensureCalculationDimension(stackResultDimension, stackedDimType); |
| } |
| |
| schema.appendCalculationDimension(stackedOverDimensionDefine); |
| schema.appendCalculationDimension(stackResultDimensionDefine); |
| } |
| else { |
| dimensionDefineList.push(stackedOverDimensionDefine); |
| dimensionDefineList.push(stackResultDimensionDefine); |
| } |
| } |
| |
| return { |
| stackedDimension: stackedDimInfo && stackedDimInfo.name, |
| stackedByDimension: stackedByDimInfo && stackedByDimInfo.name, |
| isStackedByIndex: byIndex, |
| stackedOverDimension: stackedOverDimension, |
| stackResultDimension: stackResultDimension |
| }; |
| } |
| |
| function isLegacyDimensionsInput( |
| dimensionsInput: Parameters<typeof enableDataStack>[1] |
| ): dimensionsInput is EnableDataStackDimensionsInputLegacy { |
| return !isSeriesDataSchema((dimensionsInput as EnableDataStackDimensionsInput).schema); |
| } |
| |
| export function isDimensionStacked(data: SeriesData, stackedDim: string): boolean { |
| // Each single series only maps to one pair of axis. So we do not need to |
| // check stackByDim, whatever stacked by a dimension or stacked by index. |
| return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension'); |
| } |
| |
| export function getStackedDimension(data: SeriesData, targetDim: string): DimensionName { |
| return isDimensionStacked(data, targetDim) |
| ? data.getCalculationInfo('stackResultDimension') |
| : targetDim; |
| } |