LoCs / echarts-5.5.0-rc.2 /src /data /helper /dataStackHelper.ts
ZoeDuan's picture
Upload 1382 files
4bb817b verified
raw
history blame
8.59 kB
/*
* 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;
}