Spaces:
Running
Running
/* | |
* 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, createHashMap, assert, map} from 'zrender/src/core/util'; | |
import SeriesData from '../SeriesData'; | |
import { | |
DimensionName, VISUAL_DIMENSIONS, DimensionType, DimensionIndex | |
} from '../../util/types'; | |
import { DataStoreDimensionType } from '../DataStore'; | |
import { SeriesDataSchema } from './SeriesDataSchema'; | |
export type DimensionSummaryEncode = { | |
defaultedLabel: DimensionName[], | |
defaultedTooltip: DimensionName[], | |
[coordOrVisualDimName: string]: | |
// index: coordDimIndex, value: dataDimName | |
DimensionName[] | |
}; | |
export type DimensionSummary = { | |
encode: DimensionSummaryEncode, | |
// Those details that can be expose to users are put int `userOutput`. | |
userOutput: DimensionUserOuput, | |
// All of the data dim names that mapped by coordDim. | |
dataDimsOnCoord: DimensionName[], | |
dataDimIndicesOnCoord: DimensionIndex[], | |
encodeFirstDimNotExtra: {[coordDim: string]: DimensionName}, | |
}; | |
export type DimensionUserOuputEncode = { | |
// index: coordDimIndex, value: dataDimIndex | |
[coordOrVisualDimName: string]: DimensionIndex[] | |
}; | |
class DimensionUserOuput { | |
private _encode: DimensionUserOuputEncode; | |
private _cachedDimNames: DimensionName[]; | |
private _schema?: SeriesDataSchema; | |
constructor( | |
encode: DimensionUserOuputEncode, | |
dimRequest?: SeriesDataSchema | |
) { | |
this._encode = encode; | |
this._schema = dimRequest; | |
} | |
get(): { | |
fullDimensions: DimensionName[]; | |
encode: DimensionUserOuputEncode; | |
} { | |
return { | |
// Do not generate full dimension name until fist used. | |
fullDimensions: this._getFullDimensionNames(), | |
encode: this._encode | |
}; | |
} | |
/** | |
* Get all data store dimension names. | |
* Theoretically a series data store is defined both by series and used dataset (if any). | |
* If some dimensions are omitted for performance reason in `this.dimensions`, | |
* the dimension name may not be auto-generated if user does not specify a dimension name. | |
* In this case, the dimension name is `null`/`undefined`. | |
*/ | |
private _getFullDimensionNames(): DimensionName[] { | |
if (!this._cachedDimNames) { | |
this._cachedDimNames = this._schema | |
? this._schema.makeOutputDimensionNames() | |
: []; | |
} | |
return this._cachedDimNames; | |
} | |
}; | |
export function summarizeDimensions( | |
data: SeriesData, | |
schema?: SeriesDataSchema | |
): DimensionSummary { | |
const summary: DimensionSummary = {} as DimensionSummary; | |
const encode = summary.encode = {} as DimensionSummaryEncode; | |
const notExtraCoordDimMap = createHashMap<1, DimensionName>(); | |
let defaultedLabel = [] as DimensionName[]; | |
let defaultedTooltip = [] as DimensionName[]; | |
const userOutputEncode = {} as DimensionUserOuputEncode; | |
each(data.dimensions, function (dimName) { | |
const dimItem = data.getDimensionInfo(dimName); | |
const coordDim = dimItem.coordDim; | |
if (coordDim) { | |
if (__DEV__) { | |
assert(VISUAL_DIMENSIONS.get(coordDim as any) == null); | |
} | |
const coordDimIndex = dimItem.coordDimIndex; | |
getOrCreateEncodeArr(encode, coordDim)[coordDimIndex] = dimName; | |
if (!dimItem.isExtraCoord) { | |
notExtraCoordDimMap.set(coordDim, 1); | |
// Use the last coord dim (and label friendly) as default label, | |
// because when dataset is used, it is hard to guess which dimension | |
// can be value dimension. If both show x, y on label is not look good, | |
// and conventionally y axis is focused more. | |
if (mayLabelDimType(dimItem.type)) { | |
defaultedLabel[0] = dimName; | |
} | |
// User output encode do not contain generated coords. | |
// And it only has index. User can use index to retrieve value from the raw item array. | |
getOrCreateEncodeArr(userOutputEncode, coordDim)[coordDimIndex] = | |
data.getDimensionIndex(dimItem.name); | |
} | |
if (dimItem.defaultTooltip) { | |
defaultedTooltip.push(dimName); | |
} | |
} | |
VISUAL_DIMENSIONS.each(function (v, otherDim) { | |
const encodeArr = getOrCreateEncodeArr(encode, otherDim); | |
const dimIndex = dimItem.otherDims[otherDim]; | |
if (dimIndex != null && dimIndex !== false) { | |
encodeArr[dimIndex] = dimItem.name; | |
} | |
}); | |
}); | |
let dataDimsOnCoord = [] as DimensionName[]; | |
const encodeFirstDimNotExtra = {} as {[coordDim: string]: DimensionName}; | |
notExtraCoordDimMap.each(function (v, coordDim) { | |
const dimArr = encode[coordDim]; | |
encodeFirstDimNotExtra[coordDim] = dimArr[0]; | |
// Not necessary to remove duplicate, because a data | |
// dim canot on more than one coordDim. | |
dataDimsOnCoord = dataDimsOnCoord.concat(dimArr); | |
}); | |
summary.dataDimsOnCoord = dataDimsOnCoord; | |
summary.dataDimIndicesOnCoord = map( | |
dataDimsOnCoord, dimName => data.getDimensionInfo(dimName).storeDimIndex | |
); | |
summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra; | |
const encodeLabel = encode.label; | |
// FIXME `encode.label` is not recommended, because formatter cannot be set | |
// in this way. Use label.formatter instead. Maybe remove this approach someday. | |
if (encodeLabel && encodeLabel.length) { | |
defaultedLabel = encodeLabel.slice(); | |
} | |
const encodeTooltip = encode.tooltip; | |
if (encodeTooltip && encodeTooltip.length) { | |
defaultedTooltip = encodeTooltip.slice(); | |
} | |
else if (!defaultedTooltip.length) { | |
defaultedTooltip = defaultedLabel.slice(); | |
} | |
encode.defaultedLabel = defaultedLabel; | |
encode.defaultedTooltip = defaultedTooltip; | |
summary.userOutput = new DimensionUserOuput(userOutputEncode, schema); | |
return summary; | |
} | |
function getOrCreateEncodeArr( | |
encode: DimensionSummaryEncode | DimensionUserOuputEncode, dim: DimensionName | |
): (DimensionIndex | DimensionName)[] { | |
if (!encode.hasOwnProperty(dim)) { | |
encode[dim] = []; | |
} | |
return encode[dim]; | |
} | |
// FIXME:TS should be type `AxisType` | |
export function getDimensionTypeByAxis(axisType: string): DataStoreDimensionType { | |
return axisType === 'category' | |
? 'ordinal' | |
: axisType === 'time' | |
? 'time' | |
: 'float'; | |
} | |
function mayLabelDimType(dimType: DimensionType): boolean { | |
// In most cases, ordinal and time do not suitable for label. | |
// Ordinal info can be displayed on axis. Time is too long. | |
return !(dimType === 'ordinal' || dimType === 'time'); | |
} | |
// function findTheLastDimMayLabel(data) { | |
// // Get last value dim | |
// let dimensions = data.dimensions.slice(); | |
// let valueType; | |
// let valueDim; | |
// while (dimensions.length && ( | |
// valueDim = dimensions.pop(), | |
// valueType = data.getDimensionInfo(valueDim).type, | |
// valueType === 'ordinal' || valueType === 'time' | |
// )) {} // jshint ignore:line | |
// return valueDim; | |
// } | |