/* * 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; // }; /** * 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; } { let markupText; // let markers: Dictionary; 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 }; }