@internetstiftelsen/charts 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { SPLIT_TOOLTIP_GAP_PX, TOOLTIP_BOX_ARROW_LENGTH_PX, TOOLTIP_CONNECTOR_ALIGNMENT_TOLERANCE_PX, TOOLTIP_CONNECTOR_ELBOW_RATIO, TOOLTIP_CONNECTOR_INSET_PX, TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX, TOOLTIP_CONNECTOR_PADDING_PX, TOOLTIP_OFFSET_PX, TOOLTIP_TOTAL_BORDER_WIDTH_PX, TOOLTIP_VIEWPORT_PADDING_PX, } from './types.js';
2
2
  const MAX_EXHAUSTIVE_HORIZONTAL_ROW_LAYOUTS = 10;
3
3
  const HORIZONTAL_ROW_ORDER_FLIP_PENALTY_PX = 128;
4
+ const AUTO_BAR_TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX = 8;
4
5
  export function getSplitTooltipViewportBounds() {
5
6
  const visualViewport = window.visualViewport;
6
7
  const viewportLeft = window.scrollX + (visualViewport?.offsetLeft ?? 0);
@@ -98,13 +99,16 @@ export function getAnchoredTooltipPosition(anchor, target, tooltipWidth, tooltip
98
99
  };
99
100
  }
