From 99dbeabcaf2725474fab9067d7f2ade233c24391 Mon Sep 17 00:00:00 2001 From: netil Date: Tue, 19 Nov 2024 18:51:20 +0900 Subject: [PATCH] fix(tooltip): Fix tooltip position on viewBox resizing - Fix coordinate value translating SVG to DOM - Adjust tooltip position by its type Ref #3917 --- src/ChartInternal/data/data.ts | 7 +++-- src/ChartInternal/internals/tooltip.ts | 40 ++++++++++++++++---------- src/module/util.ts | 12 ++++++-- test/interactions/viewbox-spec.ts | 6 ++-- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/ChartInternal/data/data.ts b/src/ChartInternal/data/data.ts index b3d8a993c..146148c5b 100644 --- a/src/ChartInternal/data/data.ts +++ b/src/ChartInternal/data/data.ts @@ -730,14 +730,15 @@ export default { event.changedTouches[0] : event; - let point = isRotated ? - e.clientY + scrollPos.y - rect.top : - e.clientX + scrollPos.x - rect.left; + let point = isRotated ? e.clientY + scrollPos.y : e.clientX + scrollPos.x; if (hasViewBox($el.svg)) { const pos = [point, 0]; + isRotated && pos.reverse(); point = getTransformCTM($el.svg.node(), ...pos)[isRotated ? "y" : "x"]; + } else { + point -= isRotated ? rect.top : rect.left; } index = findIndex( diff --git a/src/ChartInternal/internals/tooltip.ts b/src/ChartInternal/internals/tooltip.ts index 60700f4b0..2cb487b22 100644 --- a/src/ChartInternal/internals/tooltip.ts +++ b/src/ChartInternal/internals/tooltip.ts @@ -362,16 +362,21 @@ export default { } }, + /** + * Get tooltip position when svg has vieBox attribute + * @param {number} tWidth Tooltip width value + * @param {number} tHeight Tooltip height value + * @param {object} currPos Current event position value from SVG coordinate + * @returns {object} top, left value + */ getTooltipPositionViewBox(tWidth: number, tHeight: number, currPos: {[key: string]: number}): {top: number, left: number} { const $$ = this; - const {$el: {eventRect, main}, config, state} = $$; + const {$el: {eventRect, svg}, config, state} = $$; const isRotated = config.axis_rotated; - const hasArcType = $$.hasArcType(undefined, ["radar"]) || state.hasFunnel || - state.hasTreemap; - const target = (state.hasRadar ? main : eventRect)?.node() ?? state.event.target; - const size = 38; // getTransformCTM($el.svg.node(), 10, 0, false).x; + const hasArcType = $$.hasArcType() || state.hasFunnel || state.hasTreemap; + const target = (hasArcType ? svg : eventRect)?.node() ?? state.event.target; let {x, y} = currPos; @@ -380,25 +385,30 @@ export default { y = isRotated ? currPos.xAxis : y; } - // currPos는 SVG 좌표계 기준으로 전달됨 + // currPos value based on SVG coordinate const ctm = getTransformCTM(target, x, y, false); + const rect = target.getBoundingClientRect(); + const size = getTransformCTM(target, 20, 0, false).x; let top = ctm.y; - let left = ctm.x + size; + let left = ctm.x + (tWidth / 2) + size; if (hasArcType) { - top += tHeight; - left -= size; // (tWidth / 2); + if (state.hasFunnel || state.hasTreemap || state.hasRadar) { + left -= (tWidth / 2) + size; + top += tHeight; + } else { + top += rect.height / 2; + left += (rect.width / 2) - (tWidth - size); + } } - const rect = (hasArcType ? main.node() : target).getBoundingClientRect(); - - if (left + tWidth > rect.right) { - left = rect.right - tWidth - size; + if (left + tWidth > rect.width) { + left = rect.width - tWidth - size; } - if (top + tHeight > rect.bottom) { - top -= tHeight + size; + if (top + tHeight > rect.height) { + top -= tHeight * 2; } return { diff --git a/src/module/util.ts b/src/module/util.ts index 4df9a0ec0..cd6ff7399 100644 --- a/src/module/util.ts +++ b/src/module/util.ts @@ -551,10 +551,18 @@ function getScrollPosition(node: HTMLElement) { function getTransformCTM(node: SVGGraphicsElement, x = 0, y = 0, inverse = true): DOMPoint { const point = new DOMPoint(x, y); const screen = node.getScreenCTM(); - - return point.matrixTransform( + const res = point.matrixTransform( inverse ? screen?.inverse() : screen ); + + if (inverse === false) { + const rect = node.getBoundingClientRect(); + + res.x -= rect.x; + res.y -= rect.y; + } + + return res; } /** diff --git a/test/interactions/viewbox-spec.ts b/test/interactions/viewbox-spec.ts index d21d3d2fb..0501a728c 100644 --- a/test/interactions/viewbox-spec.ts +++ b/test/interactions/viewbox-spec.ts @@ -115,7 +115,7 @@ describe("viewBox", function() { it("should show tooltip on viewBox scale", () => { const {internal: {$el: {eventRect}}} = chart; - [100, 150, 200, 270, 350, 450].forEach(x => { + [50, 130, 200, 270, 350, 450].forEach(x => { fireEvent(eventRect.node(), "mousemove", { clientX: x, clientY: 50 @@ -156,8 +156,8 @@ describe("viewBox", function() { "value": "data1", }, { - "left": 303.112, - "top": 117.552, + "left": 445.297, + "top": 213.328, "value": "data2", } ];