| /* |
| * 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; |
| // } |