| /* | |
| * 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 * as zrUtil from 'zrender/src/core/util'; | |
| import {retrieveRawValue} from '../../data/helper/dataProvider'; | |
| import {formatTpl} from '../../util/format'; | |
| import { | |
| DataHost, | |
| DisplayState, | |
| CallbackDataParams, | |
| ColorString, | |
| ZRColor, | |
| OptionDataValue, | |
| SeriesDataType, | |
| ComponentMainType, | |
| ComponentSubType, | |
| DimensionLoose, | |
| InterpolatableValue | |
| } from '../../util/types'; | |
| import GlobalModel from '../Global'; | |
| import { TooltipMarkupBlockFragment } from '../../component/tooltip/tooltipMarkup'; | |
| import { error, makePrintable } from '../../util/log'; | |
| const DIMENSION_LABEL_REG = /\{@(.+?)\}/g; | |
| export interface DataFormatMixin extends DataHost { | |
| ecModel: GlobalModel; | |
| mainType: ComponentMainType; | |
| subType: ComponentSubType; | |
| componentIndex: number; | |
| id: string; | |
| name: string; | |
| animatedValue: OptionDataValue[]; | |
| } | |
| export class DataFormatMixin { | |
| /** | |
| * Get params for formatter | |
| */ | |
| getDataParams( | |
| dataIndex: number, | |
| dataType?: SeriesDataType | |
| ): CallbackDataParams { | |
| const data = this.getData(dataType); | |
| const rawValue = this.getRawValue(dataIndex, dataType); | |
| const rawDataIndex = data.getRawIndex(dataIndex); | |
| const name = data.getName(dataIndex); | |
| const itemOpt = data.getRawDataItem(dataIndex); | |
| const style = data.getItemVisual(dataIndex, 'style'); | |
| const color = style && style[data.getItemVisual(dataIndex, 'drawType') || 'fill'] as ZRColor; | |
| const borderColor = style && style.stroke as ColorString; | |
| const mainType = this.mainType; | |
| const isSeries = mainType === 'series'; | |
| const userOutput = data.userOutput && data.userOutput.get(); | |
| return { | |
| componentType: mainType, | |
| componentSubType: this.subType, | |
| componentIndex: this.componentIndex, | |
| seriesType: isSeries ? this.subType : null, | |
| seriesIndex: (this as any).seriesIndex, | |
| seriesId: isSeries ? this.id : null, | |
| seriesName: isSeries ? this.name : null, | |
| name: name, | |
| dataIndex: rawDataIndex, | |
| data: itemOpt, | |
| dataType: dataType, | |
| value: rawValue, | |
| color: color, | |
| borderColor: borderColor, | |
| dimensionNames: userOutput ? userOutput.fullDimensions : null, | |
| encode: userOutput ? userOutput.encode : null, | |
| // Param name list for mapping `a`, `b`, `c`, `d`, `e` | |
| $vars: ['seriesName', 'name', 'value'] | |
| }; | |
| } | |
| /** | |
| * Format label | |
| * @param dataIndex | |
| * @param status 'normal' by default | |
| * @param dataType | |
| * @param labelDimIndex Only used in some chart that | |
| * use formatter in different dimensions, like radar. | |
| * @param formatter Formatter given outside. | |
| * @return return null/undefined if no formatter | |
| */ | |
| getFormattedLabel( | |
| dataIndex: number, | |
| status?: DisplayState, | |
| dataType?: SeriesDataType, | |
| labelDimIndex?: number, | |
| formatter?: string | ((params: object) => string), | |
| extendParams?: { | |
| interpolatedValue: InterpolatableValue | |
| } | |
| ): string { | |
| status = status || 'normal'; | |
| const data = this.getData(dataType); | |
| const params = this.getDataParams(dataIndex, dataType); | |
| if (extendParams) { | |
| params.value = extendParams.interpolatedValue; | |
| } | |
| if (labelDimIndex != null && zrUtil.isArray(params.value)) { | |
| params.value = params.value[labelDimIndex]; | |
| } | |
| if (!formatter) { | |
| const itemModel = data.getItemModel(dataIndex); | |
| // @ts-ignore | |
| formatter = itemModel.get(status === 'normal' | |
| ? ['label', 'formatter'] | |
| : [status, 'label', 'formatter'] | |
| ); | |
| } | |
| if (zrUtil.isFunction(formatter)) { | |
| params.status = status; | |
| params.dimensionIndex = labelDimIndex; | |
| return formatter(params); | |
| } | |
| else if (zrUtil.isString(formatter)) { | |
| const str = formatTpl(formatter, params); | |
| // Support 'aaa{@[3]}bbb{@product}ccc'. | |
| // Do not support '}' in dim name util have to. | |
| return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr: string) { | |
| const len = dimStr.length; | |
| let dimLoose: DimensionLoose = dimStr; | |
| if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') { | |
| dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0 | |
| if (__DEV__) { | |
| if (isNaN(dimLoose)) { | |
| error(`Invalide label formatter: @${dimStr}, only support @[0], @[1], @[2], ...`); | |
| } | |
| } | |
| } | |
| let val = retrieveRawValue(data, dataIndex, dimLoose) as OptionDataValue; | |
| if (extendParams && zrUtil.isArray(extendParams.interpolatedValue)) { | |
| const dimIndex = data.getDimensionIndex(dimLoose); | |
| if (dimIndex >= 0) { | |
| val = extendParams.interpolatedValue[dimIndex]; | |
| } | |
| } | |
| return val != null ? val + '' : ''; | |
| }); | |
| } | |
| } | |
| /** | |
| * Get raw value in option | |
| */ | |
| getRawValue( | |
| idx: number, | |
| dataType?: SeriesDataType | |
| ): unknown { | |
| return retrieveRawValue(this.getData(dataType), idx); | |
| } | |
| /** | |
| * Should be implemented. | |
| * @param {number} dataIndex | |
| * @param {boolean} [multipleSeries=false] | |
| * @param {string} [dataType] | |
| */ | |
| formatTooltip( | |
| dataIndex: number, | |
| multipleSeries?: boolean, | |
| dataType?: string | |
| ): TooltipFormatResult { | |
| // Empty function | |
| return; | |
| } | |
| }; | |
| type TooltipFormatResult = | |
| // If `string`, means `TooltipFormatResultLegacyObject['html']` | |
| string | |
| // | TooltipFormatResultLegacyObject | |
| | TooltipMarkupBlockFragment; | |
| // PENDING: previously we accept this type when calling `formatTooltip`, | |
| // but guess little chance has been used outside. Do we need to backward | |
| // compat it? | |
| // type TooltipFormatResultLegacyObject = { | |
| // // `html` means the markup language text, either in 'html' or 'richText'. | |
| // // The name `html` is not appropriate because in 'richText' it is not a HTML | |
| // // string. But still support it for backward compatibility. | |
| // html: string; | |
| // markers: Dictionary<ColorString>; | |
| // }; | |
| /** | |
| * For backward compat, normalize the return from `formatTooltip`. | |
| */ | |
| export function normalizeTooltipFormatResult(result: TooltipFormatResult): { | |
| // If `markupFragment` exists, `markupText` should be ignored. | |
| frag: TooltipMarkupBlockFragment; | |
| // Can be `null`/`undefined`, means no tooltip. | |
| text: string; | |
| // Merged with `markersExisting`. | |
| // markers: Dictionary<ColorString>; | |
| } { | |
| let markupText; | |
| // let markers: Dictionary<ColorString>; | |
| let markupFragment: TooltipMarkupBlockFragment; | |
| if (zrUtil.isObject(result)) { | |
| if ((result as TooltipMarkupBlockFragment).type) { | |
| markupFragment = result as TooltipMarkupBlockFragment; | |
| } | |
| else { | |
| if (__DEV__) { | |
| console.warn('The return type of `formatTooltip` is not supported: ' + makePrintable(result)); | |
| } | |
| } | |
| // else { | |
| // markupText = (result as TooltipFormatResultLegacyObject).html; | |
| // markers = (result as TooltipFormatResultLegacyObject).markers; | |
| // if (markersExisting) { | |
| // markers = zrUtil.merge(markersExisting, markers); | |
| // } | |
| // } | |
| } | |
| else { | |
| markupText = result; | |
| } | |
| return { | |
| text: markupText, | |
| // markers: markers || markersExisting, | |
| frag: markupFragment | |
| }; | |
| } |