@internetstiftelsen/charts 0.16.0 → 0.17.0
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.
- package/README.md +1 -1
- package/dist/tooltip/dom.d.ts +6 -2
- package/dist/tooltip/dom.js +46 -27
- package/dist/tooltip/geometry.d.ts +4 -3
- package/dist/tooltip/geometry.js +496 -34
- package/dist/tooltip/types.d.ts +2 -0
- package/dist/tooltip/xy-interaction.d.ts +2 -1
- package/dist/tooltip/xy-interaction.js +219 -36
- package/dist/tooltip.d.ts +2 -1
- package/dist/tooltip.js +10 -1
- package/dist/types.d.ts +5 -3
- package/docs/components.md +20 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ A framework-agnostic, composable charting library built on D3.js with TypeScript
|
|
|
16
16
|
- **Optional Radial Animation** - Animate pie and donut segments on first render and `chart.update(...)` with `animate`
|
|
17
17
|
- **Optional Gauge Animation** - Animate gauge value transitions with `gauge.animate`
|
|
18
18
|
- **Stacking Control** - Bar and area stacking modes with optional reversed visual series order
|
|
19
|
-
- **Configurable Tooltips** - Shared or
|
|
19
|
+
- **Configurable Tooltips** - Shared, split, or single tooltips with connectors, transitions, color-coded series styling, and default max-width wrapping
|
|
20
20
|
- **Axis Direction Control** - Use `scales.x.reverse` / `scales.y.reverse` to flip an axis when needed
|
|
21
21
|
- **Flexible Scales** - Band, linear, time, and logarithmic scales (bar value axes stay linear)
|
|
22
22
|
- **Explicit or Responsive Sizing** - Set top-level `width`/`height` or let the container drive size
|
package/dist/tooltip/dom.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ type TooltipDomConfig = {
|
|
|
6
6
|
maxWidth: number;
|
|
7
7
|
transition: Required<TooltipTransitionConfig>;
|
|
8
8
|
};
|
|
9
|
+
export type TooltipStyleOverrides = Partial<Pick<ChartTheme['tooltip'], 'background' | 'border' | 'color'>>;
|
|
9
10
|
export declare class TooltipDom {
|
|
10
11
|
private readonly id;
|
|
11
12
|
private readonly splitTooltipOwner;
|
|
@@ -13,11 +14,12 @@ export declare class TooltipDom {
|
|
|
13
14
|
private readonly transition;
|
|
14
15
|
private readonly tooltipStyleKeys;
|
|
15
16
|
private readonly tooltipTransitionFrameIds;
|
|
17
|
+
private readonly tooltipStyles;
|
|
16
18
|
private tooltipDiv;
|
|
17
|
-
private tooltipTheme;
|
|
18
19
|
constructor(config: TooltipDomConfig);
|
|
19
20
|
initialize(theme: ChartTheme): void;
|
|
20
21
|
getRootTooltip(): TooltipDivSelection | null;
|
|
22
|
+
applyRootTooltipStyles(theme: ChartTheme, styleOverrides?: TooltipStyleOverrides): void;
|
|
21
23
|
setContent(content: string): void;
|
|
22
24
|
getBounds(): DOMRect | null;
|
|
23
25
|
showAt(left: number, top: number): void;
|
|
@@ -30,10 +32,11 @@ export declare class TooltipDom {
|
|
|
30
32
|
renderTooltipWithConnector(tooltip: TooltipDivSelection, arrowEdge: TooltipArrowEdge, left: number, top: number, tooltipWidth: number, tooltipHeight: number, targetX: number, targetY: number, anchor: TooltipAnchor): void;
|
|
31
33
|
renderTooltipWithoutConnector(tooltip: TooltipDivSelection, left: number, top: number): void;
|
|
32
34
|
hideTooltipSelection(tooltip: TooltipDivSelection): void;
|
|
33
|
-
getSplitTooltip(index: number, theme: ChartTheme): TooltipDivSelection;
|
|
35
|
+
getSplitTooltip(index: number, theme: ChartTheme, styleOverrides?: TooltipStyleOverrides): TooltipDivSelection;
|
|
34
36
|
hideSplitTooltips(): void;
|
|
35
37
|
hideUnusedSplitTooltips(visibleTooltips: TooltipDivSelection[]): void;
|
|
36
38
|
private applyTooltipStylesIfNeeded;
|
|
39
|
+
private resolveTooltipStyle;
|
|
37
40
|
private getTooltipStyleKey;
|
|
38
41
|
private writeTooltipStyles;
|
|
39
42
|
private showTooltipAt;
|
|
@@ -50,6 +53,7 @@ export declare class TooltipDom {
|
|
|
50
53
|
private appendTooltipConnector;
|
|
51
54
|
private appendTooltipArrow;
|
|
52
55
|
private appendTooltipArrowTriangle;
|
|
56
|
+
private getTooltipStyle;
|
|
53
57
|
private removeSplitTooltips;
|
|
54
58
|
private removeRootTooltip;
|
|
55
59
|
}
|
package/dist/tooltip/dom.js
CHANGED
|
@@ -39,13 +39,13 @@ export class TooltipDom {
|
|
|
39
39
|
writable: true,
|
|
40
40
|
value: new WeakMap()
|
|
41
41
|
});
|
|
42
|
-
Object.defineProperty(this, "
|
|
42
|
+
Object.defineProperty(this, "tooltipStyles", {
|
|
43
43
|
enumerable: true,
|
|
44
44
|
configurable: true,
|
|
45
45
|
writable: true,
|
|
46
|
-
value:
|
|
46
|
+
value: new WeakMap()
|
|
47
47
|
});
|
|
48
|
-
Object.defineProperty(this, "
|
|
48
|
+
Object.defineProperty(this, "tooltipDiv", {
|
|
49
49
|
enumerable: true,
|
|
50
50
|
configurable: true,
|
|
51
51
|
writable: true,
|
|
@@ -72,6 +72,12 @@ export class TooltipDom {
|
|
|
72
72
|
getRootTooltip() {
|
|
73
73
|
return this.tooltipDiv;
|
|
74
74
|
}
|
|
75
|
+
applyRootTooltipStyles(theme, styleOverrides) {
|
|
76
|
+
if (!this.tooltipDiv) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.applyTooltipStylesIfNeeded(this.tooltipDiv, theme, styleOverrides);
|
|
80
|
+
}
|
|
75
81
|
setContent(content) {
|
|
76
82
|
if (!this.tooltipDiv) {
|
|
77
83
|
return;
|
|
@@ -158,7 +164,7 @@ export class TooltipDom {
|
|
|
158
164
|
}
|
|
159
165
|
this.hideTooltipElement(node);
|
|
160
166
|
}
|
|
161
|
-
getSplitTooltip(index, theme) {
|
|
167
|
+
getSplitTooltip(index, theme, styleOverrides) {
|
|
162
168
|
const tooltipId = `${this.splitTooltipOwner}-${index}`;
|
|
163
169
|
const existingTooltip = select(`#${tooltipId}`);
|
|
164
170
|
const tooltip = existingTooltip.empty()
|
|
@@ -169,7 +175,7 @@ export class TooltipDom {
|
|
|
169
175
|
.attr('data-chart-tooltip-owner', this.splitTooltipOwner)
|
|
170
176
|
.attr('data-chart-tooltip-index', String(index))
|
|
171
177
|
: existingTooltip;
|
|
172
|
-
this.applyTooltipStylesIfNeeded(tooltip, theme);
|
|
178
|
+
this.applyTooltipStylesIfNeeded(tooltip, theme, styleOverrides);
|
|
173
179
|
return tooltip;
|
|
174
180
|
}
|
|
175
181
|
hideSplitTooltips() {
|
|
@@ -192,46 +198,53 @@ export class TooltipDom {
|
|
|
192
198
|
this.hideTooltipElement(node);
|
|
193
199
|
});
|
|
194
200
|
}
|
|
195
|
-
applyTooltipStylesIfNeeded(tooltip, theme) {
|
|
201
|
+
applyTooltipStylesIfNeeded(tooltip, theme, styleOverrides) {
|
|
196
202
|
const node = tooltip.node();
|
|
197
203
|
if (!node) {
|
|
198
204
|
return;
|
|
199
205
|
}
|
|
200
|
-
const
|
|
206
|
+
const tooltipStyle = this.resolveTooltipStyle(theme, styleOverrides);
|
|
207
|
+
const styleKey = this.getTooltipStyleKey(tooltipStyle);
|
|
201
208
|
if (this.tooltipStyleKeys.get(node) === styleKey) {
|
|
202
|
-
this.
|
|
209
|
+
this.tooltipStyles.set(node, tooltipStyle);
|
|
203
210
|
return;
|
|
204
211
|
}
|
|
205
212
|
this.tooltipStyleKeys.set(node, styleKey);
|
|
206
|
-
this.
|
|
213
|
+
this.tooltipStyles.set(node, tooltipStyle);
|
|
214
|
+
this.writeTooltipStyles(tooltip, tooltipStyle);
|
|
207
215
|
}
|
|
208
|
-
|
|
216
|
+
resolveTooltipStyle(theme, styleOverrides) {
|
|
217
|
+
return {
|
|
218
|
+
...theme.tooltip,
|
|
219
|
+
...styleOverrides,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
getTooltipStyleKey(tooltipStyle) {
|
|
209
223
|
return [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
224
|
+
tooltipStyle.background,
|
|
225
|
+
tooltipStyle.border,
|
|
226
|
+
tooltipStyle.color,
|
|
227
|
+
tooltipStyle.fontFamily,
|
|
228
|
+
tooltipStyle.fontSize,
|
|
229
|
+
tooltipStyle.fontWeight,
|
|
216
230
|
this.maxWidth,
|
|
217
231
|
this.transition.show,
|
|
218
232
|
this.transition.duration,
|
|
219
233
|
this.transition.easing,
|
|
220
234
|
].join('|');
|
|
221
235
|
}
|
|
222
|
-
writeTooltipStyles(tooltip,
|
|
223
|
-
this.tooltipTheme = theme.tooltip;
|
|
236
|
+
writeTooltipStyles(tooltip, tooltipStyle) {
|
|
224
237
|
tooltip
|
|
225
238
|
.style('position', 'absolute')
|
|
226
|
-
.style('background-color',
|
|
227
|
-
.style('border', `${TOOLTIP_BORDER_WIDTH_PX}px solid ${
|
|
239
|
+
.style('background-color', tooltipStyle.background)
|
|
240
|
+
.style('border', `${TOOLTIP_BORDER_WIDTH_PX}px solid ${tooltipStyle.border}`)
|
|
228
241
|
.style('border-radius', '4px')
|
|
229
242
|
.style('padding', '8px')
|
|
230
243
|
.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)')
|
|
231
|
-
.style('color',
|
|
232
|
-
.style('font-family',
|
|
233
|
-
.style('font-size', `${
|
|
234
|
-
.style('font-weight',
|
|
244
|
+
.style('color', tooltipStyle.color)
|
|
245
|
+
.style('font-family', tooltipStyle.fontFamily)
|
|
246
|
+
.style('font-size', `${tooltipStyle.fontSize}px`)
|
|
247
|
+
.style('font-weight', tooltipStyle.fontWeight)
|
|
235
248
|
.style('box-sizing', 'border-box')
|
|
236
249
|
.style('overflow-wrap', 'break-word')
|
|
237
250
|
.style('overflow', 'visible')
|
|
@@ -351,7 +364,8 @@ export class TooltipDom {
|
|
|
351
364
|
body.style('position', 'relative').style('z-index', String(TOOLTIP_BODY_Z_INDEX));
|
|
352
365
|
}
|
|
353
366
|
appendTooltipConnector(tooltip, connectorLayout) {
|
|
354
|
-
const
|
|
367
|
+
const tooltipStyle = this.getTooltipStyle(tooltip);
|
|
368
|
+
const tooltipBorder = tooltipStyle?.border ?? '#dddddd';
|
|
355
369
|
const connector = tooltip
|
|
356
370
|
.append('svg')
|
|
357
371
|
.attr('data-chart-tooltip-connector', 'true')
|
|
@@ -377,8 +391,9 @@ export class TooltipDom {
|
|
|
377
391
|
.attr('stroke-linejoin', 'round');
|
|
378
392
|
}
|
|
379
393
|
appendTooltipArrow(tooltip, connectorLayout) {
|
|
380
|
-
const
|
|
381
|
-
const
|
|
394
|
+
const tooltipStyle = this.getTooltipStyle(tooltip);
|
|
395
|
+
const tooltipBackground = tooltipStyle?.background ?? '#ffffff';
|
|
396
|
+
const tooltipBorder = tooltipStyle?.border ?? '#dddddd';
|
|
382
397
|
this.appendTooltipArrowTriangle(tooltip, connectorLayout, 'data-chart-tooltip-arrow', tooltipBorder, TOOLTIP_BOX_ARROW_LENGTH_PX, TOOLTIP_BOX_ARROW_HALF_HEIGHT_PX, TOOLTIP_ARROW_BORDER_Z_INDEX);
|
|
383
398
|
this.appendTooltipArrowTriangle(tooltip, connectorLayout, 'data-chart-tooltip-arrow-fill', tooltipBackground, TOOLTIP_BOX_ARROW_LENGTH_PX - 1, TOOLTIP_BOX_ARROW_HALF_HEIGHT_PX - 1, TOOLTIP_ARROW_FILL_Z_INDEX);
|
|
384
399
|
}
|
|
@@ -422,6 +437,10 @@ export class TooltipDom {
|
|
|
422
437
|
.style('border-right', `${halfHeight}px solid transparent`)
|
|
423
438
|
.style('border-top', `${length}px solid ${color}`);
|
|
424
439
|
}
|
|
440
|
+
getTooltipStyle(tooltip) {
|
|
441
|
+
const node = tooltip.node();
|
|
442
|
+
return node ? this.tooltipStyles.get(node) : undefined;
|
|
443
|
+
}
|
|
425
444
|
removeSplitTooltips() {
|
|
426
445
|
document
|
|
427
446
|
.querySelectorAll(`[data-chart-tooltip-owner="${this.splitTooltipOwner}"]`)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { TooltipBarAnchorPosition, TooltipPosition } from '../types.js';
|
|
2
2
|
import { type SplitTooltipLayout, type SplitTooltipViewportBounds, type TooltipAnchor, type TooltipArrowEdge, type TooltipConnectorLayout, type TooltipTarget, type XYTooltipSeries } from './types.js';
|
|
3
3
|
export declare function getSplitTooltipViewportBounds(): SplitTooltipViewportBounds;
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function clipTooltipAnchorToBounds(anchor: TooltipAnchor, bounds: SplitTooltipViewportBounds): TooltipAnchor;
|
|
5
|
+
export declare function resolveTooltipArrowEdge(position: TooltipPosition, anchor: TooltipAnchor, target: TooltipTarget, tooltipWidth: number, tooltipHeight: number, bounds?: SplitTooltipViewportBounds): TooltipArrowEdge;
|
|
5
6
|
export declare function resolveSidePlacementArrowEdge(anchor: TooltipAnchor, tooltipWidth: number, bounds?: SplitTooltipViewportBounds): TooltipArrowEdge;
|
|
6
7
|
export declare function resolveVerticalPlacementArrowEdge(target: TooltipTarget, tooltipHeight: number, bounds?: SplitTooltipViewportBounds): TooltipArrowEdge;
|
|
7
8
|
export declare function resolveSharedTooltipTarget(anchor: TooltipAnchor): TooltipTarget;
|
|
8
9
|
export declare function resolveSplitTooltipTarget(currentSeries: XYTooltipSeries, anchor: TooltipAnchor, barAnchorPosition: TooltipBarAnchorPosition): TooltipTarget;
|
|
9
|
-
export declare function getAnchoredTooltipPosition(anchor: TooltipAnchor, target: TooltipTarget, tooltipWidth: number, tooltipHeight: number, arrowEdge: TooltipArrowEdge): {
|
|
10
|
+
export declare function getAnchoredTooltipPosition(anchor: TooltipAnchor, target: TooltipTarget, tooltipWidth: number, tooltipHeight: number, arrowEdge: TooltipArrowEdge, bounds?: SplitTooltipViewportBounds): {
|
|
10
11
|
left: number;
|
|
11
12
|
top: number;
|
|
12
13
|
} | null;
|
|
@@ -15,4 +16,4 @@ export declare function resolveTooltipArrowPosition(arrowEdge: TooltipArrowEdge,
|
|
|
15
16
|
left: number;
|
|
16
17
|
top: number;
|
|
17
18
|
};
|
|
18
|
-
export declare function resolveSplitTooltipPositions(layouts: SplitTooltipLayout[], position: TooltipPosition): void;
|
|
19
|
+
export declare function resolveSplitTooltipPositions(layouts: SplitTooltipLayout[], position: TooltipPosition, bounds?: SplitTooltipViewportBounds, isHorizontal?: boolean): void;
|