From 0d220d875cfcd830019f92b6e0896b132f00defc Mon Sep 17 00:00:00 2001 From: Konrad Amtenbrink Date: Fri, 1 Apr 2022 15:52:36 +0200 Subject: [PATCH 1/4] Changed calculated label gap to be passed from top --- src/component/axis/AxisBuilder.ts | 13 +++++++++---- src/component/axis/CartesianAxisView.ts | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts index 5ed1ed3f6b..cb05f7287d 100644 --- a/src/component/axis/AxisBuilder.ts +++ b/src/component/axis/AxisBuilder.ts @@ -128,16 +128,20 @@ class AxisBuilder { opt: AxisBuilderCfg; + labelGap: number; + readonly group = new graphic.Group(); private _transformGroup: graphic.Group; - constructor(axisModel: AxisBaseModel, opt?: AxisBuilderCfg) { + constructor(axisModel: AxisBaseModel, opt?: AxisBuilderCfg, labelGap?: number) { this.opt = opt; this.axisModel = axisModel; + this.labelGap = labelGap; + // Default value defaults( opt, @@ -234,7 +238,8 @@ interface AxisElementsBuilder { opt: AxisBuilderCfg, axisModel: AxisBaseModel, group: graphic.Group, - transformGroup: graphic.Group + transformGroup: graphic.Group, + labelGap?: number ):void } @@ -364,7 +369,7 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu } }, - axisName(opt, axisModel, group, transformGroup) { + axisName(opt, axisModel, group, transformGroup, labelGap?) { const name = retrieve(opt.axisName, axisModel.get('name')); if (!name) { @@ -374,7 +379,7 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu const nameLocation = axisModel.get('nameLocation'); const nameDirection = opt.nameDirection; const textStyleModel = axisModel.getModel('nameTextStyle'); - const gap = axisModel.get('nameGap') || 0; + const gap = (axisModel.get('nameGap') || 0) + labelGap; const extent = axisModel.axis.getExtent(); const gapSignal = extent[0] > extent[1] ? -1 : 1; diff --git a/src/component/axis/CartesianAxisView.ts b/src/component/axis/CartesianAxisView.ts index e040398902..4524224ab6 100644 --- a/src/component/axis/CartesianAxisView.ts +++ b/src/component/axis/CartesianAxisView.ts @@ -27,6 +27,7 @@ import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import CartesianAxisModel from '../../coord/cartesian/AxisModel'; import GridModel from '../../coord/cartesian/GridModel'; +import { estimateLabelUnionRect } from '../../coord/axisHelper'; import { Payload } from '../../util/types'; import { isIntervalOrLogScale } from '../../scale/helper'; @@ -66,6 +67,20 @@ class CartesianAxisView extends AxisView { const layout = cartesianAxisHelper.layout(gridModel, axisModel); + function calcDistanceToAxis() { + const axis = axisModel.axis; + if (axis.grid.model.get('containLabel') && !axis.model.get('axisLabel').inside) { + const labelUnionRect = estimateLabelUnionRect(axis); + if (!labelUnionRect) { + return 0; + } + const dim = axis.isHorizontal() ? 'height' : 'width'; + const margin = axisModel.getModel('axisLabel').get('margin'); + return labelUnionRect[dim] + margin; + } + return 0; + } + const axisBuilder = new AxisBuilder(axisModel, zrUtil.extend({ handleAutoShown(elementType) { const cartesians = gridModel.coordinateSystem.getCartesians(); @@ -78,7 +93,7 @@ class CartesianAxisView extends AxisView { // Not show axisTick or axisLine if other axis is category / time return false; } - } as AxisBuilderCfg, layout)); + } as AxisBuilderCfg, layout), calcDistanceToAxis()); zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder); From 45140f421da6095b65105d096266dde207f587b0 Mon Sep 17 00:00:00 2001 From: Konrad Amtenbrink Date: Wed, 20 Jul 2022 11:02:03 +0200 Subject: [PATCH 2/4] fix: refactored based on comments in the PR --- src/component/axis/AxisBuilder.ts | 55 ++++++++++++++++--------- src/component/axis/CartesianAxisView.ts | 16 +------ src/coord/axisCommonTypes.ts | 2 +- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts index cb05f7287d..acd79a2694 100644 --- a/src/component/axis/AxisBuilder.ts +++ b/src/component/axis/AxisBuilder.ts @@ -24,6 +24,7 @@ import {createTextStyle} from '../../label/labelStyle'; import Model from '../../model/Model'; import {isRadianAroundZero, remRadian} from '../../util/number'; import {createSymbol, normalizeSymbolOffset} from '../../util/symbol'; +import { estimateLabelUnionRect } from '../../coord/axisHelper'; import * as matrixUtil from 'zrender/src/core/matrix'; import {applyTransform as v2ApplyTransform} from 'zrender/src/core/vector'; import {shouldShowAllLabels} from '../../coord/axisHelper'; @@ -128,20 +129,16 @@ class AxisBuilder { opt: AxisBuilderCfg; - labelGap: number; - readonly group = new graphic.Group(); private _transformGroup: graphic.Group; - constructor(axisModel: AxisBaseModel, opt?: AxisBuilderCfg, labelGap?: number) { + constructor(axisModel: AxisBaseModel, opt?: AxisBuilderCfg) { this.opt = opt; this.axisModel = axisModel; - this.labelGap = labelGap; - // Default value defaults( opt, @@ -355,7 +352,7 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu buildAxisMinorTicks(group, transformGroup, axisModel, opt.tickDirection); // This bit fixes the label overlap issue for the time chart. - // See https://github.com/apache/echarts/issues/14266 for more. + // See https://github.com/apache/echarts/issues/142156 for more. if (axisModel.get(['axisLabel', 'hideOverlap'])) { const labelList = prepareLayoutList(map(labelEls, label => ({ label, @@ -369,30 +366,46 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu } }, - axisName(opt, axisModel, group, transformGroup, labelGap?) { + axisName(opt, axisModel, group, transformGroup) { + function calcDistanceToAxis() { + const defaultMargin = 10; + const axis = axisModel.axis; + // const isHorizontal = axis.getRotate() === 0 || axis.getRotate() === 180; + const isHorizontal = true; + const labelUnionRect = estimateLabelUnionRect(axis); + if (!labelUnionRect) { + return 0; + } + const dim = isHorizontal ? 'height' : 'width'; + const margin = axisModel.getModel('axisLabel').get('margin'); + return labelUnionRect[dim] + margin + defaultMargin; + } const name = retrieve(opt.axisName, axisModel.get('name')); if (!name) { return; } - + const labelGap = calcDistanceToAxis(); const nameLocation = axisModel.get('nameLocation'); const nameDirection = opt.nameDirection; const textStyleModel = axisModel.getModel('nameTextStyle'); - const gap = (axisModel.get('nameGap') || 0) + labelGap; - + const gap = (axisModel.get('nameGap') || 0); const extent = axisModel.axis.getExtent(); const gapSignal = extent[0] > extent[1] ? -1 : 1; + const pos = [ nameLocation === 'start' ? extent[0] - gapSignal * gap + : nameLocation === 'outsideStart' + ? extent[0] + gapSignal * (gap) + (nameDirection * labelGap) : nameLocation === 'end' ? extent[1] + gapSignal * gap - : (extent[0] + extent[1]) / 2, // 'middle' - // Reuse labelOffset. - isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0 - ]; - + : nameLocation === 'outsideEnd' + ? extent[1] - gapSignal * (gap) - (nameDirection * labelGap) + : (extent[0] + extent[1]) / 2, // 'middle' or 'outsideMiddle' + // Resuse labelOffset. + isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * (gap + (isNameLocationOutside(nameLocation) ? labelGap : 0)) : isNameLocationOutside(nameLocation) ? nameDirection * (gap + labelGap) : 0 + ] let labelLayout; let nameRotation = axisModel.get('nameRotate'); @@ -481,14 +494,15 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu }; function endTextLayout( - rotation: number, textPosition: 'start' | 'middle' | 'end', textRotate: number, extent: number[] + rotation: number, textPosition: 'start' | 'middle' | 'end' | 'outsideStart' | 'outsideMiddle' | 'outsideEnd', textRotate: number, extent: number[] ) { const rotationDiff = remRadian(textRotate - rotation); let textAlign: ZRTextAlign; let textVerticalAlign: ZRTextVerticalAlign; const inverse = extent[0] > extent[1]; - const onLeft = (textPosition === 'start' && !inverse) - || (textPosition !== 'start' && inverse); + const textIsStart = textPosition.toLocaleLowerCase().includes('start'); + const onLeft = ((textIsStart) && !inverse) + || (!textIsStart && inverse); if (isRadianAroundZero(rotationDiff - PI / 2)) { textVerticalAlign = onLeft ? 'bottom' : 'top'; @@ -605,9 +619,12 @@ function isTwoLabelOverlapped( } function isNameLocationCenter(nameLocation: string) { - return nameLocation === 'middle' || nameLocation === 'center'; + return nameLocation === 'middle' || nameLocation === 'center' || nameLocation === 'outsideMiddle'; } +function isNameLocationOutside(nameLocation: string) { + return nameLocation.toLowerCase().includes('outside') +} function createTicks( ticksCoords: TickCoord[], diff --git a/src/component/axis/CartesianAxisView.ts b/src/component/axis/CartesianAxisView.ts index 4524224ab6..bd544bde7e 100644 --- a/src/component/axis/CartesianAxisView.ts +++ b/src/component/axis/CartesianAxisView.ts @@ -67,20 +67,6 @@ class CartesianAxisView extends AxisView { const layout = cartesianAxisHelper.layout(gridModel, axisModel); - function calcDistanceToAxis() { - const axis = axisModel.axis; - if (axis.grid.model.get('containLabel') && !axis.model.get('axisLabel').inside) { - const labelUnionRect = estimateLabelUnionRect(axis); - if (!labelUnionRect) { - return 0; - } - const dim = axis.isHorizontal() ? 'height' : 'width'; - const margin = axisModel.getModel('axisLabel').get('margin'); - return labelUnionRect[dim] + margin; - } - return 0; - } - const axisBuilder = new AxisBuilder(axisModel, zrUtil.extend({ handleAutoShown(elementType) { const cartesians = gridModel.coordinateSystem.getCartesians(); @@ -93,7 +79,7 @@ class CartesianAxisView extends AxisView { // Not show axisTick or axisLine if other axis is category / time return false; } - } as AxisBuilderCfg, layout), calcDistanceToAxis()); + } as AxisBuilderCfg, layout)); zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder); diff --git a/src/coord/axisCommonTypes.ts b/src/coord/axisCommonTypes.ts index e3241cb02e..cd1a491667 100644 --- a/src/coord/axisCommonTypes.ts +++ b/src/coord/axisCommonTypes.ts @@ -35,7 +35,7 @@ export interface AxisBaseOptionCommon extends ComponentOption, inverse?: boolean; // Axis name displayed. name?: string; - nameLocation?: 'start' | 'middle' | 'end'; + nameLocation?: 'start' | 'middle' | 'end' | 'outsideStart' | 'outsideMiddle' | 'outsideEnd'; // By degree. nameRotate?: number; nameTruncate?: { From 195afded908995025ca1cf7f0cbcabde8b4bd674 Mon Sep 17 00:00:00 2001 From: Konrad Amtenbrink Date: Fri, 22 Jul 2022 10:09:22 +0200 Subject: [PATCH 3/4] test: added outside axis label tests --- src/component/axis/AxisBuilder.ts | 17 +++--- src/component/axis/CartesianAxisView.ts | 1 - test/axisLabel.html | 73 +++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts index acd79a2694..455654dafe 100644 --- a/src/component/axis/AxisBuilder.ts +++ b/src/component/axis/AxisBuilder.ts @@ -24,10 +24,9 @@ import {createTextStyle} from '../../label/labelStyle'; import Model from '../../model/Model'; import {isRadianAroundZero, remRadian} from '../../util/number'; import {createSymbol, normalizeSymbolOffset} from '../../util/symbol'; -import { estimateLabelUnionRect } from '../../coord/axisHelper'; +import { estimateLabelUnionRect, shouldShowAllLabels } from '../../coord/axisHelper'; import * as matrixUtil from 'zrender/src/core/matrix'; import {applyTransform as v2ApplyTransform} from 'zrender/src/core/vector'; -import {shouldShowAllLabels} from '../../coord/axisHelper'; import { AxisBaseModel } from '../../coord/AxisBaseModel'; import { ZRTextVerticalAlign, ZRTextAlign, ECElement, ColorString } from '../../util/types'; import { AxisBaseOption } from '../../coord/axisCommonTypes'; @@ -404,8 +403,10 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu ? extent[1] - gapSignal * (gap) - (nameDirection * labelGap) : (extent[0] + extent[1]) / 2, // 'middle' or 'outsideMiddle' // Resuse labelOffset. - isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * (gap + (isNameLocationOutside(nameLocation) ? labelGap : 0)) : isNameLocationOutside(nameLocation) ? nameDirection * (gap + labelGap) : 0 - ] + isNameLocationCenter(nameLocation) + ? opt.labelOffset + nameDirection * (gap + (isNameLocationOutside(nameLocation) ? labelGap : 0)) + : isNameLocationOutside(nameLocation) ? nameDirection * (gap + labelGap) : 0 + ]; let labelLayout; let nameRotation = axisModel.get('nameRotate'); @@ -493,9 +494,9 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu }; -function endTextLayout( - rotation: number, textPosition: 'start' | 'middle' | 'end' | 'outsideStart' | 'outsideMiddle' | 'outsideEnd', textRotate: number, extent: number[] -) { +function endTextLayout(rotation: number, + textPosition: 'start' | 'middle' | 'end' | 'outsideStart' | 'outsideMiddle' | 'outsideEnd', + textRotate: number, extent: number[]) { const rotationDiff = remRadian(textRotate - rotation); let textAlign: ZRTextAlign; let textVerticalAlign: ZRTextVerticalAlign; @@ -623,7 +624,7 @@ function isNameLocationCenter(nameLocation: string) { } function isNameLocationOutside(nameLocation: string) { - return nameLocation.toLowerCase().includes('outside') + return nameLocation.toLowerCase().includes('outside'); } function createTicks( diff --git a/src/component/axis/CartesianAxisView.ts b/src/component/axis/CartesianAxisView.ts index bd544bde7e..e040398902 100644 --- a/src/component/axis/CartesianAxisView.ts +++ b/src/component/axis/CartesianAxisView.ts @@ -27,7 +27,6 @@ import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import CartesianAxisModel from '../../coord/cartesian/AxisModel'; import GridModel from '../../coord/cartesian/GridModel'; -import { estimateLabelUnionRect } from '../../coord/axisHelper'; import { Payload } from '../../util/types'; import { isIntervalOrLogScale } from '../../scale/helper'; diff --git a/test/axisLabel.html b/test/axisLabel.html index a3c5b97971..611f621b32 100644 --- a/test/axisLabel.html +++ b/test/axisLabel.html @@ -44,6 +44,8 @@
+
+
@@ -375,6 +377,77 @@ + + + \ No newline at end of file From 9af5af9affa314a798db8ad131148d69b5bb5675 Mon Sep 17 00:00:00 2001 From: Konrad Amtenbrink Date: Thu, 25 Aug 2022 10:54:58 +0200 Subject: [PATCH 4/4] refactor: added conditional axis distance calculation --- src/component/axis/AxisBuilder.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts index 30053c82b7..577ee79c3f 100644 --- a/src/component/axis/AxisBuilder.ts +++ b/src/component/axis/AxisBuilder.ts @@ -353,7 +353,7 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu buildAxisMinorTicks(group, transformGroup, axisModel, opt.tickDirection); // This bit fixes the label overlap issue for the time chart. - // See https://github.com/apache/echarts/issues/142156 for more. + // See https://github.com/apache/echarts/issues/14266 for more. if (axisModel.get(['axisLabel', 'hideOverlap'])) { const labelList = prepareLayoutList(map(labelEls, label => ({ label, @@ -371,8 +371,7 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu function calcDistanceToAxis() { const defaultMargin = 10; const axis = axisModel.axis; - // const isHorizontal = axis.getRotate() === 0 || axis.getRotate() === 180; - const isHorizontal = true; + const isHorizontal = axis.isHorizontal(); const labelUnionRect = estimateLabelUnionRect(axis); if (!labelUnionRect) { return 0; @@ -386,7 +385,8 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu if (!name) { return; } - const labelGap = calcDistanceToAxis(); + const isOutside = name === 'outsideStart' || name === 'outsideMiddle' || name === 'outsideEnd'; + const labelGap = isOutside ? calcDistanceToAxis() : 0; const nameLocation = axisModel.get('nameLocation'); const nameDirection = opt.nameDirection; const textStyleModel = axisModel.getModel('nameTextStyle'); @@ -503,7 +503,7 @@ function endTextLayout(rotation: number, let textAlign: ZRTextAlign; let textVerticalAlign: ZRTextVerticalAlign; const inverse = extent[0] > extent[1]; - const textIsStart = textPosition.toLocaleLowerCase().includes('start'); + const textIsStart = textPosition === 'start' || textPosition === 'outsideStart'; const onLeft = ((textIsStart) && !inverse) || (!textIsStart && inverse); @@ -626,7 +626,7 @@ function isNameLocationCenter(nameLocation: string) { } function isNameLocationOutside(nameLocation: string) { - return nameLocation.toLowerCase().includes('outside'); + return nameLocation === 'outsideStart' || nameLocation === 'outsideMiddle' || nameLocation === 'outsideEnd'; } function createTicks(