Skip to content

Commit

Permalink
fix(tooltip): Fix tooltip position on viewBox resizing
Browse files Browse the repository at this point in the history
- Fix coordinate value translating SVG to DOM
- Adjust tooltip position by its type

Ref #3917
  • Loading branch information
netil authored and netil committed Nov 19, 2024
1 parent 744c4fd commit 99dbeab
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 23 deletions.
7 changes: 4 additions & 3 deletions src/ChartInternal/data/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
40 changes: 25 additions & 15 deletions src/ChartInternal/internals/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 {
Expand Down
12 changes: 10 additions & 2 deletions src/module/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <DOMMatrix>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;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions test/interactions/viewbox-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -156,8 +156,8 @@ describe("viewBox", function() {
"value": "data1",
},
{
"left": 303.112,
"top": 117.552,
"left": 445.297,
"top": 213.328,
"value": "data2",
}
];
Expand Down

0 comments on commit 99dbeab

Please sign in to comment.