100
101
  export function resolveTooltipConnectorLayout(arrowEdge, tooltipLeft, tooltipTop, tooltipWidth, tooltipHeight, targetX, targetY, anchor) {
101
- const localTargetX = targetX - tooltipLeft;
102
- const localTargetY = targetY - tooltipTop;
102
+ const boxArrowPosition = resolveTooltipBoxArrowPosition(arrowEdge, tooltipLeft, tooltipTop, tooltipWidth, tooltipHeight, targetX, targetY);
103
+ const arrowTip = resolveTooltipArrowTip(arrowEdge, boxArrowPosition.x, boxArrowPosition.y, TOOLTIP_BOX_ARROW_LENGTH_PX);
104
+ const arrowTipX = tooltipLeft + arrowTip.x;
105
+ const arrowTipY = tooltipTop + arrowTip.y;
106
+ const connectorTarget = resolveTooltipConnectorTarget(arrowEdge, targetX, targetY, arrowTipX, arrowTipY, anchor);
107
+ const localTargetX = connectorTarget.x - tooltipLeft;
108
+ const localTargetY = connectorTarget.y - tooltipTop;
103
109
  if (!Number.isFinite(localTargetX) || !Number.isFinite(localTargetY)) {
104
110
  return null;
105
111
  }
106
- const boxArrowPosition = resolveTooltipBoxArrowPosition(arrowEdge, tooltipLeft, tooltipTop, tooltipWidth, tooltipHeight, targetX, targetY);
107
- const arrowTip = resolveTooltipArrowTip(arrowEdge, boxArrowPosition.x, boxArrowPosition.y, TOOLTIP_BOX_ARROW_LENGTH_PX);
108
112
  const minX = Math.min(arrowTip.x, localTargetX) - TOOLTIP_CONNECTOR_PADDING_PX;
109
113
  const maxX = Math.max(arrowTip.x, localTargetX) + TOOLTIP_CONNECTOR_PADDING_PX;
110
114
  const minY = Math.min(arrowTip.y, localTargetY) - TOOLTIP_CONNECTOR_PADDING_PX;
@@ -117,9 +121,7 @@ export function resolveTooltipConnectorLayout(arrowEdge, tooltipLeft, tooltipTop
117
121
  const startY = arrowTip.y - minY;
118
122
  const endX = localTargetX - minX;
119
123
  const endY = localTargetY - minY;
120
- const arrowTipX = tooltipLeft + arrowTip.x;
121
- const arrowTipY = tooltipTop + arrowTip.y;
122
- const connectorPath = resolveTooltipConnectorPath(arrowEdge, startX, startY, endX, endY, arrowTipX, arrowTipY, anchor);
124
+ const connectorPath = resolveTooltipConnectorPath(arrowEdge, startX, startY, endX, endY, arrowTipX, arrowTipY, anchor, connectorTarget.preferDirectPath);
123
125
  if (!hasFiniteNumbers(width, height, boxX, boxY, startX, startY, endX, endY)) {
124
126
  return null;
125
127
  }
@@ -134,6 +136,43 @@ export function resolveTooltipConnectorLayout(arrowEdge, tooltipLeft, tooltipTop
134
136
  arrowY: boxArrowPosition.y,
135
137
  };
136
138
  }
139
+ function resolveTooltipConnectorTarget(arrowEdge, targetX, targetY, arrowTipX, arrowTipY, anchor) {
140
+ if (isPointTooltipAnchor(anchor)) {
141
+ return { x: targetX, y: targetY, preferDirectPath: false };
142
+ }
143
+ if (arrowEdge === 'left') {
144
+ return {
145
+ x: anchor.right,
146
+ y: clampTooltipCoordinate(arrowTipY, anchor.top, anchor.bottom),
147
+ preferDirectPath: true,
148
+ };
149
+ }
150
+ if (arrowEdge === 'right') {
151
+ return {
152
+ x: anchor.left,
153
+ y: clampTooltipCoordinate(arrowTipY, anchor.top, anchor.bottom),
154
+ preferDirectPath: true,
155
+ };
156
+ }
157
+ if (arrowEdge === 'top') {
158
+ return {
159
+ x: clampTooltipCoordinate(arrowTipX, anchor.left, anchor.right),
160
+ y: anchor.bottom,
161
+ preferDirectPath: true,
162
+ };
163
+ }
164
+ return {
165
+ x: clampTooltipCoordinate(arrowTipX, anchor.left, anchor.right),
166
+ y: anchor.top,
167
+ preferDirectPath: true,
168
+ };
169
+ }
170
+ function isPointTooltipAnchor(anchor) {
171
+ return (Math.abs(anchor.left - anchor.right) <=
172
+ TOOLTIP_CONNECTOR_ALIGNMENT_TOLERANCE_PX &&
173
+ Math.abs(anchor.top - anchor.bottom) <=
174
+ TOOLTIP_CONNECTOR_ALIGNMENT_TOLERANCE_PX);
175
+ }
137
176
  export function resolveTooltipArrowPosition(arrowEdge, boxX, boxY, length, halfHeight) {
138
177
  switch (arrowEdge) {
139
178
  case 'left':
@@ -210,17 +249,26 @@ function getTooltipConnectorOffset(start, size, target) {
210
249
  const preferredOffset = target - start;
211
250
  return Math.max(minOffset, Math.min(preferredOffset, maxOffset));
212
251
  }
213
- function resolveTooltipConnectorPath(arrowEdge, startX, startY, endX, endY, arrowTipX, arrowTipY, anchor) {
252
+ function resolveTooltipConnectorPath(arrowEdge, startX, startY, endX, endY, arrowTipX, arrowTipY, anchor, preferDirectPath) {
214
253
  if (arrowEdge === 'left' || arrowEdge === 'right') {
215
- if (isTooltipArrowTipNearVerticalAnchorSpan(arrowTipY, anchor)) {
254
+ const minPathLength = preferDirectPath
255
+ ? AUTO_BAR_TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX
256
+ : TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX;
257
+ if (isTooltipArrowTipNearVerticalAnchorSpan(arrowTipY, anchor, minPathLength)) {
216
258
  return '';
217
259
  }
260
+ if (preferDirectPath) {
261
+ return `M ${startX},${startY} L ${endX},${endY}`;
262
+ }
218
263
  const elbowX = startX + (endX - startX) * TOOLTIP_CONNECTOR_ELBOW_RATIO;
219
264
  return `M ${startX},${startY} L ${elbowX},${startY} L ${endX},${endY}`;
220
265
  }
221
266
  if (isTooltipArrowTipInsideHorizontalAnchorSpan(arrowTipX, anchor)) {
222
267
  return '';
223
268
  }
269
+ if (preferDirectPath) {
270
+ return `M ${startX},${startY} L ${endX},${endY}`;
271
+ }
224
272
  const elbowY = startY + (endY - startY) * TOOLTIP_CONNECTOR_ELBOW_RATIO;
225
273
  return `M ${startX},${startY} L ${startX},${elbowY} L ${endX},${endY}`;
226
274
  }
@@ -232,12 +280,12 @@ function isTooltipArrowTipInsideVerticalAnchorSpan(arrowTipY, anchor) {
232
280
  return (arrowTipY >= anchor.top - TOOLTIP_CONNECTOR_ALIGNMENT_TOLERANCE_PX &&
233
281
  arrowTipY <= anchor.bottom + TOOLTIP_CONNECTOR_ALIGNMENT_TOLERANCE_PX);
234
282
  }
235
- function isTooltipArrowTipNearVerticalAnchorSpan(arrowTipY, anchor) {
283
+ function isTooltipArrowTipNearVerticalAnchorSpan(arrowTipY, anchor, minPathLength = TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX) {
236
284
  if (isTooltipArrowTipInsideVerticalAnchorSpan(arrowTipY, anchor)) {
237
285
  return true;
238
286
  }
239
- return (arrowTipY >= anchor.top - TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX &&
240
- arrowTipY <= anchor.bottom + TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX);
287
+ return (arrowTipY >= anchor.top - minPathLength &&
288
+ arrowTipY <= anchor.bottom + minPathLength);
241
289
  }
242
290
  function resolveTooltipArrowTip(arrowEdge, boxX, boxY, length) {
243
291
  if (arrowEdge === 'left' || arrowEdge === 'right') {
@@ -288,6 +336,7 @@ function getCombinedSplitTooltipTarget(layouts) {
288
336
  function getSideSplitTooltipLayouts(layouts) {
289
337
  if (layouts.every((layout) => layout.targetMode === 'auto')) {
290
338
  return [...layouts].sort((a, b) => a.anchor.top - b.anchor.top ||
339
+ a.anchor.bottom - b.anchor.bottom ||
291
340
  a.anchor.left - b.anchor.left ||
292
341
  a.order - b.order);
293
342
  }
@@ -662,6 +711,15 @@ function getSidePlacementCandidates(layout, placedLayouts, allLayouts, bounds) {
662
711
  ];
663
712
  if (layout.targetMode === 'auto') {
664
713
  const connectorlessRange = getSideConnectorlessTopRange(layout);
714
+ const exactConnectorlessRange = getExactSideConnectorlessTopRange(layout);
715
+ candidates.push({
716
+ top: exactConnectorlessRange.min,
717
+ arrowEdge: layout.arrowEdge,
718
+ });
719
+ candidates.push({
720
+ top: exactConnectorlessRange.max,
721
+ arrowEdge: layout.arrowEdge,
722
+ });
665
723
  candidates.push({
666
724
  top: connectorlessRange.min,
667
725
  arrowEdge: layout.arrowEdge,
@@ -750,6 +808,17 @@ function getFixedPointSideSpreadPreferredTop(layout, direction) {
750
808
  return layout.targetY - TOOLTIP_CONNECTOR_INSET_PX;
751
809
  }
752
810
  function getSideConnectorlessTopRange(layout) {
811
+ const nearPathPadding = layout.targetMode === 'auto'
812
+ ? AUTO_BAR_TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX
813
+ : 0;
814
+ return {
815
+ min: layout.anchor.top -
816
+ getTooltipConnectorMaxOffset(layout.height) -
817
+ nearPathPadding,
818
+ max: layout.anchor.bottom - TOOLTIP_CONNECTOR_INSET_PX + nearPathPadding,
819
+ };
820
+ }
821
+ function getExactSideConnectorlessTopRange(layout) {
753
822
  return {
754
823
  min: layout.anchor.top - getTooltipConnectorMaxOffset(layout.height),
755
824
  max: layout.anchor.bottom - TOOLTIP_CONNECTOR_INSET_PX,
@@ -757,7 +826,9 @@ function getSideConnectorlessTopRange(layout) {
757
826
  }
758
827
  function isSidePlacementConnectorless(candidate, layout) {
759
828
  if (layout.targetMode === 'auto') {
760
- return doRangesOverlap(layout.anchor.top, layout.anchor.bottom, candidate.top + TOOLTIP_CONNECTOR_INSET_PX, candidate.top + getTooltipConnectorMaxOffset(layout.height));
829
+ const connectorlessRange = getSideConnectorlessTopRange(layout);
830
+ return (candidate.top >= connectorlessRange.min &&
831
+ candidate.top <= connectorlessRange.max);
761
832
  }
762
833
  const arrowTipY = getSidePlacementArrowTipY(candidate.top, layout);
763
834
  return (arrowTipY >=
@@ -6,7 +6,7 @@ import type { Scatter } from '../scatter.js';
6
6
  import type { TooltipTransitionConfig } from '../types.js';
7
7
  export declare const TOOLTIP_OFFSET_PX = 12;
8
8
  export declare const TOOLTIP_VIEWPORT_PADDING_PX = 10;
9
- export declare const TOOLTIP_CONNECTOR_INSET_PX = 14;
9
+ export declare const TOOLTIP_CONNECTOR_INSET_PX = 10;
10
10
  export declare const TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX = 16;
11
11
  export declare const TOOLTIP_CONNECTOR_PADDING_PX = 4;
12
12
  export declare const TOOLTIP_CONNECTOR_ELBOW_RATIO = 0.45;
@@ -20,7 +20,7 @@ export declare const TOOLTIP_ARROW_FILL_Z_INDEX = 5;
20
20
  export declare const TOOLTIP_BODY_Z_INDEX = 6;
21
21
  export declare const TOOLTIP_TOTAL_BORDER_WIDTH_PX: number;
22
22
  export declare const TOOLTIP_ROOT_Z_INDEX = 30;
23
- export declare const SPLIT_TOOLTIP_GAP_PX = 8;
23
+ export declare const SPLIT_TOOLTIP_GAP_PX = 4;
24
24
  export declare const DEFAULT_TOOLTIP_MAX_WIDTH_PX = 280;
25
25
  export declare const DEFAULT_TOOLTIP_TRANSITION: Required<TooltipTransitionConfig>;
26
26
  export declare const TOOLTIP_HIDDEN_TRANSFORM = "translateY(2px)";
@@ -1,6 +1,6 @@
1
1
  export const TOOLTIP_OFFSET_PX = 12;
2
2
  export const TOOLTIP_VIEWPORT_PADDING_PX = 10;
3
- export const TOOLTIP_CONNECTOR_INSET_PX = 14;
3
+ export const TOOLTIP_CONNECTOR_INSET_PX = 10;
4
4
  export const TOOLTIP_CONNECTOR_MIN_PATH_LENGTH_PX = 16;
5
5
  export const TOOLTIP_CONNECTOR_PADDING_PX = 4;
6
6
  export const TOOLTIP_CONNECTOR_ELBOW_RATIO = 0.45;
@@ -14,7 +14,7 @@ export const TOOLTIP_ARROW_FILL_Z_INDEX = 5;
14
14
  export const TOOLTIP_BODY_Z_INDEX = 6;
15
15
  export const TOOLTIP_TOTAL_BORDER_WIDTH_PX = TOOLTIP_BORDER_WIDTH_PX * 2;
16
16
  export const TOOLTIP_ROOT_Z_INDEX = 30;
17
- export const SPLIT_TOOLTIP_GAP_PX = 8;
17
+ export const SPLIT_TOOLTIP_GAP_PX = 4;
18
18
  export const DEFAULT_TOOLTIP_MAX_WIDTH_PX = 280;
19
19
  export const DEFAULT_TOOLTIP_TRANSITION = {
20
20
  show: false,
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.18.1",
2
+ "version": "0.18.2",
3
3
  "name": "@internetstiftelsen/charts",
4
4
  "type": "module",
5
5
  "sideEffects": false,