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 * as zrUtil from 'zrender/src/core/util'; | |
| import * as graphic from '../../util/graphic'; | |
| import * as textContain from 'zrender/src/contain/text'; | |
| import * as formatUtil from '../../util/format'; | |
| import * as matrix from 'zrender/src/core/matrix'; | |
| import * as axisHelper from '../../coord/axisHelper'; | |
| import AxisBuilder from '../axis/AxisBuilder'; | |
| import Axis from '../../coord/Axis'; | |
| import { | |
| ScaleDataValue, CallbackDataParams, ZRTextAlign, ZRTextVerticalAlign, ZRColor, CommonAxisPointerOption, ColorString | |
| } from '../../util/types'; | |
| import { VectorArray } from 'zrender/src/core/vector'; | |
| import GlobalModel from '../../model/Global'; | |
| import IntervalScale from '../../scale/Interval'; | |
| import Axis2D from '../../coord/cartesian/Axis2D'; | |
| import { AxisPointerElementOptions } from './BaseAxisPointer'; | |
| import { AxisBaseModel } from '../../coord/AxisBaseModel'; | |
| import ExtensionAPI from '../../core/ExtensionAPI'; | |
| import CartesianAxisModel from '../../coord/cartesian/AxisModel'; | |
| import Model from '../../model/Model'; | |
| import { PathStyleProps } from 'zrender/src/graphic/Path'; | |
| import { createTextStyle } from '../../label/labelStyle'; | |
| interface LayoutInfo { | |
| position: VectorArray | |
| rotation: number | |
| labelOffset?: number | |
| /** | |
| * 1 | -1 | |
| */ | |
| labelDirection?: number | |
| labelMargin?: number | |
| } | |
| // Not use top level axisPointer model | |
| type AxisPointerModel = Model<CommonAxisPointerOption>; | |
| export function buildElStyle(axisPointerModel: AxisPointerModel) { | |
| const axisPointerType = axisPointerModel.get('type'); | |
| const styleModel = axisPointerModel.getModel(axisPointerType + 'Style' as 'lineStyle' | 'shadowStyle'); | |
| let style: PathStyleProps; | |
| if (axisPointerType === 'line') { | |
| style = styleModel.getLineStyle(); | |
| style.fill = null; | |
| } | |
| else if (axisPointerType === 'shadow') { | |
| style = styleModel.getAreaStyle(); | |
| style.stroke = null; | |
| } | |
| return style; | |
| } | |
| /** | |
| * @param {Function} labelPos {align, verticalAlign, position} | |
| */ | |
| export function buildLabelElOption( | |
| elOption: AxisPointerElementOptions, | |
| axisModel: AxisBaseModel, | |
| axisPointerModel: AxisPointerModel, | |
| api: ExtensionAPI, | |
| labelPos: { | |
| align?: ZRTextAlign | |
| verticalAlign?: ZRTextVerticalAlign | |
| position: number[] | |
| } | |
| ) { | |
| const value = axisPointerModel.get('value'); | |
| const text = getValueLabel( | |
| value, axisModel.axis, axisModel.ecModel, | |
| axisPointerModel.get('seriesDataIndices'), | |
| { | |
| precision: axisPointerModel.get(['label', 'precision']), | |
| formatter: axisPointerModel.get(['label', 'formatter']) | |
| } | |
| ); | |
| const labelModel = axisPointerModel.getModel('label'); | |
| const paddings = formatUtil.normalizeCssArray(labelModel.get('padding') || 0); | |
| const font = labelModel.getFont(); | |
| const textRect = textContain.getBoundingRect(text, font); | |
| const position = labelPos.position; | |
| const width = textRect.width + paddings[1] + paddings[3]; | |
| const height = textRect.height + paddings[0] + paddings[2]; | |
| // Adjust by align. | |
| const align = labelPos.align; | |
| align === 'right' && (position[0] -= width); | |
| align === 'center' && (position[0] -= width / 2); | |
| const verticalAlign = labelPos.verticalAlign; | |
| verticalAlign === 'bottom' && (position[1] -= height); | |
| verticalAlign === 'middle' && (position[1] -= height / 2); | |
| // Not overflow ec container | |
| confineInContainer(position, width, height, api); | |
| let bgColor = labelModel.get('backgroundColor') as ZRColor; | |
| if (!bgColor || bgColor === 'auto') { | |
| bgColor = axisModel.get(['axisLine', 'lineStyle', 'color']); | |
| } | |
| elOption.label = { | |
| // shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')}, | |
| x: position[0], | |
| y: position[1], | |
| style: createTextStyle(labelModel, { | |
| text: text, | |
| font: font, | |
| fill: labelModel.getTextColor(), | |
| padding: paddings, | |
| backgroundColor: bgColor as ColorString | |
| }), | |
| // Label should be over axisPointer. | |
| z2: 10 | |
| }; | |
| } | |
| // Do not overflow ec container | |
| function confineInContainer(position: number[], width: number, height: number, api: ExtensionAPI) { | |
| const viewWidth = api.getWidth(); | |
| const viewHeight = api.getHeight(); | |
| position[0] = Math.min(position[0] + width, viewWidth) - width; | |
| position[1] = Math.min(position[1] + height, viewHeight) - height; | |
| position[0] = Math.max(position[0], 0); | |
| position[1] = Math.max(position[1], 0); | |
| } | |
| export function getValueLabel( | |
| value: ScaleDataValue, | |
| axis: Axis, | |
| ecModel: GlobalModel, | |
| seriesDataIndices: CommonAxisPointerOption['seriesDataIndices'], | |
| opt?: { | |
| precision?: number | 'auto' | |
| formatter?: CommonAxisPointerOption['label']['formatter'] | |
| } | |
| ): string { | |
| value = axis.scale.parse(value); | |
| let text = (axis.scale as IntervalScale).getLabel( | |
| { | |
| value | |
| }, { | |
| // If `precision` is set, width can be fixed (like '12.00500'), which | |
| // helps to debounce when when moving label. | |
| precision: opt.precision | |
| } | |
| ); | |
| const formatter = opt.formatter; | |
| if (formatter) { | |
| const params = { | |
| value: axisHelper.getAxisRawValue(axis, {value}), | |
| axisDimension: axis.dim, | |
| axisIndex: (axis as Axis2D).index, // Only Carteian Axis has index | |
| seriesData: [] as CallbackDataParams[] | |
| }; | |
| zrUtil.each(seriesDataIndices, function (idxItem) { | |
| const series = ecModel.getSeriesByIndex(idxItem.seriesIndex); | |
| const dataIndex = idxItem.dataIndexInside; | |
| const dataParams = series && series.getDataParams(dataIndex); | |
| dataParams && params.seriesData.push(dataParams); | |
| }); | |
| if (zrUtil.isString(formatter)) { | |
| text = formatter.replace('{value}', text); | |
| } | |
| else if (zrUtil.isFunction(formatter)) { | |
| text = formatter(params); | |
| } | |
| } | |
| return text; | |
| } | |
| export function getTransformedPosition( | |
| axis: Axis, | |
| value: ScaleDataValue, | |
| layoutInfo: LayoutInfo | |
| ): number[] { | |
| const transform = matrix.create(); | |
| matrix.rotate(transform, transform, layoutInfo.rotation); | |
| matrix.translate(transform, transform, layoutInfo.position); | |
| return graphic.applyTransform([ | |
| axis.dataToCoord(value), | |
| (layoutInfo.labelOffset || 0) | |
| + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0) | |
| ], transform); | |
| } | |
| export function buildCartesianSingleLabelElOption( | |
| value: ScaleDataValue, | |
| elOption: AxisPointerElementOptions, | |
| layoutInfo: LayoutInfo, | |
| axisModel: CartesianAxisModel, | |
| axisPointerModel: AxisPointerModel, | |
| api: ExtensionAPI | |
| ) { | |
| // @ts-ignore | |
| const textLayout = AxisBuilder.innerTextLayout( | |
| layoutInfo.rotation, 0, layoutInfo.labelDirection | |
| ); | |
| layoutInfo.labelMargin = axisPointerModel.get(['label', 'margin']); | |
| buildLabelElOption(elOption, axisModel, axisPointerModel, api, { | |
| position: getTransformedPosition(axisModel.axis, value, layoutInfo), | |
| align: textLayout.textAlign, | |
| verticalAlign: textLayout.textVerticalAlign | |
| }); | |
| } | |
| export function makeLineShape(p1: number[], p2: number[], xDimIndex?: number) { | |
| xDimIndex = xDimIndex || 0; | |
| return { | |
| x1: p1[xDimIndex], | |
| y1: p1[1 - xDimIndex], | |
| x2: p2[xDimIndex], | |
| y2: p2[1 - xDimIndex] | |
| }; | |
| } | |
| export function makeRectShape(xy: number[], wh: number[], xDimIndex?: number) { | |
| xDimIndex = xDimIndex || 0; | |
| return { | |
| x: xy[xDimIndex], | |
| y: xy[1 - xDimIndex], | |
| width: wh[xDimIndex], | |
| height: wh[1 - xDimIndex] | |
| }; | |
| } | |
| export function makeSectorShape( | |
| cx: number, | |
| cy: number, | |
| r0: number, | |
| r: number, | |
| startAngle: number, | |
| endAngle: number | |
| ) { | |
| return { | |
| cx: cx, | |
| cy: cy, | |
| r0: r0, | |
| r: r, | |
| startAngle: startAngle, | |
| endAngle: endAngle, | |
| clockwise: true | |
| }; | |
| } | |