diff --git a/docs/assets/option/en/component/crosshair-common/crosshair-label.md b/docs/assets/option/en/component/crosshair-common/crosshair-label.md index aa93654f05..1a8cdc7674 100644 --- a/docs/assets/option/en/component/crosshair-common/crosshair-label.md +++ b/docs/assets/option/en/component/crosshair-common/crosshair-label.md @@ -39,6 +39,10 @@ For detailed usage, please refer to the [Tutorial Document](/vchart/guide/tutori Text background related configuration. +#${prefix} syncAxisLabelAngle(boolean) = false + +Whether the text rotates with the axis label angle. Currently only supported in rectangular coordinate system, supported since version `1.13.12`. + ##${prefix} visible(boolean) = true Whether to display the text background or not. diff --git a/docs/assets/option/zh/component/crosshair-common/crosshair-label.md b/docs/assets/option/zh/component/crosshair-common/crosshair-label.md index 563eb2aa75..94061787b0 100644 --- a/docs/assets/option/zh/component/crosshair-common/crosshair-label.md +++ b/docs/assets/option/zh/component/crosshair-common/crosshair-label.md @@ -39,6 +39,10 @@ label 文本格式化方法。函数的定义如下: 文本背景相关配置。 +#${prefix} syncAxisLabelAngle(boolean) = false + +文本是否跟随轴标签的角度旋转,目前只在直角坐标系下支持,自`1.13.12`版本开始支持。 + ##${prefix} visible(boolean) = true 是否显示文本背景。 diff --git a/packages/vchart/src/component/crosshair/base.ts b/packages/vchart/src/component/crosshair/base.ts index ba226ca93f..14be270d33 100644 --- a/packages/vchart/src/component/crosshair/base.ts +++ b/packages/vchart/src/component/crosshair/base.ts @@ -567,6 +567,7 @@ export abstract class BaseCrossHair; zIndex?: number; + /** + * 文本是否跟随轴标签的角度旋转 + * default: false + * @since 1.13.12 + */ + syncAxisLabelAngle?: boolean; }; /** * 极坐标系样式 @@ -75,6 +81,7 @@ export interface ICrosshairInfo { visible: boolean; _isCache?: boolean; axis: IAxis; + axisLabel: IText; /** * 半径轴对应的crosshair,当crosshair类型为多边形的时候,多边形的边数 */ diff --git a/packages/vchart/src/component/crosshair/interface/spec.ts b/packages/vchart/src/component/crosshair/interface/spec.ts index 259ec8368f..0e64821eb8 100644 --- a/packages/vchart/src/component/crosshair/interface/spec.ts +++ b/packages/vchart/src/component/crosshair/interface/spec.ts @@ -186,6 +186,11 @@ export interface ICrosshairLabelSpec { * 文本背景相关配置 */ labelBackground?: ICrosshairLabelBackgroundSpec; + /** + * 文本是否跟随轴标签的角度旋转,目前只在直角坐标系下支持 + * @since 1.13.12 + */ + syncAxisLabelAngle?: boolean; } export interface ICrosshairLabelBackgroundSpec { diff --git a/packages/vchart/src/component/crosshair/utils/cartesian.ts b/packages/vchart/src/component/crosshair/utils/cartesian.ts index 129433c848..eaf6a77b4a 100644 --- a/packages/vchart/src/component/crosshair/utils/cartesian.ts +++ b/packages/vchart/src/component/crosshair/utils/cartesian.ts @@ -1,3 +1,4 @@ +import type { IText } from '@visactor/vrender-core'; import type { BandScale } from '@visactor/vscale'; // eslint-disable-next-line no-duplicate-imports import { isContinuous, isDiscrete } from '@visactor/vscale'; @@ -32,7 +33,7 @@ export const layoutByValue = ( const { currentValue, cacheInfo, labelsComp, attributes, coordKey } = stateByField[field]; let axis = null; let coord = 0; - + let axisLabel: IText = null; if (currentValue.size) { const item = Array.from(currentValue.values())[0]; coord = @@ -40,6 +41,10 @@ export const layoutByValue = ( item.axis.getLayoutStartPoint()[coordKey as 'x' | 'y'] - layoutStartPoint[coordKey as 'x' | 'y']; axis = item.axis; + axisLabel = axis + .getVRenderComponents()[0] + ?.children[0]?.children[0]?.getChildByName('axis-label-container') + ?.getChildByName('axis-label-container-layer-0')?.children[0]; } const isVisible = !!currentValue.size && Number.isFinite(coord) && !Number.isNaN(coord); const useCache = enableRemain && !isVisible && isValid(cacheInfo); @@ -58,7 +63,8 @@ export const layoutByValue = ( }, {}) : null, visible: isVisible, - axis + axis, + axisLabel: axisLabel }; if (newCacheInfo) { newCacheInfo._isCache = useCache; @@ -98,34 +104,34 @@ export const layoutByValue = ( if (newCacheInfo && attributes.label?.visible && !useCache) { const labelOffset = getAxisLabelOffset(axis.getSpec()); const axisOrient = axis.getOrient(); - + const syncAxisLabelAngle = attributes.label?.syncAxisLabelAngle; if (newCacheInfo.labels[axisOrient]) { newCacheInfo.labels[axisOrient].visible = true; newCacheInfo.labels[axisOrient].text = value; if (axisOrient === 'left') { newCacheInfo.labels[axisOrient].dx = -labelOffset; newCacheInfo.labelsTextStyle[axisOrient] = { - textAlign: 'right', - textBaseline: 'middle' + textAlign: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textAlign ?? 'right' : 'right', + textBaseline: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textBaseline ?? 'middle' : 'middle' }; } else if (axisOrient === 'right') { newCacheInfo.labels[axisOrient].dx = labelOffset; newCacheInfo.labelsTextStyle[axisOrient] = { - textAlign: 'left', - textBaseline: 'middle' + textAlign: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textAlign ?? 'left' : 'left', + textBaseline: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textBaseline ?? 'middle' : 'middle' }; } else if (axisOrient === 'top') { newCacheInfo.labels[axisOrient].y = 0; newCacheInfo.labels[axisOrient].dy = -labelOffset; newCacheInfo.labelsTextStyle[axisOrient] = { - textAlign: 'center', - textBaseline: 'bottom' + textAlign: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textAlign ?? 'center' : 'center', + textBaseline: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textBaseline ?? 'bottom' : 'bottom' }; } else if (axisOrient === 'bottom') { newCacheInfo.labels[axisOrient].dy = labelOffset; newCacheInfo.labelsTextStyle[axisOrient] = { - textAlign: 'center', - textBaseline: 'top' + textAlign: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textAlign ?? 'center' : 'center', + textBaseline: syncAxisLabelAngle && axisLabel ? axisLabel.attribute.textBaseline ?? 'top' : 'top' }; } newCacheInfo.labels[axisOrient].defaultFormatter = niceLabelFormatter;