layerchart 2.0.0-next.4 → 2.0.0-next.41
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/dist/components/AnnotationLine.svelte +15 -2
- package/dist/components/AnnotationPoint.svelte +29 -11
- package/dist/components/AnnotationRange.svelte +18 -4
- package/dist/components/Arc.svelte +5 -5
- package/dist/components/Area.svelte +10 -2
- package/dist/components/Axis.svelte +175 -58
- package/dist/components/Axis.svelte.d.ts +23 -6
- package/dist/components/Bar.svelte +20 -15
- package/dist/components/Bar.svelte.d.ts +2 -2
- package/dist/components/Bars.svelte +4 -4
- package/dist/components/Blur.svelte +7 -6
- package/dist/components/Blur.svelte.d.ts +2 -5
- package/dist/components/BrushContext.svelte +45 -45
- package/dist/components/Calendar.svelte +31 -10
- package/dist/components/Calendar.svelte.d.ts +2 -1
- package/dist/components/Chart.svelte +76 -27
- package/dist/components/Chart.svelte.d.ts +26 -8
- package/dist/components/ChartClipPath.svelte +1 -1
- package/dist/components/Circle.svelte +44 -3
- package/dist/components/CircleClipPath.svelte +8 -1
- package/dist/components/ClipPath.svelte +1 -2
- package/dist/components/ColorRamp.svelte +1 -1
- package/dist/components/ComputedStyles.svelte +9 -2
- package/dist/components/Connector.svelte +3 -3
- package/dist/components/Connector.svelte.d.ts +1 -1
- package/dist/components/Ellipse.svelte +228 -0
- package/dist/components/Ellipse.svelte.d.ts +64 -0
- package/dist/components/ForceSimulation.svelte +184 -50
- package/dist/components/ForceSimulation.svelte.d.ts +95 -21
- package/dist/components/Frame.svelte +1 -1
- package/dist/components/GeoCircle.svelte +1 -1
- package/dist/components/GeoEdgeFade.svelte +1 -1
- package/dist/components/GeoPath.svelte +30 -8
- package/dist/components/GeoPoint.svelte +4 -5
- package/dist/components/GeoSpline.svelte +5 -5
- package/dist/components/GeoSpline.svelte.d.ts +1 -1
- package/dist/components/GeoTile.svelte +1 -1
- package/dist/components/Graticule.svelte +5 -5
- package/dist/components/Grid.svelte +60 -63
- package/dist/components/Group.svelte +13 -8
- package/dist/components/Group.svelte.d.ts +10 -3
- package/dist/components/Highlight.svelte +55 -28
- package/dist/components/Highlight.svelte.d.ts +4 -0
- package/dist/components/Hull.svelte +12 -5
- package/dist/components/Labels.svelte +24 -13
- package/dist/components/Labels.svelte.d.ts +12 -5
- package/dist/components/Legend.svelte +143 -70
- package/dist/components/Legend.svelte.d.ts +12 -8
- package/dist/components/Line.svelte +40 -3
- package/dist/components/LinearGradient.svelte +35 -4
- package/dist/components/Link.svelte +1 -1
- package/dist/components/Marker.svelte +37 -26
- package/dist/components/MonthPath.svelte +26 -12
- package/dist/components/MonthPath.svelte.d.ts +4 -3
- package/dist/components/MotionPath.svelte +1 -1
- package/dist/components/Pack.svelte.d.ts +10 -3
- package/dist/components/Partition.svelte.d.ts +10 -3
- package/dist/components/Pattern.svelte +5 -5
- package/dist/components/Pie.svelte +1 -2
- package/dist/components/Points.svelte +11 -72
- package/dist/components/Points.svelte.d.ts +1 -8
- package/dist/components/Polygon.svelte +309 -0
- package/dist/components/Polygon.svelte.d.ts +115 -0
- package/dist/components/RadialGradient.svelte +4 -6
- package/dist/components/Rect.svelte +55 -5
- package/dist/components/Rect.svelte.d.ts +2 -2
- package/dist/components/RectClipPath.svelte +4 -3
- package/dist/components/RectClipPath.svelte.d.ts +2 -2
- package/dist/components/Rule.svelte +167 -77
- package/dist/components/Rule.svelte.d.ts +7 -2
- package/dist/components/Spline.svelte +59 -28
- package/dist/components/Spline.svelte.d.ts +12 -4
- package/dist/components/Text.svelte +121 -73
- package/dist/components/Text.svelte.d.ts +6 -0
- package/dist/components/TileImage.svelte +19 -4
- package/dist/components/TransformContext.svelte +9 -3
- package/dist/components/TransformControls.svelte +89 -38
- package/dist/components/Tree.svelte.d.ts +10 -3
- package/dist/components/Treemap.svelte +63 -26
- package/dist/components/Treemap.svelte.d.ts +21 -14
- package/dist/components/Voronoi.svelte +12 -13
- package/dist/components/charts/ArcChart.svelte +43 -71
- package/dist/components/charts/ArcChart.svelte.d.ts +10 -3
- package/dist/components/charts/AreaChart.svelte +29 -59
- package/dist/components/charts/AreaChart.svelte.d.ts +10 -3
- package/dist/components/charts/BarChart.svelte +79 -71
- package/dist/components/charts/BarChart.svelte.d.ts +10 -3
- package/dist/components/charts/DefaultTooltip.svelte +3 -3
- package/dist/components/charts/DefaultTooltip.svelte.d.ts +1 -1
- package/dist/components/charts/LineChart.svelte +69 -75
- package/dist/components/charts/LineChart.svelte.d.ts +21 -8
- package/dist/components/charts/PieChart.svelte +44 -71
- package/dist/components/charts/PieChart.svelte.d.ts +10 -3
- package/dist/components/charts/ScatterChart.svelte +10 -39
- package/dist/components/charts/ScatterChart.svelte.d.ts +10 -3
- package/dist/components/charts/utils.svelte.d.ts +1 -19
- package/dist/components/charts/utils.svelte.js +7 -35
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +5 -1
- package/dist/components/layout/Canvas.svelte +96 -69
- package/dist/components/layout/Canvas.svelte.d.ts +6 -0
- package/dist/components/layout/Html.svelte +15 -9
- package/dist/components/layout/Layer.svelte +6 -4
- package/dist/components/layout/Layer.svelte.d.ts +6 -4
- package/dist/components/layout/Svg.svelte +19 -11
- package/dist/components/layout/WebGL.svelte +26 -6
- package/dist/components/layout/WebGL.svelte.d.ts +5 -2
- package/dist/components/tooltip/Tooltip.svelte +73 -36
- package/dist/components/tooltip/Tooltip.svelte.d.ts +10 -3
- package/dist/components/tooltip/TooltipContext.svelte +167 -54
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +19 -5
- package/dist/components/tooltip/TooltipHeader.svelte +32 -18
- package/dist/components/tooltip/TooltipHeader.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipItem.svelte +46 -37
- package/dist/components/tooltip/TooltipItem.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipList.svelte +12 -10
- package/dist/components/tooltip/TooltipSeparator.svelte +18 -10
- package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
- package/dist/docs/Blockquote.svelte +6 -4
- package/dist/docs/Blockquote.svelte.d.ts +4 -19
- package/dist/docs/Code.svelte +70 -28
- package/dist/docs/Code.svelte.d.ts +9 -24
- package/dist/docs/Header1.svelte +4 -2
- package/dist/docs/Header1.svelte.d.ts +4 -28
- package/dist/docs/Json.svelte +11 -3
- package/dist/docs/Json.svelte.d.ts +9 -21
- package/dist/docs/Layout.svelte +10 -7
- package/dist/docs/Layout.svelte.d.ts +4 -19
- package/dist/docs/Link.svelte +7 -3
- package/dist/docs/Link.svelte.d.ts +4 -38
- package/dist/docs/Preview.svelte +22 -23
- package/dist/docs/Preview.svelte.d.ts +5 -6
- package/dist/docs/TilesetField.svelte +20 -19
- package/dist/docs/TilesetField.svelte.d.ts +5 -22
- package/dist/docs/ViewSourceButton.svelte +10 -7
- package/dist/docs/ViewSourceButton.svelte.d.ts +7 -21
- package/dist/states/series.svelte.d.ts +30 -0
- package/dist/states/series.svelte.js +54 -0
- package/dist/styles/daisyui-5.css +6 -0
- package/dist/styles/shadcn-svelte.css +11 -0
- package/dist/styles/skeleton-3.css +15 -0
- package/dist/utils/arcText.svelte.js +4 -4
- package/dist/utils/array.d.ts +11 -0
- package/dist/utils/array.js +23 -0
- package/dist/utils/array.test.d.ts +1 -0
- package/dist/utils/array.test.js +200 -0
- package/dist/utils/attributes.d.ts +3 -13
- package/dist/utils/attributes.js +4 -18
- package/dist/utils/canvas.d.ts +77 -0
- package/dist/utils/canvas.js +105 -41
- package/dist/utils/common.d.ts +9 -0
- package/dist/utils/common.js +18 -1
- package/dist/utils/common.test.js +26 -1
- package/dist/utils/genData.d.ts +22 -8
- package/dist/utils/genData.js +34 -14
- package/dist/utils/graph/dagre.d.ts +4 -4
- package/dist/utils/graph/dagre.js +5 -7
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/math.d.ts +17 -0
- package/dist/utils/math.js +17 -0
- package/dist/utils/motion.svelte.js +1 -1
- package/dist/utils/path.d.ts +10 -0
- package/dist/utils/path.js +30 -0
- package/dist/utils/rect.svelte.d.ts +2 -2
- package/dist/utils/rect.svelte.js +73 -1
- package/dist/utils/scales.svelte.d.ts +9 -3
- package/dist/utils/scales.svelte.js +47 -4
- package/dist/utils/shape.d.ts +43 -0
- package/dist/utils/shape.js +59 -0
- package/dist/utils/stack.js +1 -1
- package/dist/utils/string.d.ts +49 -0
- package/dist/utils/string.js +4 -2
- package/dist/utils/ticks.d.ts +15 -4
- package/dist/utils/ticks.js +140 -159
- package/dist/utils/ticks.test.js +16 -26
- package/dist/utils/treemap.d.ts +1 -1
- package/dist/utils/types.d.ts +15 -2
- package/package.json +36 -35
- package/dist/utils/object.js +0 -2
|
@@ -87,23 +87,23 @@
|
|
|
87
87
|
/**
|
|
88
88
|
* Add additional content at the start of the line.
|
|
89
89
|
*
|
|
90
|
-
* Receives `{ point: DOMPoint }` as a snippet prop.
|
|
90
|
+
* Receives `{ point: DOMPoint; value: { x: number; y: number } }` as a snippet prop.
|
|
91
91
|
*/
|
|
92
|
-
startContent?: Snippet<[{ point: DOMPoint }]>;
|
|
92
|
+
startContent?: Snippet<[{ point: DOMPoint; value: { x: number; y: number } }]>;
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
95
|
* Add additional content at the end of the line.
|
|
96
96
|
*
|
|
97
|
-
* Receives `{ point: DOMPoint }` as a snippet prop.
|
|
97
|
+
* Receives `{ point: DOMPoint; value: { x: number; y: number } }` as a snippet prop.
|
|
98
98
|
*/
|
|
99
|
-
endContent?: Snippet<[{ point: DOMPoint }]>;
|
|
99
|
+
endContent?: Snippet<[{ point: DOMPoint; value: { x: number; y: number } }]>;
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* A reference to the `<path>` element.
|
|
103
103
|
*
|
|
104
104
|
* @bindable
|
|
105
105
|
*/
|
|
106
|
-
|
|
106
|
+
pathRef?: SVGPathElement;
|
|
107
107
|
|
|
108
108
|
motion?: MotionProp;
|
|
109
109
|
} & CommonStyleProps;
|
|
@@ -132,7 +132,6 @@
|
|
|
132
132
|
import { getChartContext } from './Chart.svelte';
|
|
133
133
|
import { createKey } from '../utils/key.svelte.js';
|
|
134
134
|
import { createId } from '../utils/createId.js';
|
|
135
|
-
import { layerClass } from '../utils/attributes.js';
|
|
136
135
|
|
|
137
136
|
const ctx = getChartContext();
|
|
138
137
|
|
|
@@ -159,14 +158,14 @@
|
|
|
159
158
|
startContent,
|
|
160
159
|
endContent,
|
|
161
160
|
opacity,
|
|
162
|
-
|
|
161
|
+
pathRef: pathRefProp = $bindable(),
|
|
163
162
|
...restProps
|
|
164
163
|
}: SplineProps = $props();
|
|
165
164
|
|
|
166
|
-
let
|
|
165
|
+
let pathRef = $state<SVGPathElement>();
|
|
167
166
|
|
|
168
167
|
$effect.pre(() => {
|
|
169
|
-
|
|
168
|
+
pathRefProp = pathRef;
|
|
170
169
|
});
|
|
171
170
|
|
|
172
171
|
const markerStart = $derived(markerStartProp ?? marker);
|
|
@@ -274,7 +273,7 @@
|
|
|
274
273
|
? merge({ styles: { strokeWidth } }, styleOverrides)
|
|
275
274
|
: {
|
|
276
275
|
styles: { fill, fillOpacity, stroke, strokeWidth, opacity },
|
|
277
|
-
classes: className,
|
|
276
|
+
classes: cls('lc-spline-path', className),
|
|
278
277
|
}
|
|
279
278
|
);
|
|
280
279
|
}
|
|
@@ -331,8 +330,8 @@
|
|
|
331
330
|
easing: typeof draw === 'object' && draw.easing ? draw.easing : cubicInOut,
|
|
332
331
|
interpolate() {
|
|
333
332
|
return (t: number) => {
|
|
334
|
-
const totalLength =
|
|
335
|
-
const point =
|
|
333
|
+
const totalLength = pathRef?.getTotalLength() ?? 0;
|
|
334
|
+
const point = pathRef?.getPointAtLength(totalLength * t);
|
|
336
335
|
return point;
|
|
337
336
|
};
|
|
338
337
|
},
|
|
@@ -343,16 +342,16 @@
|
|
|
343
342
|
$effect(() => {
|
|
344
343
|
if (!startContent && !endContent) return;
|
|
345
344
|
d;
|
|
346
|
-
if (!
|
|
347
|
-
startPoint =
|
|
348
|
-
const totalLength =
|
|
349
|
-
endPoint.target =
|
|
345
|
+
if (!pathRef || !pathRef.getTotalLength()) return;
|
|
346
|
+
startPoint = pathRef.getPointAtLength(0);
|
|
347
|
+
const totalLength = pathRef.getTotalLength();
|
|
348
|
+
endPoint.target = pathRef.getPointAtLength(totalLength);
|
|
350
349
|
});
|
|
351
350
|
|
|
352
351
|
$effect(() => {
|
|
353
352
|
if (!draw) return;
|
|
354
|
-
[tweenedState.current];
|
|
355
353
|
// Anytime the path data changes, redraw
|
|
354
|
+
[pathData, data, ctx.data];
|
|
356
355
|
key = Symbol();
|
|
357
356
|
});
|
|
358
357
|
</script>
|
|
@@ -362,12 +361,7 @@
|
|
|
362
361
|
<path
|
|
363
362
|
d={tweenedState.current}
|
|
364
363
|
{...restProps}
|
|
365
|
-
class={cls(
|
|
366
|
-
layerClass('spline-path'),
|
|
367
|
-
!fill && 'fill-none',
|
|
368
|
-
!stroke && 'stroke-surface-content',
|
|
369
|
-
className
|
|
370
|
-
)}
|
|
364
|
+
class={cls('lc-spline-path', className)}
|
|
371
365
|
{fill}
|
|
372
366
|
fill-opacity={fillOpacity}
|
|
373
367
|
{stroke}
|
|
@@ -377,22 +371,59 @@
|
|
|
377
371
|
marker-mid={markerMidId ? `url(#${markerMidId})` : undefined}
|
|
378
372
|
marker-end={markerEndId ? `url(#${markerEndId})` : undefined}
|
|
379
373
|
in:drawTransition|global={typeof draw === 'object' ? draw : undefined}
|
|
380
|
-
bind:this={
|
|
374
|
+
bind:this={pathRef}
|
|
381
375
|
/>
|
|
382
376
|
<MarkerWrapper id={markerStartId} marker={markerStart} />
|
|
383
377
|
<MarkerWrapper id={markerMidId} marker={markerMid} />
|
|
384
378
|
<MarkerWrapper id={markerEndId} marker={markerEnd} />
|
|
385
379
|
|
|
386
380
|
{#if startContent && startPoint}
|
|
387
|
-
<Group x={startPoint.x} y={startPoint.y} class=
|
|
388
|
-
{@render startContent({
|
|
381
|
+
<Group x={startPoint.x} y={startPoint.y} class="lc-spline-g-start">
|
|
382
|
+
{@render startContent({
|
|
383
|
+
point: startPoint,
|
|
384
|
+
value: {
|
|
385
|
+
x: ctx.xScale?.invert?.(startPoint.x),
|
|
386
|
+
y: ctx.yScale?.invert?.(startPoint.y),
|
|
387
|
+
},
|
|
388
|
+
})}
|
|
389
389
|
</Group>
|
|
390
390
|
{/if}
|
|
391
391
|
|
|
392
392
|
{#if endContent && endPoint.current}
|
|
393
|
-
<Group x={endPoint.current.x} y={endPoint.current.y} class=
|
|
394
|
-
{@render endContent({
|
|
393
|
+
<Group x={endPoint.current.x} y={endPoint.current.y} class="lc-spline-g-end">
|
|
394
|
+
{@render endContent({
|
|
395
|
+
point: endPoint.current,
|
|
396
|
+
value: {
|
|
397
|
+
x: ctx.xScale?.invert?.(endPoint.current.x),
|
|
398
|
+
y: ctx.yScale?.invert?.(endPoint.current.y),
|
|
399
|
+
},
|
|
400
|
+
})}
|
|
395
401
|
</Group>
|
|
396
402
|
{/if}
|
|
397
403
|
{/key}
|
|
398
404
|
{/if}
|
|
405
|
+
|
|
406
|
+
<style>
|
|
407
|
+
@layer base {
|
|
408
|
+
:global(:where(.lc-spline-path)) {
|
|
409
|
+
--fill-color: none;
|
|
410
|
+
--stroke-color: var(--color-surface-content, currentColor);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* Svg | Canvas layers */
|
|
414
|
+
:global(:where(.lc-layout-svg .lc-spline-path, svg.lc-spline-path):not([fill])) {
|
|
415
|
+
fill: var(--fill-color);
|
|
416
|
+
}
|
|
417
|
+
:global(:where(.lc-layout-svg .lc-spline-path, svg.lc-spline-path):not([stroke])) {
|
|
418
|
+
stroke: var(--stroke-color);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* Html layers */
|
|
422
|
+
:global(:where(.lc-layout-html .lc-spline-path):not([background-color])) {
|
|
423
|
+
background-color: var(--fill-color);
|
|
424
|
+
}
|
|
425
|
+
:global(:where(.lc-layout-html .lc-spline-path):not([border-color])) {
|
|
426
|
+
border-color: var(--stroke-color);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
</style>
|
|
@@ -67,29 +67,37 @@ export type SplinePropsWithoutHTML = {
|
|
|
67
67
|
/**
|
|
68
68
|
* Add additional content at the start of the line.
|
|
69
69
|
*
|
|
70
|
-
* Receives `{ point: DOMPoint }` as a snippet prop.
|
|
70
|
+
* Receives `{ point: DOMPoint; value: { x: number; y: number } }` as a snippet prop.
|
|
71
71
|
*/
|
|
72
72
|
startContent?: Snippet<[{
|
|
73
73
|
point: DOMPoint;
|
|
74
|
+
value: {
|
|
75
|
+
x: number;
|
|
76
|
+
y: number;
|
|
77
|
+
};
|
|
74
78
|
}]>;
|
|
75
79
|
/**
|
|
76
80
|
* Add additional content at the end of the line.
|
|
77
81
|
*
|
|
78
|
-
* Receives `{ point: DOMPoint }` as a snippet prop.
|
|
82
|
+
* Receives `{ point: DOMPoint; value: { x: number; y: number } }` as a snippet prop.
|
|
79
83
|
*/
|
|
80
84
|
endContent?: Snippet<[{
|
|
81
85
|
point: DOMPoint;
|
|
86
|
+
value: {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
};
|
|
82
90
|
}]>;
|
|
83
91
|
/**
|
|
84
92
|
* A reference to the `<path>` element.
|
|
85
93
|
*
|
|
86
94
|
* @bindable
|
|
87
95
|
*/
|
|
88
|
-
|
|
96
|
+
pathRef?: SVGPathElement;
|
|
89
97
|
motion?: MotionProp;
|
|
90
98
|
} & CommonStyleProps;
|
|
91
99
|
export type SplineProps = SplinePropsWithoutHTML & Without<SVGAttributes<SVGPathElement>, SplinePropsWithoutHTML>;
|
|
92
100
|
import { draw as _drawTransition } from 'svelte/transition';
|
|
93
|
-
declare const Spline: import("svelte").Component<SplineProps, {}, "
|
|
101
|
+
declare const Spline: import("svelte").Component<SplineProps, {}, "pathRef">;
|
|
94
102
|
type Spline = ReturnType<typeof Spline>;
|
|
95
103
|
export default Spline;
|
|
@@ -97,6 +97,20 @@
|
|
|
97
97
|
*/
|
|
98
98
|
verticalAnchor?: 'start' | 'middle' | 'end' | 'inherit';
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* The dominant baseline of the text. Useful for aligning text to the baseline of the axis.
|
|
102
|
+
*
|
|
103
|
+
* @default 'auto'
|
|
104
|
+
*/
|
|
105
|
+
dominantBaseline?:
|
|
106
|
+
| 'auto'
|
|
107
|
+
| 'text-before-edge'
|
|
108
|
+
| 'text-after-edge'
|
|
109
|
+
| 'middle'
|
|
110
|
+
| 'hanging'
|
|
111
|
+
| 'ideographic'
|
|
112
|
+
| 'mathematical';
|
|
113
|
+
|
|
100
114
|
/**
|
|
101
115
|
* Rotational angle of the text
|
|
102
116
|
*/
|
|
@@ -174,24 +188,9 @@
|
|
|
174
188
|
import { getComputedStyles, renderText, type ComputedStylesOptions } from '../utils/canvas.js';
|
|
175
189
|
|
|
176
190
|
import { createKey } from '../utils/key.svelte.js';
|
|
177
|
-
import { layerClass } from '../utils/attributes.js';
|
|
178
191
|
import { degreesToRadians } from '../utils/math.js';
|
|
179
192
|
import { createId } from '../utils/createId.js';
|
|
180
193
|
|
|
181
|
-
/*
|
|
182
|
-
TODO:
|
|
183
|
-
- [ ] Handle styled text (use <slot /> to measure?)
|
|
184
|
-
- [ ] Simplify by using `alignment-baseline` / `dominant-baseline`, rework multiline or drop support, etc
|
|
185
|
-
- https://svelte.dev/repl/f12d3003313a43ba8a0be53e5786f1c7?version=3.44.3
|
|
186
|
-
- https://observablehq.com/@neocartocnrs/cheat-sheet-on-texts-in-svg
|
|
187
|
-
|
|
188
|
-
Reference:
|
|
189
|
-
- https://bl.ocks.org/mbostock/7555321
|
|
190
|
-
- https://github.com/airbnb/visx/blob/master/packages/visx-text/src/Text.tsx
|
|
191
|
-
- https://airbnb.io/visx/text
|
|
192
|
-
- https://github.com/airbnb/visx/blob/master/packages/visx-demo/src/pages/text.tsx
|
|
193
|
-
*/
|
|
194
|
-
|
|
195
194
|
const uid = $props.id();
|
|
196
195
|
|
|
197
196
|
let {
|
|
@@ -208,6 +207,7 @@
|
|
|
208
207
|
scaleToFit = false,
|
|
209
208
|
textAnchor = 'start',
|
|
210
209
|
verticalAnchor = 'end',
|
|
210
|
+
dominantBaseline = 'auto',
|
|
211
211
|
rotate,
|
|
212
212
|
opacity = 1,
|
|
213
213
|
strokeWidth = 0,
|
|
@@ -227,6 +227,8 @@
|
|
|
227
227
|
...restProps
|
|
228
228
|
}: TextProps = $props();
|
|
229
229
|
|
|
230
|
+
const renderCtx = getRenderContext();
|
|
231
|
+
|
|
230
232
|
let ref = $state<SVGTextElement>();
|
|
231
233
|
let svgRef = $state<SVGElement>();
|
|
232
234
|
let pathRef = $state<SVGPathElement>();
|
|
@@ -260,49 +262,56 @@
|
|
|
260
262
|
};
|
|
261
263
|
});
|
|
262
264
|
|
|
263
|
-
|
|
265
|
+
// Handle null and convert `\n` strings back to newline characters
|
|
266
|
+
const rawText = $derived(value != null ? value.toString().replace(/\\n/g, '\n') : '');
|
|
264
267
|
|
|
265
268
|
const textValue = $derived.by(() => {
|
|
266
269
|
if (!truncateConfig) return rawText;
|
|
267
270
|
return truncateText(rawText, truncateConfig);
|
|
268
271
|
});
|
|
269
272
|
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
const words = $derived(textValue ? textValue.split(/(?:(?!\u00A0+)\s+)/) : []);
|
|
273
|
+
const spaceWidth = $derived(getStringWidth('\u00A0', style) || 0);
|
|
273
274
|
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
width: getStringWidth(word, style) || 0,
|
|
278
|
-
}))
|
|
279
|
-
);
|
|
275
|
+
const wordsByLines = $derived.by(() => {
|
|
276
|
+
// Split by newlines to preserve explicit line breaks
|
|
277
|
+
const lines = textValue.split('\n');
|
|
280
278
|
|
|
281
|
-
|
|
279
|
+
return lines.flatMap((line) => {
|
|
280
|
+
// Split each line into words
|
|
281
|
+
const words = line.split(/(?:(?!\u00A0+)\s+)/);
|
|
282
282
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (
|
|
288
|
-
currentLine &&
|
|
289
|
-
(width == null || scaleToFit || (currentLine.width || 0) + item.width + spaceWidth < width)
|
|
290
|
-
) {
|
|
291
|
-
// Word can be added to an existing line
|
|
292
|
-
currentLine.words.push(item.word);
|
|
293
|
-
currentLine.width = currentLine.width || 0;
|
|
294
|
-
currentLine.width += item.width + spaceWidth;
|
|
283
|
+
if (width == null) {
|
|
284
|
+
// No width specified, only use explicit line breaks (if used)
|
|
285
|
+
return [{ words }];
|
|
295
286
|
} else {
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
287
|
+
// Handle word wrapping within each line
|
|
288
|
+
return words.reduce((result: { words: string[]; width?: number }[], item) => {
|
|
289
|
+
const currentLine = result[result.length - 1];
|
|
290
|
+
const itemWidth = getStringWidth(item, style) || 0;
|
|
291
|
+
|
|
292
|
+
if (
|
|
293
|
+
currentLine &&
|
|
294
|
+
(width == null ||
|
|
295
|
+
scaleToFit ||
|
|
296
|
+
(currentLine.width || 0) + itemWidth + spaceWidth < width)
|
|
297
|
+
) {
|
|
298
|
+
// Word can be added to an existing line
|
|
299
|
+
currentLine.words.push(item);
|
|
300
|
+
currentLine.width = currentLine.width || 0;
|
|
301
|
+
currentLine.width += itemWidth + spaceWidth;
|
|
302
|
+
} else {
|
|
303
|
+
// Add first word to line or word is too long to scaleToFit on existing line
|
|
304
|
+
const newLine = { words: [item], width: itemWidth };
|
|
305
|
+
result.push(newLine);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return result;
|
|
309
|
+
}, []);
|
|
299
310
|
}
|
|
311
|
+
});
|
|
312
|
+
});
|
|
300
313
|
|
|
301
|
-
|
|
302
|
-
}, [])
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
const lines = $derived(wordsByLines.length);
|
|
314
|
+
const lineCount = $derived(wordsByLines.length);
|
|
306
315
|
|
|
307
316
|
/**
|
|
308
317
|
* Convert css value to pixel value (ex. 0.71em => 11.36)
|
|
@@ -327,28 +336,18 @@
|
|
|
327
336
|
|
|
328
337
|
const startDy = $derived.by(() => {
|
|
329
338
|
if (verticalAnchor === 'start') {
|
|
330
|
-
return getPixelValue(
|
|
331
|
-
} else if (verticalAnchor === 'middle') {
|
|
332
|
-
return ((lines - 1) / 2) * -getPixelValue(lineHeight) + getPixelValue(capHeight) / 2;
|
|
333
|
-
} else {
|
|
334
|
-
return (lines - 1) * -getPixelValue(lineHeight);
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const pathStartDy = $derived.by(() => {
|
|
339
|
-
if (verticalAnchor === 'start') {
|
|
340
|
-
return getPixelValue(capHeight);
|
|
339
|
+
return getPixelValue(lineHeight);
|
|
341
340
|
} else if (verticalAnchor === 'middle') {
|
|
342
|
-
return (
|
|
341
|
+
return ((lineCount - 1) / 2) * -getPixelValue(lineHeight) + getPixelValue(capHeight) / 2;
|
|
343
342
|
} else {
|
|
344
|
-
return
|
|
343
|
+
return (lineCount - 1) * -getPixelValue(lineHeight) - getPixelValue(capHeight) / 2;
|
|
345
344
|
}
|
|
346
345
|
});
|
|
347
346
|
|
|
348
347
|
const scaleTransform = $derived.by(() => {
|
|
349
348
|
if (
|
|
350
349
|
scaleToFit &&
|
|
351
|
-
|
|
350
|
+
lineCount > 0 &&
|
|
352
351
|
typeof x == 'number' &&
|
|
353
352
|
typeof y == 'number' &&
|
|
354
353
|
typeof width == 'number'
|
|
@@ -411,7 +410,7 @@
|
|
|
411
410
|
paintOrder: 'stroke',
|
|
412
411
|
textAnchor,
|
|
413
412
|
},
|
|
414
|
-
classes: cls(
|
|
413
|
+
classes: cls('lc-text', className),
|
|
415
414
|
};
|
|
416
415
|
|
|
417
416
|
const computedStyles = getComputedStyles(ctx.canvas, styles);
|
|
@@ -473,13 +472,7 @@
|
|
|
473
472
|
{#if renderCtx === 'svg'}
|
|
474
473
|
<!-- `overflow: visible` allow contents to be shown outside element -->
|
|
475
474
|
<!-- `paint-order: stroke` supports stroke outlining text -->
|
|
476
|
-
<svg
|
|
477
|
-
x={dx}
|
|
478
|
-
y={dy}
|
|
479
|
-
{...svgProps}
|
|
480
|
-
class={cls(layerClass('text-svg'), 'overflow-visible [paint-order:stroke]', svgProps?.class)}
|
|
481
|
-
bind:this={svgRef}
|
|
482
|
-
>
|
|
475
|
+
<svg x={dx} y={dy} {...svgProps} class={['lc-text-svg', svgProps?.class]} bind:this={svgRef}>
|
|
483
476
|
{#if path}
|
|
484
477
|
<defs>
|
|
485
478
|
{#key path}
|
|
@@ -496,13 +489,14 @@
|
|
|
496
489
|
stroke-width={strokeWidth}
|
|
497
490
|
{opacity}
|
|
498
491
|
transform={transformProp}
|
|
499
|
-
class={
|
|
492
|
+
class={['lc-text', className]}
|
|
500
493
|
>
|
|
501
494
|
<textPath
|
|
502
495
|
style="text-anchor: {textAnchor};"
|
|
496
|
+
dominant-baseline={dominantBaseline}
|
|
503
497
|
href="#{pathId}"
|
|
504
498
|
{startOffset}
|
|
505
|
-
class=
|
|
499
|
+
class="lc-text-path"
|
|
506
500
|
>
|
|
507
501
|
{wordsByLines.map((line) => line.words.join(' ')).join()}
|
|
508
502
|
</textPath>
|
|
@@ -514,19 +508,20 @@
|
|
|
514
508
|
y={motionY.current}
|
|
515
509
|
{transform}
|
|
516
510
|
text-anchor={textAnchor}
|
|
511
|
+
dominant-baseline={dominantBaseline}
|
|
517
512
|
{...restProps}
|
|
518
513
|
{fill}
|
|
519
514
|
fill-opacity={fillOpacity}
|
|
520
515
|
{stroke}
|
|
521
516
|
stroke-width={strokeWidth}
|
|
522
517
|
{opacity}
|
|
523
|
-
class={
|
|
518
|
+
class={['lc-text', className]}
|
|
524
519
|
>
|
|
525
520
|
{#each wordsByLines as line, index}
|
|
526
521
|
<tspan
|
|
527
522
|
x={motionX.current}
|
|
528
|
-
dy={index === 0 ? startDy : lineHeight}
|
|
529
|
-
class=
|
|
523
|
+
dy={index === 0 ? startDy : getPixelValue(lineHeight)}
|
|
524
|
+
class="lc-text-tspan"
|
|
530
525
|
>
|
|
531
526
|
{line.words.join(' ')}
|
|
532
527
|
</tspan>
|
|
@@ -534,4 +529,57 @@
|
|
|
534
529
|
</text>
|
|
535
530
|
{/if}
|
|
536
531
|
</svg>
|
|
532
|
+
{:else if renderCtx === 'html'}
|
|
533
|
+
{@const translateX = textAnchor === 'middle' ? '-50%' : textAnchor === 'end' ? '-100%' : '0%'}
|
|
534
|
+
{@const translateY =
|
|
535
|
+
verticalAnchor === 'middle' ? '-50%' : verticalAnchor === 'end' ? '-100%' : '0%'}
|
|
536
|
+
<!-- TODO: How best to handle dx/dy when adjusted for svg style issues? -->
|
|
537
|
+
<!-- style:line-height={lineHeight} -->
|
|
538
|
+
<!-- TODO: How to handle fill-/stroke- vs bg-/text-/border- colors? -->
|
|
539
|
+
<div
|
|
540
|
+
style:position="absolute"
|
|
541
|
+
style:left="{dx + motionX.current}px"
|
|
542
|
+
style:top="{dy + motionY.current}px"
|
|
543
|
+
style:transform="translate({translateX}, {translateY}) rotate({rotate ?? 0}deg)"
|
|
544
|
+
style:transform-origin="{verticalAnchor === 'middle'
|
|
545
|
+
? 'center'
|
|
546
|
+
: verticalAnchor === 'end'
|
|
547
|
+
? 'bottom'
|
|
548
|
+
: 'top'}
|
|
549
|
+
{textAnchor === 'middle' ? 'center' : textAnchor === 'end' ? 'right' : 'left'}"
|
|
550
|
+
class={['lc-text', className]}
|
|
551
|
+
>
|
|
552
|
+
{textValue}
|
|
553
|
+
</div>
|
|
537
554
|
{/if}
|
|
555
|
+
|
|
556
|
+
<style>
|
|
557
|
+
@layer base {
|
|
558
|
+
:global(:where(.lc-text)) {
|
|
559
|
+
--fill-color: var(--color-surface-content, currentColor);
|
|
560
|
+
--stroke-color: initial;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
:global(:where(.lc-text-svg)) {
|
|
564
|
+
overflow: visible;
|
|
565
|
+
paint-order: stroke;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/* Svg | Canvas layers */
|
|
569
|
+
:global(:where(.lc-layout-svg .lc-text, svg.lc-text):not([fill])) {
|
|
570
|
+
color: var(--fill-color);
|
|
571
|
+
fill: currentColor;
|
|
572
|
+
}
|
|
573
|
+
:global(:where(.lc-layout-svg .lc-text, svg.lc-text):not([stroke])) {
|
|
574
|
+
stroke: var(--stroke-color);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* Html layers */
|
|
578
|
+
:global(:where(.lc-layout-html .lc-text):not([background-color])) {
|
|
579
|
+
color: var(--fill-color);
|
|
580
|
+
}
|
|
581
|
+
:global(:where(.lc-layout-html .lc-text):not([border-color])) {
|
|
582
|
+
border-color: var(--stroke-color);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
</style>
|
|
@@ -80,6 +80,12 @@ export type TextPropsWithoutHTML = {
|
|
|
80
80
|
* @default 'end'
|
|
81
81
|
*/
|
|
82
82
|
verticalAnchor?: 'start' | 'middle' | 'end' | 'inherit';
|
|
83
|
+
/**
|
|
84
|
+
* The dominant baseline of the text. Useful for aligning text to the baseline of the axis.
|
|
85
|
+
*
|
|
86
|
+
* @default 'auto'
|
|
87
|
+
*/
|
|
88
|
+
dominantBaseline?: 'auto' | 'text-before-edge' | 'text-after-edge' | 'middle' | 'hanging' | 'ideographic' | 'mathematical';
|
|
83
89
|
/**
|
|
84
90
|
* Rotational angle of the text
|
|
85
91
|
*/
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
y={(y + ty) * scale - 0.5}
|
|
136
136
|
width={scale + 1}
|
|
137
137
|
height={scale + 1}
|
|
138
|
-
{...extractLayerProps(restProps, 'tile-image-lower')}
|
|
138
|
+
{...extractLayerProps(restProps, 'lc-tile-image-lower')}
|
|
139
139
|
/>
|
|
140
140
|
<image
|
|
141
141
|
{href}
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
y={(y + ty) * scale}
|
|
144
144
|
width={scale}
|
|
145
145
|
height={scale}
|
|
146
|
-
{...extractLayerProps(restProps, 'tile-image')}
|
|
146
|
+
{...extractLayerProps(restProps, 'lc-tile-image')}
|
|
147
147
|
/>
|
|
148
148
|
{/key}
|
|
149
149
|
{#if debug}
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
y={(y + ty) * scale}
|
|
153
153
|
width={scale}
|
|
154
154
|
height={scale}
|
|
155
|
-
class="
|
|
155
|
+
class="lc-tile-image-debug-rect"
|
|
156
156
|
/>
|
|
157
157
|
<Text
|
|
158
158
|
x={(x + tx) * scale}
|
|
@@ -161,6 +161,21 @@
|
|
|
161
161
|
dx={2}
|
|
162
162
|
dy={-2}
|
|
163
163
|
value="{x}-{y}-{z}"
|
|
164
|
-
class="
|
|
164
|
+
class="lc-tile-image-debug-text"
|
|
165
165
|
/>
|
|
166
166
|
{/if}
|
|
167
|
+
|
|
168
|
+
<style>
|
|
169
|
+
@layer components {
|
|
170
|
+
:global(:where(.lc-tile-image-debug-rect)) {
|
|
171
|
+
fill: none;
|
|
172
|
+
stroke: var(--color-danger, red);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
:global(:where(.lc-tile-image-debug-text)) {
|
|
176
|
+
--fill-color: var(--color-danger, red);
|
|
177
|
+
font-size: 14px;
|
|
178
|
+
font-weight: 500;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
</style>
|
|
@@ -216,8 +216,6 @@
|
|
|
216
216
|
import type { Without } from '../utils/types.js';
|
|
217
217
|
import { getChartContext } from './Chart.svelte';
|
|
218
218
|
import type { Snippet } from 'svelte';
|
|
219
|
-
import { cls } from '@layerstack/tailwind';
|
|
220
|
-
import { layerClass } from '../utils/attributes.js';
|
|
221
219
|
import {
|
|
222
220
|
createControlledMotion,
|
|
223
221
|
createMotionTracker,
|
|
@@ -519,9 +517,17 @@
|
|
|
519
517
|
onpointerup={onPointerUp}
|
|
520
518
|
ondblclick={onDoubleClick}
|
|
521
519
|
onclickcapture={onClick}
|
|
522
|
-
class={
|
|
520
|
+
class={['lc-transform-context', className]}
|
|
523
521
|
bind:this={ref}
|
|
524
522
|
{...restProps}
|
|
525
523
|
>
|
|
526
524
|
{@render children?.({ transformContext: transformContext })}
|
|
527
525
|
</div>
|
|
526
|
+
|
|
527
|
+
<style>
|
|
528
|
+
@layer base {
|
|
529
|
+
:where(.lc-transform-context) {
|
|
530
|
+
height: 100%;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
</style>
|