@internetstiftelsen/charts 0.18.2 → 0.19.1
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 +3 -1
- package/dist/legend.d.ts +4 -1
- package/dist/legend.js +38 -3
- package/dist/radial-chart-base.d.ts +4 -0
- package/dist/radial-chart-base.js +16 -4
- package/dist/tooltip/dom.d.ts +4 -0
- package/dist/tooltip/dom.js +41 -4
- package/dist/tooltip/xy-interaction.js +25 -1
- package/dist/types.d.ts +4 -1
- package/docs/components.md +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -255,7 +255,9 @@ axis, and responsive behavior. `ChartGroup.height` behaves like chart height:
|
|
|
255
255
|
set it for a fixed total group height, or omit it to size from the render
|
|
256
256
|
container. Set `syncY: true` when you want vertical `XYChart` children to share
|
|
257
257
|
the same Y domain so grid lines stay aligned while only one child renders a
|
|
258
|
-
visible Y axis.
|
|
258
|
+
visible Y axis. Legend rows wrap automatically, with `align` positioning the
|
|
259
|
+
legend block and `textAlign` aligning rows inside it:
|
|
260
|
+
`new Legend({ align: 'center', textAlign: 'left' })`.
|
|
259
261
|
|
|
260
262
|
`ChartGroup` also supports declarative responsive layout overrides. Group
|
|
261
263
|
breakpoints can change `cols` and `gap`, while `addChart(..., options)` can
|
package/dist/legend.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Selection } from 'd3';
|
|
2
|
-
import type { LegendConfig, ChartTheme, LegendSeries, ExportHooks, LegendConfigBase, LegendMode } from './types.js';
|
|
2
|
+
import type { LegendConfig, ChartTheme, HorizontalAlignment, LegendSeries, ExportHooks, LegendConfigBase, LegendMode } from './types.js';
|
|
3
3
|
import type { LayoutAwareComponent, ComponentSpace } from './chart-interface.js';
|
|
4
4
|
import { LegendStateController } from './legend-state.js';
|
|
5
5
|
export declare class Legend implements LayoutAwareComponent<LegendConfigBase> {
|
|
@@ -7,6 +7,8 @@ export declare class Legend implements LayoutAwareComponent<LegendConfigBase> {
|
|
|
7
7
|
mode: LegendMode;
|
|
8
8
|
readonly position: LegendConfig['position'];
|
|
9
9
|
readonly disconnectedTarget?: string | HTMLElement;
|
|
10
|
+
readonly align: HorizontalAlignment;
|
|
11
|
+
readonly textAlign: HorizontalAlignment;
|
|
10
12
|
readonly exportHooks?: ExportHooks<LegendConfigBase>;
|
|
11
13
|
private readonly marginTop;
|
|
12
14
|
private readonly marginBottom;
|
|
@@ -53,5 +55,6 @@ export declare class Legend implements LayoutAwareComponent<LegendConfigBase> {
|
|
|
53
55
|
private positionRows;
|
|
54
56
|
private getLayoutSignature;
|
|
55
57
|
private getFallbackRowHeight;
|
|
58
|
+
private getAlignmentOffset;
|
|
56
59
|
private bindStateController;
|
|
57
60
|
}
|
package/dist/legend.js
CHANGED
|
@@ -28,6 +28,18 @@ export class Legend {
|
|
|
28
28
|
writable: true,
|
|
29
29
|
value: void 0
|
|
30
30
|
});
|
|
31
|
+
Object.defineProperty(this, "align", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: void 0
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(this, "textAlign", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
value: void 0
|
|
42
|
+
});
|
|
31
43
|
Object.defineProperty(this, "exportHooks", {
|
|
32
44
|
enumerable: true,
|
|
33
45
|
configurable: true,
|
|
@@ -106,10 +118,12 @@ export class Legend {
|
|
|
106
118
|
writable: true,
|
|
107
119
|
value: null
|
|
108
120
|
});
|
|
109
|
-
const { mode = 'inline', position = 'bottom', disconnectedTarget, marginTop = 20, marginBottom = 10, paddingX, itemSpacingX, itemSpacingY, exportHooks, } = config ?? {};
|
|
121
|
+
const { mode = 'inline', position = 'bottom', disconnectedTarget, align = 'center', textAlign = 'center', marginTop = 20, marginBottom = 10, paddingX, itemSpacingX, itemSpacingY, exportHooks, } = config ?? {};
|
|
110
122
|
this.mode = mode;
|
|
111
123
|
this.position = position;
|
|
112
124
|
this.disconnectedTarget = disconnectedTarget;
|
|
125
|
+
this.align = align;
|
|
126
|
+
this.textAlign = textAlign;
|
|
113
127
|
this.marginTop = marginTop;
|
|
114
128
|
this.marginBottom = marginBottom;
|
|
115
129
|
this.paddingX = paddingX;
|
|
@@ -124,6 +138,8 @@ export class Legend {
|
|
|
124
138
|
mode: this.mode,
|
|
125
139
|
position: this.position,
|
|
126
140
|
disconnectedTarget: this.disconnectedTarget,
|
|
141
|
+
align: this.align,
|
|
142
|
+
textAlign: this.textAlign,
|
|
127
143
|
marginTop: this.marginTop,
|
|
128
144
|
marginBottom: this.marginBottom,
|
|
129
145
|
paddingX: this.paddingX,
|
|
@@ -335,6 +351,8 @@ export class Legend {
|
|
|
335
351
|
paddingX: this.paddingX ?? theme.legend.paddingX,
|
|
336
352
|
itemSpacingX: this.itemSpacingX ?? theme.legend.itemSpacingX,
|
|
337
353
|
itemSpacingY: this.itemSpacingY ?? theme.legend.itemSpacingY,
|
|
354
|
+
align: this.align,
|
|
355
|
+
textAlign: this.textAlign,
|
|
338
356
|
};
|
|
339
357
|
}
|
|
340
358
|
buildLegendItems(series) {
|
|
@@ -402,10 +420,15 @@ export class Legend {
|
|
|
402
420
|
positionRows(rows, width, settings) {
|
|
403
421
|
const positionedItems = [];
|
|
404
422
|
const availableWidth = Math.max(0, width - settings.paddingX * 2);
|
|
423
|
+
const legendBlockWidth = rows.reduce((maxWidth, row) => {
|
|
424
|
+
return Math.max(maxWidth, row.width);
|
|
425
|
+
}, 0);
|
|
426
|
+
const legendBlockX = settings.paddingX +
|
|
427
|
+
this.getAlignmentOffset(availableWidth, legendBlockWidth, settings.align);
|
|
405
428
|
let accumulatedRowHeight = 0;
|
|
406
429
|
rows.forEach((row, rowIndex) => {
|
|
407
|
-
const rowX =
|
|
408
|
-
|
|
430
|
+
const rowX = legendBlockX +
|
|
431
|
+
this.getAlignmentOffset(legendBlockWidth, row.width, settings.textAlign);
|
|
409
432
|
const rowY = accumulatedRowHeight + rowIndex * settings.itemSpacingY;
|
|
410
433
|
let currentX = rowX;
|
|
411
434
|
row.items.forEach((item, itemIndex) => {
|
|
@@ -433,6 +456,8 @@ export class Legend {
|
|
|
433
456
|
theme.legend.paddingX,
|
|
434
457
|
theme.legend.itemSpacingX,
|
|
435
458
|
theme.legend.itemSpacingY,
|
|
459
|
+
this.align,
|
|
460
|
+
this.textAlign,
|
|
436
461
|
this.paddingX ?? '',
|
|
437
462
|
this.itemSpacingX ?? '',
|
|
438
463
|
this.itemSpacingY ?? '',
|
|
@@ -442,6 +467,16 @@ export class Legend {
|
|
|
442
467
|
getFallbackRowHeight(theme) {
|
|
443
468
|
return Math.max(theme.legend.boxSize, theme.legend.fontSize);
|
|
444
469
|
}
|
|
470
|
+
getAlignmentOffset(availableWidth, rowWidth, align) {
|
|
471
|
+
const remainingWidth = Math.max(0, availableWidth - rowWidth);
|
|
472
|
+
if (align === 'left') {
|
|
473
|
+
return 0;
|
|
474
|
+
}
|
|
475
|
+
if (align === 'right') {
|
|
476
|
+
return remainingWidth;
|
|
477
|
+
}
|
|
478
|
+
return remainingWidth / 2;
|
|
479
|
+
}
|
|
445
480
|
bindStateController(controller) {
|
|
446
481
|
this.stateControllerCleanup?.();
|
|
447
482
|
this.stateController = controller;
|
|
@@ -39,6 +39,10 @@ export declare abstract class RadialChartBase extends BaseChart {
|
|
|
39
39
|
protected showTooltipAtElement(target: Element, content: string): void;
|
|
40
40
|
protected hideTooltip(): void;
|
|
41
41
|
private applyTooltipPosition;
|
|
42
|
+
private getTooltipViewportLeft;
|
|
43
|
+
private getTooltipViewportRight;
|
|
44
|
+
private getTooltipViewportTop;
|
|
45
|
+
private getTooltipViewportBottom;
|
|
42
46
|
private resolveRadialLabelLayout;
|
|
43
47
|
private resolveRadialLabelOverflowContext;
|
|
44
48
|
private createVisibleRadialLabelLayout;
|
|
@@ -159,7 +159,7 @@ export class RadialChartBase extends BaseChart {
|
|
|
159
159
|
}
|
|
160
160
|
let x = event.pageX + TOOLTIP_OFFSET_PX;
|
|
161
161
|
const y = event.pageY - rect.height / 2;
|
|
162
|
-
if (x + rect.width >
|
|
162
|
+
if (x + rect.width > this.getTooltipViewportRight()) {
|
|
163
163
|
x = event.pageX - rect.width - TOOLTIP_OFFSET_PX;
|
|
164
164
|
}
|
|
165
165
|
this.applyTooltipPosition(x, y, rect.height, rect.width);
|
|
@@ -182,7 +182,7 @@ export class RadialChartBase extends BaseChart {
|
|
|
182
182
|
window.scrollY +
|
|
183
183
|
targetRect.height / 2 -
|
|
184
184
|
tooltipRect.height / 2;
|
|
185
|
-
if (x + tooltipRect.width >
|
|
185
|
+
if (x + tooltipRect.width > this.getTooltipViewportRight()) {
|
|
186
186
|
x =
|
|
187
187
|
targetRect.left +
|
|
188
188
|
window.scrollX -
|
|
@@ -195,10 +195,22 @@ export class RadialChartBase extends BaseChart {
|
|
|
195
195
|
this.tooltip?.hide();
|
|
196
196
|
}
|
|
197
197
|
applyTooltipPosition(rawX, rawY, height, width) {
|
|
198
|
-
const x = Math.max(
|
|
199
|
-
const y = Math.max(
|
|
198
|
+
const x = Math.max(this.getTooltipViewportLeft(), Math.min(rawX, this.getTooltipViewportRight() - width));
|
|
199
|
+
const y = Math.max(this.getTooltipViewportTop(), Math.min(rawY, this.getTooltipViewportBottom() - height));
|
|
200
200
|
this.tooltip?.showAt(x, y);
|
|
201
201
|
}
|
|
202
|
+
getTooltipViewportLeft() {
|
|
203
|
+
return window.scrollX + EDGE_MARGIN_PX;
|
|
204
|
+
}
|
|
205
|
+
getTooltipViewportRight() {
|
|
206
|
+
return window.scrollX + window.innerWidth - EDGE_MARGIN_PX;
|
|
207
|
+
}
|
|
208
|
+
getTooltipViewportTop() {
|
|
209
|
+
return window.scrollY + EDGE_MARGIN_PX;
|
|
210
|
+
}
|
|
211
|
+
getTooltipViewportBottom() {
|
|
212
|
+
return window.scrollY + window.innerHeight - EDGE_MARGIN_PX;
|
|
213
|
+
}
|
|
202
214
|
resolveRadialLabelLayout(text, options) {
|
|
203
215
|
const overflowContext = this.resolveRadialLabelOverflowContext(options.maxLabelWidth);
|
|
204
216
|
if (!overflowContext) {
|
package/dist/tooltip/dom.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare class TooltipDom {
|
|
|
17
17
|
private readonly transition;
|
|
18
18
|
private readonly tooltipStyleKeys;
|
|
19
19
|
private readonly tooltipTransitionFrameIds;
|
|
20
|
+
private readonly tooltipPositionResetTimeoutIds;
|
|
20
21
|
private readonly tooltipStyles;
|
|
21
22
|
private tooltipDiv;
|
|
22
23
|
constructor(config: TooltipDomConfig);
|
|
@@ -45,6 +46,9 @@ export declare class TooltipDom {
|
|
|
45
46
|
private showTooltipAt;
|
|
46
47
|
private showTooltipSelection;
|
|
47
48
|
private hideTooltipElement;
|
|
49
|
+
private resetTooltipPosition;
|
|
50
|
+
private scheduleTooltipPositionReset;
|
|
51
|
+
private cancelTooltipPositionReset;
|
|
48
52
|
private getTooltipTransitionStyle;
|
|
49
53
|
private isTooltipVisible;
|
|
50
54
|
private getTooltipPosition;
|
package/dist/tooltip/dom.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { select } from 'd3';
|
|
2
2
|
import { resolveTooltipArrowPosition, resolveTooltipConnectorLayout, } from './geometry.js';
|
|
3
3
|
import { TOOLTIP_ARROW_BORDER_Z_INDEX, TOOLTIP_ARROW_FILL_Z_INDEX, TOOLTIP_BODY_Z_INDEX, TOOLTIP_BORDER_WIDTH_PX, TOOLTIP_BOX_ARROW_HALF_HEIGHT_PX, TOOLTIP_BOX_ARROW_LENGTH_PX, TOOLTIP_CONNECTOR_Z_INDEX, TOOLTIP_HIDDEN_TRANSFORM, TOOLTIP_ROOT_Z_INDEX, TOOLTIP_VISIBLE_TRANSFORM, } from './types.js';
|
|
4
|
+
const HIDDEN_TOOLTIP_POSITION_PX = '0px';
|
|
4
5
|
export class TooltipDom {
|
|
5
6
|
constructor(config) {
|
|
6
7
|
Object.defineProperty(this, "id", {
|
|
@@ -39,6 +40,12 @@ export class TooltipDom {
|
|
|
39
40
|
writable: true,
|
|
40
41
|
value: new WeakMap()
|
|
41
42
|
});
|
|
43
|
+
Object.defineProperty(this, "tooltipPositionResetTimeoutIds", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: new WeakMap()
|
|
48
|
+
});
|
|
42
49
|
Object.defineProperty(this, "tooltipStyles", {
|
|
43
50
|
enumerable: true,
|
|
44
51
|
configurable: true,
|
|
@@ -284,15 +291,16 @@ export class TooltipDom {
|
|
|
284
291
|
: null);
|
|
285
292
|
}
|
|
286
293
|
showTooltipSelection(tooltip, slideOffset = null) {
|
|
294
|
+
const node = tooltip.node();
|
|
295
|
+
if (!node) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
this.cancelTooltipPositionReset(node);
|
|
287
299
|
tooltip.style('visibility', 'visible');
|
|
288
300
|
if (!this.transition.show) {
|
|
289
301
|
return;
|
|
290
302
|
}
|
|
291
303
|
tooltip.style('opacity', '1');
|
|
292
|
-
const node = tooltip.node();
|
|
293
|
-
if (!node) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
304
|
if (!slideOffset || !this.hasVisibleSlideOffset(slideOffset)) {
|
|
297
305
|
this.cancelTooltipTransitionFrame(node);
|
|
298
306
|
tooltip.style('transform', TOOLTIP_VISIBLE_TRANSFORM);
|
|
@@ -301,14 +309,43 @@ export class TooltipDom {
|
|
|
301
309
|
this.slideTooltipFromOffset(node, slideOffset);
|
|
302
310
|
}
|
|
303
311
|
hideTooltipElement(node) {
|
|
312
|
+
const wasVisible = this.isTooltipVisible(node);
|
|
313
|
+
this.cancelTooltipPositionReset(node);
|
|
304
314
|
this.cancelTooltipTransitionFrame(node);
|
|
305
315
|
if (!this.transition.show) {
|
|
306
316
|
node.style.visibility = 'hidden';
|
|
317
|
+
this.resetTooltipPosition(node);
|
|
307
318
|
return;
|
|
308
319
|
}
|
|
309
320
|
node.style.visibility = 'visible';
|
|
310
321
|
node.style.opacity = '0';
|
|
311
322
|
node.style.transform = TOOLTIP_HIDDEN_TRANSFORM;
|
|
323
|
+
if (!wasVisible) {
|
|
324
|
+
this.resetTooltipPosition(node);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
this.scheduleTooltipPositionReset(node);
|
|
328
|
+
}
|
|
329
|
+
resetTooltipPosition(node) {
|
|
330
|
+
node.style.left = HIDDEN_TOOLTIP_POSITION_PX;
|
|
331
|
+
node.style.top = HIDDEN_TOOLTIP_POSITION_PX;
|
|
332
|
+
}
|
|
333
|
+
scheduleTooltipPositionReset(node) {
|
|
334
|
+
const timeoutId = window.setTimeout(() => {
|
|
335
|
+
this.tooltipPositionResetTimeoutIds.delete(node);
|
|
336
|
+
if (!this.isTooltipVisible(node)) {
|
|
337
|
+
this.resetTooltipPosition(node);
|
|
338
|
+
}
|
|
339
|
+
}, this.transition.duration);
|
|
340
|
+
this.tooltipPositionResetTimeoutIds.set(node, timeoutId);
|
|
341
|
+
}
|
|
342
|
+
cancelTooltipPositionReset(node) {
|
|
343
|
+
const timeoutId = this.tooltipPositionResetTimeoutIds.get(node);
|
|
344
|
+
if (timeoutId === undefined) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
window.clearTimeout(timeoutId);
|
|
348
|
+
this.tooltipPositionResetTimeoutIds.delete(node);
|
|
312
349
|
}
|
|
313
350
|
getTooltipTransitionStyle() {
|
|
314
351
|
return `opacity ${this.transition.duration}ms ${this.transition.easing}, transform ${this.transition.duration}ms ${this.transition.easing}`;
|
|
@@ -517,12 +517,36 @@ function getClosestSingleTooltipCandidate(candidates, request) {
|
|
|
517
517
|
!Number.isFinite(request.pointerY)) {
|
|
518
518
|
return candidates[0];
|
|
519
519
|
}
|
|
520
|
+
const touchedBarCandidate = getTouchedBarTooltipCandidate(candidates, request);
|
|
521
|
+
if (touchedBarCandidate) {
|
|
522
|
+
return touchedBarCandidate;
|
|
523
|
+
}
|
|
520
524
|
return candidates.reduce((closest, candidate) => {
|
|
521
525
|
const closestDistance = getSingleTooltipDistance(closest, request);
|
|
522
526
|
const candidateDistance = getSingleTooltipDistance(candidate, request);
|
|
523
527
|
return candidateDistance < closestDistance ? candidate : closest;
|
|
524
528
|
});
|
|
525
529
|
}
|
|
530
|
+
function getTouchedBarTooltipCandidate(candidates, request) {
|
|
531
|
+
const touchedBarCandidates = candidates.filter((candidate) => {
|
|
532
|
+
return (candidate.series.type === 'bar' &&
|
|
533
|
+
isPointerInsideAnchor(request, candidate.anchor));
|
|
534
|
+
});
|
|
535
|
+
return touchedBarCandidates[touchedBarCandidates.length - 1] ?? null;
|
|
536
|
+
}
|
|
537
|
+
function isPointerInsideAnchor(request, anchor) {
|
|
538
|
+
const { pointerX, pointerY } = request;
|
|
539
|
+
if (pointerX === undefined ||
|
|
540
|
+
pointerY === undefined ||
|
|
541
|
+
!Number.isFinite(pointerX) ||
|
|
542
|
+
!Number.isFinite(pointerY)) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
return (pointerX >= anchor.left &&
|
|
546
|
+
pointerX <= anchor.right &&
|
|
547
|
+
pointerY >= anchor.top &&
|
|
548
|
+
pointerY <= anchor.bottom);
|
|
549
|
+
}
|
|
526
550
|
function getSingleTooltipDistance(candidate, request) {
|
|
527
551
|
const deltaX = (request.pointerX ?? 0) - candidate.target.x;
|
|
528
552
|
const deltaY = (request.pointerY ?? 0) - candidate.target.y;
|
|
@@ -785,7 +809,7 @@ function attachTooltipScrollListeners(svgNode, onScroll) {
|
|
|
785
809
|
};
|
|
786
810
|
}
|
|
787
811
|
function getTooltipScrollTargets(svgNode) {
|
|
788
|
-
const scrollTargets = new Set(
|
|
812
|
+
const scrollTargets = new Set();
|
|
789
813
|
let currentElement = svgNode.parentElement;
|
|
790
814
|
while (currentElement) {
|
|
791
815
|
if (isScrollableElement(currentElement)) {
|
package/dist/types.d.ts
CHANGED
|
@@ -330,10 +330,13 @@ export type TooltipConfigBase = {
|
|
|
330
330
|
export type TooltipConfig = TooltipConfigBase & {
|
|
331
331
|
exportHooks?: ExportHooks<TooltipConfigBase>;
|
|
332
332
|
};
|
|
333
|
+
export type HorizontalAlignment = 'left' | 'center' | 'right';
|
|
333
334
|
export type LegendConfigBase = {
|
|
334
335
|
mode?: LegendMode;
|
|
335
336
|
position?: 'bottom';
|
|
336
337
|
disconnectedTarget?: string | HTMLElement;
|
|
338
|
+
align?: HorizontalAlignment;
|
|
339
|
+
textAlign?: HorizontalAlignment;
|
|
337
340
|
marginTop?: number;
|
|
338
341
|
marginBottom?: number;
|
|
339
342
|
paddingX?: number;
|
|
@@ -355,7 +358,7 @@ export type LegendItem = {
|
|
|
355
358
|
visible: boolean;
|
|
356
359
|
};
|
|
357
360
|
export type TextPosition = 'top' | 'bottom';
|
|
358
|
-
export type TextAlign =
|
|
361
|
+
export type TextAlign = HorizontalAlignment;
|
|
359
362
|
export type TextVariantStyle = {
|
|
360
363
|
fontSize?: number;
|
|
361
364
|
fontWeight?: string;
|
package/docs/components.md
CHANGED
|
@@ -211,6 +211,8 @@ new Legend({
|
|
|
211
211
|
mode?: 'inline' | 'disconnected' | 'hidden', // Rendering mode (default: 'inline')
|
|
212
212
|
position?: 'bottom', // Position (currently only 'bottom')
|
|
213
213
|
disconnectedTarget?: string | HTMLElement, // External mount target when mode is 'disconnected'
|
|
214
|
+
align?: 'left' | 'center' | 'right', // Legend block alignment (default: 'center')
|
|
215
|
+
textAlign?: 'left' | 'center' | 'right', // Wrapped row alignment within the legend block (default: 'center')
|
|
214
216
|
marginTop?: number, // Space above legend (default: 20)
|
|
215
217
|
marginBottom?: number, // Space below legend (default: 10)
|
|
216
218
|
paddingX?: number, // Horizontal inset for legend layout (default: theme.legend.paddingX)
|
|
@@ -220,7 +222,10 @@ new Legend({
|
|
|
220
222
|
```
|
|
221
223
|
|
|
222
224
|
Legend items automatically wrap to new rows when they do not fit available
|
|
223
|
-
width.
|
|
225
|
+
width. The widest wrapped row defines the legend block. Use `align` to position
|
|
226
|
+
that block and `textAlign` to align rows inside it, for example
|
|
227
|
+
`{ align: 'center', textAlign: 'left' }` for a centered legend with
|
|
228
|
+
left-aligned wrapped rows.
|
|
224
229
|
|
|
225
230
|
- `inline`: current default behavior (legend rendered inside the chart SVG)
|
|
226
231
|
- `disconnected`: legend rendered in a separate SVG outside chart layout
|
package/package.json
CHANGED