layerchart 2.0.0-next.1 → 2.0.0-next.11
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/actions/movable.d.ts +28 -0
- package/dist/actions/movable.js +91 -0
- package/dist/components/AnnotationLine.svelte +143 -0
- package/dist/components/AnnotationLine.svelte.d.ts +30 -0
- package/dist/components/AnnotationPoint.svelte +119 -0
- package/dist/components/AnnotationPoint.svelte.d.ts +34 -0
- package/dist/components/AnnotationRange.svelte +147 -0
- package/dist/components/AnnotationRange.svelte.d.ts +40 -0
- package/dist/components/Arc.svelte +344 -151
- package/dist/components/Arc.svelte.d.ts +138 -0
- package/dist/components/Area.svelte +165 -149
- package/dist/components/Area.svelte.d.ts +45 -0
- package/dist/components/Axis.svelte +320 -179
- package/dist/components/Axis.svelte.d.ts +127 -0
- package/dist/components/Bar.svelte +166 -107
- package/dist/components/Bar.svelte.d.ts +51 -0
- package/dist/components/Bars.svelte +56 -67
- package/dist/components/Bars.svelte.d.ts +27 -0
- package/dist/components/Blur.svelte +42 -12
- package/dist/components/Blur.svelte.d.ts +23 -21
- package/dist/components/Bounds.svelte +49 -19
- package/dist/components/Bounds.svelte.d.ts +24 -50
- package/dist/components/BrushContext.svelte +296 -168
- package/dist/components/BrushContext.svelte.d.ts +97 -65
- package/dist/components/Calendar.svelte +116 -59
- package/dist/components/Calendar.svelte.d.ts +50 -31
- package/dist/components/Chart.svelte +1289 -398
- package/dist/components/Chart.svelte.d.ts +535 -410
- package/dist/components/ChartClipPath.svelte +37 -15
- package/dist/components/ChartClipPath.svelte.d.ts +21 -19
- package/dist/components/Circle.svelte +124 -85
- package/dist/components/Circle.svelte.d.ts +52 -0
- package/dist/components/CircleClipPath.svelte +76 -16
- package/dist/components/CircleClipPath.svelte.d.ts +46 -0
- package/dist/components/ClipPath.svelte +71 -21
- package/dist/components/ClipPath.svelte.d.ts +40 -27
- package/dist/components/ColorRamp.svelte +75 -9
- package/dist/components/ColorRamp.svelte.d.ts +37 -19
- package/dist/components/ComputedStyles.svelte +17 -5
- package/dist/components/ComputedStyles.svelte.d.ts +11 -19
- package/dist/components/Connector.svelte +149 -0
- package/dist/components/Connector.svelte.d.ts +51 -0
- package/dist/components/Dagre.svelte +211 -122
- package/dist/components/Dagre.svelte.d.ts +119 -56
- package/dist/components/ForceSimulation.svelte +215 -90
- package/dist/components/ForceSimulation.svelte.d.ts +82 -35
- package/dist/components/Frame.svelte +33 -13
- package/dist/components/Frame.svelte.d.ts +13 -17
- package/dist/components/GeoCircle.svelte +29 -16
- package/dist/components/GeoCircle.svelte.d.ts +22 -24
- package/dist/components/GeoContext.svelte +113 -72
- package/dist/components/GeoContext.svelte.d.ts +49 -41
- package/dist/components/GeoEdgeFade.svelte +49 -13
- package/dist/components/GeoEdgeFade.svelte.d.ts +17 -19
- package/dist/components/GeoPath.svelte +157 -127
- package/dist/components/GeoPath.svelte.d.ts +48 -36
- package/dist/components/GeoPoint.svelte +52 -20
- package/dist/components/GeoPoint.svelte.d.ts +25 -22
- package/dist/components/GeoSpline.svelte +75 -26
- package/dist/components/GeoSpline.svelte.d.ts +29 -20
- package/dist/components/GeoTile.svelte +100 -49
- package/dist/components/GeoTile.svelte.d.ts +38 -23
- package/dist/components/GeoVisible.svelte +17 -9
- package/dist/components/GeoVisible.svelte.d.ts +10 -18
- package/dist/components/Graticule.svelte +30 -14
- package/dist/components/Graticule.svelte.d.ts +11 -52
- package/dist/components/Grid.svelte +230 -117
- package/dist/components/Grid.svelte.d.ts +71 -0
- package/dist/components/Group.svelte +173 -106
- package/dist/components/Group.svelte.d.ts +81 -0
- package/dist/components/Highlight.svelte +410 -308
- package/dist/components/Highlight.svelte.d.ts +107 -0
- package/dist/components/Hull.svelte +97 -46
- package/dist/components/Hull.svelte.d.ts +40 -30
- package/dist/components/Labels.svelte +127 -47
- package/dist/components/Labels.svelte.d.ts +70 -27
- package/dist/components/Legend.svelte +374 -190
- package/dist/components/Legend.svelte.d.ts +95 -44
- package/dist/components/Line.svelte +163 -125
- package/dist/components/Line.svelte.d.ts +75 -0
- package/dist/components/LinearGradient.svelte +153 -78
- package/dist/components/LinearGradient.svelte.d.ts +66 -31
- package/dist/components/Link.svelte +160 -104
- package/dist/components/Link.svelte.d.ts +54 -0
- package/dist/components/Marker.svelte +100 -39
- package/dist/components/Marker.svelte.d.ts +59 -27
- package/dist/components/MarkerWrapper.svelte +35 -0
- package/dist/components/MarkerWrapper.svelte.d.ts +18 -0
- package/dist/components/MonthPath.svelte +65 -20
- package/dist/components/MonthPath.svelte.d.ts +23 -17
- package/dist/components/MotionPath.svelte +80 -24
- package/dist/components/MotionPath.svelte.d.ts +46 -27
- package/dist/components/Pack.svelte +53 -17
- package/dist/components/Pack.svelte.d.ts +42 -21
- package/dist/components/Partition.svelte +64 -22
- package/dist/components/Partition.svelte.d.ts +49 -26
- package/dist/components/Pattern.svelte +297 -11
- package/dist/components/Pattern.svelte.d.ts +103 -19
- package/dist/components/Pie.svelte +122 -76
- package/dist/components/Pie.svelte.d.ts +65 -51
- package/dist/components/Point.svelte +20 -9
- package/dist/components/Point.svelte.d.ts +16 -20
- package/dist/components/Points.svelte +148 -137
- package/dist/components/Points.svelte.d.ts +45 -34
- package/dist/components/RadialGradient.svelte +148 -77
- package/dist/components/RadialGradient.svelte.d.ts +69 -31
- package/dist/components/Rect.svelte +121 -102
- package/dist/components/Rect.svelte.d.ts +36 -0
- package/dist/components/RectClipPath.svelte +82 -18
- package/dist/components/RectClipPath.svelte.d.ts +55 -0
- package/dist/components/Rule.svelte +107 -63
- package/dist/components/Rule.svelte.d.ts +40 -19
- package/dist/components/Sankey.svelte +132 -55
- package/dist/components/Sankey.svelte.d.ts +61 -31
- package/dist/components/Spline.svelte +281 -218
- package/dist/components/Spline.svelte.d.ts +95 -0
- package/dist/components/Text.svelte +463 -197
- package/dist/components/Text.svelte.d.ts +136 -0
- package/dist/components/Threshold.svelte +48 -16
- package/dist/components/Threshold.svelte.d.ts +29 -31
- package/dist/components/TileImage.svelte +103 -30
- package/dist/components/TileImage.svelte.d.ts +48 -23
- package/dist/components/TransformContext.svelte +365 -171
- package/dist/components/TransformControls.svelte +50 -26
- package/dist/components/TransformControls.svelte.d.ts +27 -19
- package/dist/components/Tree.svelte +74 -33
- package/dist/components/Tree.svelte.d.ts +42 -30
- package/dist/components/Treemap.svelte +119 -42
- package/dist/components/Treemap.svelte.d.ts +75 -27
- package/dist/components/Voronoi.svelte +153 -103
- package/dist/components/Voronoi.svelte.d.ts +42 -41
- package/dist/components/charts/ArcChart.svelte +464 -0
- package/dist/components/charts/ArcChart.svelte.d.ts +90 -0
- package/dist/components/charts/AreaChart.svelte +444 -393
- package/dist/components/charts/AreaChart.svelte.d.ts +61 -0
- package/dist/components/charts/BarChart.svelte +463 -389
- package/dist/components/charts/BarChart.svelte.d.ts +76 -0
- package/dist/components/charts/ChartAnnotations.svelte +37 -0
- package/dist/components/charts/ChartAnnotations.svelte.d.ts +10 -0
- package/dist/components/charts/DefaultTooltip.svelte +60 -0
- package/dist/components/charts/DefaultTooltip.svelte.d.ts +10 -0
- package/dist/components/charts/LineChart.svelte +366 -315
- package/dist/components/charts/LineChart.svelte.d.ts +53 -0
- package/dist/components/charts/PieChart.svelte +458 -316
- package/dist/components/charts/PieChart.svelte.d.ts +137 -353
- package/dist/components/charts/ScatterChart.svelte +332 -296
- package/dist/components/charts/ScatterChart.svelte.d.ts +39 -0
- package/dist/components/charts/index.d.ts +8 -0
- package/dist/components/charts/index.js +7 -0
- package/dist/components/charts/types.d.ts +253 -0
- package/dist/components/charts/utils.svelte.d.ts +30 -0
- package/dist/components/charts/utils.svelte.js +59 -0
- package/dist/components/index.d.ts +76 -4
- package/dist/components/index.js +76 -5
- package/dist/components/layout/Canvas.svelte +347 -171
- package/dist/components/layout/Canvas.svelte.d.ts +110 -55
- package/dist/components/layout/Html.svelte +82 -42
- package/dist/components/layout/Html.svelte.d.ts +39 -28
- package/dist/components/layout/Layer.svelte +39 -0
- package/dist/components/layout/Layer.svelte.d.ts +17 -0
- package/dist/components/layout/Svg.svelte +122 -70
- package/dist/components/layout/Svg.svelte.d.ts +53 -34
- package/dist/components/layout/WebGL.svelte +135 -0
- package/dist/components/layout/WebGL.svelte.d.ts +50 -0
- package/dist/components/tooltip/Tooltip.svelte +253 -78
- package/dist/components/tooltip/Tooltip.svelte.d.ts +149 -31
- package/dist/components/tooltip/TooltipContext.svelte +426 -271
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +86 -55
- package/dist/components/tooltip/TooltipHeader.svelte +100 -11
- package/dist/components/tooltip/TooltipHeader.svelte.d.ts +43 -23
- package/dist/components/tooltip/TooltipItem.svelte +167 -27
- package/dist/components/tooltip/TooltipItem.svelte.d.ts +63 -31
- package/dist/components/tooltip/TooltipList.svelte +22 -3
- package/dist/components/tooltip/TooltipList.svelte.d.ts +6 -17
- package/dist/components/tooltip/TooltipSeparator.svelte +27 -1
- package/dist/components/tooltip/TooltipSeparator.svelte.d.ts +6 -15
- package/dist/components/tooltip/index.d.ts +6 -0
- package/dist/components/tooltip/index.js +6 -0
- package/dist/components/tooltip/tooltipMetaContext.d.ts +79 -0
- package/dist/components/tooltip/tooltipMetaContext.js +139 -0
- package/dist/components/types.d.ts +1 -0
- package/dist/components/types.js +1 -0
- package/dist/docs/Blockquote.svelte +3 -1
- package/dist/docs/Blockquote.svelte.d.ts +5 -16
- package/dist/docs/Code.svelte +20 -12
- package/dist/docs/Code.svelte.d.ts +12 -22
- package/dist/docs/ConnectorSweepMenuField.svelte +17 -0
- package/dist/docs/ConnectorSweepMenuField.svelte.d.ts +7 -0
- package/dist/docs/ConnectorTypeMenuField.svelte +17 -0
- package/dist/docs/ConnectorTypeMenuField.svelte.d.ts +7 -0
- package/dist/docs/CurveMenuField.svelte +14 -3
- package/dist/docs/CurveMenuField.svelte.d.ts +9 -18
- package/dist/docs/GeoDebug.svelte +47 -42
- package/dist/docs/GeoDebug.svelte.d.ts +4 -16
- package/dist/docs/Header1.svelte +4 -2
- package/dist/docs/Header1.svelte.d.ts +5 -18
- package/dist/docs/Json.svelte +11 -3
- package/dist/docs/Json.svelte.d.ts +9 -17
- package/dist/docs/Layout.svelte +10 -7
- package/dist/docs/Layout.svelte.d.ts +5 -15
- package/dist/docs/Link.svelte +7 -3
- package/dist/docs/Link.svelte.d.ts +5 -27
- package/dist/docs/PathDataMenuField.svelte +14 -10
- package/dist/docs/PathDataMenuField.svelte.d.ts +8 -18
- package/dist/docs/Preview.svelte +20 -7
- package/dist/docs/Preview.svelte.d.ts +12 -22
- package/dist/docs/TilesetField.svelte +20 -19
- package/dist/docs/TilesetField.svelte.d.ts +6 -19
- package/dist/docs/TransformDebug.svelte +5 -6
- package/dist/docs/TransformDebug.svelte.d.ts +18 -14
- package/dist/docs/ViewSourceButton.svelte +7 -4
- package/dist/docs/ViewSourceButton.svelte.d.ts +8 -18
- package/dist/types/d3-shape-extentions.d.ts +7 -0
- package/dist/utils/afterTick.d.ts +5 -0
- package/dist/utils/afterTick.js +8 -0
- package/dist/utils/arcText.svelte.d.ts +57 -0
- package/dist/utils/arcText.svelte.js +262 -0
- package/dist/utils/array.d.ts +9 -1
- package/dist/utils/array.js +13 -0
- package/dist/utils/attributes.d.ts +29 -0
- package/dist/utils/attributes.js +40 -0
- package/dist/utils/canvas.js +47 -10
- package/dist/utils/chart.d.ts +78 -0
- package/dist/utils/chart.js +512 -0
- package/dist/utils/color.d.ts +1 -0
- package/dist/utils/color.js +8 -0
- package/dist/utils/common.d.ts +3 -5
- package/dist/utils/common.js +3 -2
- package/dist/utils/connectorUtils.d.ts +21 -0
- package/dist/utils/connectorUtils.js +111 -0
- package/dist/utils/createId.d.ts +7 -0
- package/dist/utils/createId.js +9 -0
- package/dist/utils/debug.d.ts +1 -0
- package/dist/utils/debug.js +84 -0
- package/dist/utils/filterObject.d.ts +9 -0
- package/dist/utils/filterObject.js +12 -0
- package/dist/utils/graph/dagre.d.ts +34 -0
- package/dist/utils/graph/dagre.js +78 -0
- package/dist/utils/graph/dagre.test.d.ts +1 -0
- package/dist/utils/{graph.test.js → graph/dagre.test.js} +19 -33
- package/dist/utils/graph/sankey.d.ts +28 -0
- package/dist/utils/{graph.js → graph/sankey.js} +13 -41
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/key.svelte.d.ts +3 -0
- package/dist/utils/key.svelte.js +11 -0
- package/dist/utils/legendPayload.d.ts +7 -0
- package/dist/utils/legendPayload.js +8 -0
- package/dist/utils/motion.svelte.d.ts +140 -0
- package/dist/utils/motion.svelte.js +180 -0
- package/dist/utils/motion.test.d.ts +1 -0
- package/dist/utils/motion.test.js +213 -0
- package/dist/utils/{rect.d.ts → rect.svelte.d.ts} +7 -4
- package/dist/utils/rect.svelte.js +105 -0
- package/dist/utils/scales.svelte.d.ts +91 -0
- package/dist/utils/scales.svelte.js +201 -0
- package/dist/utils/stack.d.ts +2 -3
- package/dist/utils/stack.js +1 -1
- package/dist/utils/string.js +87 -0
- package/dist/utils/ticks.d.ts +9 -3
- package/dist/utils/ticks.js +122 -147
- package/dist/utils/ticks.test.d.ts +1 -0
- package/dist/utils/ticks.test.js +57 -0
- package/dist/utils/types.d.ts +81 -0
- package/package.json +28 -24
- package/dist/components/ChartContext.svelte +0 -295
- package/dist/components/ChartContext.svelte.d.ts +0 -139
- package/dist/components/TransformContext.svelte.d.ts +0 -158
- package/dist/stores/motionStore.d.ts +0 -30
- package/dist/stores/motionStore.js +0 -62
- package/dist/utils/graph.d.ts +0 -37
- package/dist/utils/rect.js +0 -107
- package/dist/utils/scales.d.ts +0 -66
- package/dist/utils/scales.js +0 -136
- /package/dist/{utils/graph.test.d.ts → components/charts/types.js} +0 -0
|
@@ -1,112 +1,311 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { CommonStyleProps, Without } from '../utils/types.js';
|
|
3
|
+
import type { SVGAttributes } from 'svelte/elements';
|
|
4
|
+
import { createMotion, type MotionProp } from '../utils/motion.svelte.js';
|
|
5
|
+
|
|
6
|
+
export type TextPropsWithoutHTML = {
|
|
7
|
+
/**
|
|
8
|
+
* text value
|
|
9
|
+
* @default 0
|
|
10
|
+
*/
|
|
11
|
+
value?: string | number;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The fill color of the text
|
|
15
|
+
*/
|
|
16
|
+
fill?: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Maximum width to occupy (approximate as words are not split)
|
|
20
|
+
*/
|
|
21
|
+
width?: number;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* x position of the text
|
|
25
|
+
*
|
|
26
|
+
* @default 0
|
|
27
|
+
*/
|
|
28
|
+
x?: string | number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initial x position of the text
|
|
32
|
+
*
|
|
33
|
+
* @default x
|
|
34
|
+
*/
|
|
35
|
+
initialX?: string | number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* y position of the text
|
|
39
|
+
*
|
|
40
|
+
* @default 0
|
|
41
|
+
*/
|
|
42
|
+
y?: string | number;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Initial y position of the text
|
|
46
|
+
*
|
|
47
|
+
* @default y
|
|
48
|
+
*/
|
|
49
|
+
initialY?: string | number;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* dx offset of the text
|
|
53
|
+
*
|
|
54
|
+
* @default 0
|
|
55
|
+
*/
|
|
56
|
+
dx?: string | number;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* dy offset of the text
|
|
60
|
+
*
|
|
61
|
+
* @default 0
|
|
62
|
+
*/
|
|
63
|
+
dy?: string | number;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Desired "line height" of the text, implemented as y offsets
|
|
67
|
+
*
|
|
68
|
+
* @default "1em"
|
|
69
|
+
*/
|
|
70
|
+
lineHeight?: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Cap height of the text
|
|
74
|
+
* @default '0.71em'
|
|
75
|
+
*/
|
|
76
|
+
capHeight?: string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Whether to scale the fontSize to accommodate the specified width
|
|
80
|
+
*
|
|
81
|
+
* @default false
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
scaleToFit?: boolean;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Horizontal text anchor
|
|
88
|
+
*
|
|
89
|
+
* @default 'start'
|
|
90
|
+
*/
|
|
91
|
+
textAnchor?: 'start' | 'middle' | 'end' | 'inherit';
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Vertical text anchor
|
|
95
|
+
*
|
|
96
|
+
* @default 'end'
|
|
97
|
+
*/
|
|
98
|
+
verticalAnchor?: 'start' | 'middle' | 'end' | 'inherit';
|
|
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
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Rotational angle of the text
|
|
116
|
+
*/
|
|
117
|
+
rotate?: number;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* A bindable reference to the wrapping `<svg>` element.
|
|
121
|
+
*
|
|
122
|
+
* @bindable
|
|
123
|
+
*/
|
|
124
|
+
svgRef?: SVGElement;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Props to pass to the wrapping `<svg>` element.
|
|
128
|
+
*/
|
|
129
|
+
svgProps?: Omit<SVGAttributes<SVGElement>, 'children'>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A bindable reference to the inner `<text>` element
|
|
133
|
+
*
|
|
134
|
+
* @bindable
|
|
135
|
+
*/
|
|
136
|
+
ref?: SVGTextElement;
|
|
137
|
+
motion?: MotionProp;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Whether to enable text truncation
|
|
141
|
+
*/
|
|
142
|
+
truncate?: boolean | TruncateTextOptions;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* A unique identifier for the SVG path element.
|
|
146
|
+
* One is generated by default if not provided.
|
|
147
|
+
*
|
|
148
|
+
*/
|
|
149
|
+
pathId?: string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The path to render the text along.
|
|
153
|
+
*/
|
|
154
|
+
path?: string | null;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Specify the offset for the start of the text along the path.
|
|
158
|
+
* Can be a percentage ('50%') or a length value.
|
|
159
|
+
*
|
|
160
|
+
* @default '0%'
|
|
161
|
+
*/
|
|
162
|
+
startOffset?: string | number;
|
|
163
|
+
} & CommonStyleProps;
|
|
164
|
+
|
|
165
|
+
export type TextProps = TextPropsWithoutHTML &
|
|
166
|
+
Without<SVGAttributes<SVGTextElement>, TextPropsWithoutHTML>;
|
|
167
|
+
|
|
168
|
+
function getPathLength(pathRef: SVGPathElement | undefined) {
|
|
169
|
+
if (pathRef && typeof pathRef.getTotalLength === 'function') {
|
|
170
|
+
try {
|
|
171
|
+
return pathRef.getTotalLength();
|
|
172
|
+
} catch (e) {
|
|
173
|
+
console.error('Error getting path length:', e);
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return 0;
|
|
178
|
+
}
|
|
179
|
+
</script>
|
|
180
|
+
|
|
1
181
|
<script lang="ts">
|
|
2
|
-
import { onDestroy, tick } from 'svelte';
|
|
3
|
-
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
4
182
|
import { cls } from '@layerstack/tailwind';
|
|
5
|
-
import { objectId } from '@layerstack/utils/object';
|
|
6
183
|
import { merge } from 'lodash-es';
|
|
7
184
|
|
|
8
185
|
import { getRenderContext } from './Chart.svelte';
|
|
9
|
-
import {
|
|
10
|
-
import { getStringWidth } from '../utils/string.js';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/** Rotational angle of the text */
|
|
64
|
-
export let rotate: number | undefined = undefined;
|
|
65
|
-
|
|
66
|
-
export let fill: string | undefined = undefined;
|
|
67
|
-
export let fillOpacity: number | undefined = undefined;
|
|
68
|
-
export let stroke: string | undefined = undefined;
|
|
69
|
-
export let strokeWidth: number | undefined = undefined;
|
|
70
|
-
export let opacity: number | undefined = undefined;
|
|
186
|
+
import { registerCanvasComponent } from './layout/Canvas.svelte';
|
|
187
|
+
import { getStringWidth, truncateText, type TruncateTextOptions } from '../utils/string.js';
|
|
188
|
+
import { getComputedStyles, renderText, type ComputedStylesOptions } from '../utils/canvas.js';
|
|
189
|
+
|
|
190
|
+
import { createKey } from '../utils/key.svelte.js';
|
|
191
|
+
import { layerClass } from '../utils/attributes.js';
|
|
192
|
+
import { degreesToRadians } from '../utils/math.js';
|
|
193
|
+
import { createId } from '../utils/createId.js';
|
|
194
|
+
|
|
195
|
+
const uid = $props.id();
|
|
196
|
+
|
|
197
|
+
let {
|
|
198
|
+
value,
|
|
199
|
+
x = 0,
|
|
200
|
+
initialX = x,
|
|
201
|
+
y = 0,
|
|
202
|
+
initialY = y,
|
|
203
|
+
dx = 0,
|
|
204
|
+
dy = 0,
|
|
205
|
+
lineHeight = '1em',
|
|
206
|
+
capHeight = '0.71em',
|
|
207
|
+
width,
|
|
208
|
+
scaleToFit = false,
|
|
209
|
+
textAnchor = 'start',
|
|
210
|
+
verticalAnchor = 'end',
|
|
211
|
+
dominantBaseline = 'auto',
|
|
212
|
+
rotate,
|
|
213
|
+
opacity = 1,
|
|
214
|
+
strokeWidth = 0,
|
|
215
|
+
stroke,
|
|
216
|
+
fill,
|
|
217
|
+
fillOpacity,
|
|
218
|
+
motion,
|
|
219
|
+
svgRef: svgRefProp = $bindable(),
|
|
220
|
+
ref: refProp = $bindable(),
|
|
221
|
+
class: className,
|
|
222
|
+
svgProps = {},
|
|
223
|
+
truncate = false,
|
|
224
|
+
path,
|
|
225
|
+
pathId = createId('text-path', uid),
|
|
226
|
+
startOffset = '0%',
|
|
227
|
+
transform: transformProp,
|
|
228
|
+
...restProps
|
|
229
|
+
}: TextProps = $props();
|
|
230
|
+
|
|
231
|
+
const renderCtx = getRenderContext();
|
|
232
|
+
|
|
233
|
+
let ref = $state<SVGTextElement>();
|
|
234
|
+
let svgRef = $state<SVGElement>();
|
|
235
|
+
let pathRef = $state<SVGPathElement>();
|
|
236
|
+
|
|
237
|
+
$effect.pre(() => {
|
|
238
|
+
refProp = ref;
|
|
239
|
+
});
|
|
71
240
|
|
|
72
|
-
|
|
73
|
-
|
|
241
|
+
$effect.pre(() => {
|
|
242
|
+
svgRefProp = svgRef;
|
|
243
|
+
});
|
|
74
244
|
|
|
75
|
-
let
|
|
76
|
-
let wordsWithWidth: { word: string; width: number }[] = [];
|
|
77
|
-
let spaceWidth: number = 0;
|
|
245
|
+
let style = $state<CSSStyleDeclaration>(); // TODO: read from DOM?
|
|
78
246
|
|
|
79
|
-
|
|
247
|
+
const resolvedWidth = $derived(path ? getPathLength(pathRef) : width);
|
|
80
248
|
|
|
81
|
-
|
|
249
|
+
const defaultTruncateOptions: TruncateTextOptions = $derived({
|
|
250
|
+
maxChars: undefined,
|
|
251
|
+
position: 'end',
|
|
252
|
+
maxWidth: resolvedWidth,
|
|
253
|
+
});
|
|
82
254
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
255
|
+
const truncateConfig: TruncateTextOptions | boolean = $derived.by(() => {
|
|
256
|
+
if (typeof truncate === 'boolean') {
|
|
257
|
+
if (truncate) return defaultTruncateOptions;
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
...defaultTruncateOptions,
|
|
262
|
+
...truncate,
|
|
263
|
+
};
|
|
264
|
+
});
|
|
87
265
|
|
|
88
|
-
|
|
266
|
+
// Handle null and convert `\n` strings back to newline characters
|
|
267
|
+
const rawText = $derived(value != null ? value.toString().replace(/\\n/g, '\n') : '');
|
|
89
268
|
|
|
90
|
-
|
|
91
|
-
|
|
269
|
+
const textValue = $derived.by(() => {
|
|
270
|
+
if (!truncateConfig) return rawText;
|
|
271
|
+
return truncateText(rawText, truncateConfig);
|
|
272
|
+
});
|
|
92
273
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
274
|
+
const spaceWidth = $derived(getStringWidth('\u00A0', style) || 0);
|
|
275
|
+
|
|
276
|
+
const wordsByLines = $derived.by(() => {
|
|
277
|
+
// Split by newlines to preserve explicit line breaks
|
|
278
|
+
const lines = textValue.split('\n');
|
|
279
|
+
|
|
280
|
+
return lines.flatMap((line) => {
|
|
281
|
+
// Split each line into words
|
|
282
|
+
const words = line.split(/(?:(?!\u00A0+)\s+)/);
|
|
283
|
+
|
|
284
|
+
// Handle word wrapping within each line
|
|
285
|
+
return words.reduce((result: { words: string[]; width?: number }[], item) => {
|
|
286
|
+
const currentLine = result[result.length - 1];
|
|
287
|
+
const itemWidth = getStringWidth(item, style) || 0;
|
|
288
|
+
|
|
289
|
+
if (
|
|
290
|
+
currentLine &&
|
|
291
|
+
(width == null || scaleToFit || (currentLine.width || 0) + itemWidth + spaceWidth < width)
|
|
292
|
+
) {
|
|
293
|
+
// Word can be added to an existing line
|
|
294
|
+
currentLine.words.push(item);
|
|
295
|
+
currentLine.width = currentLine.width || 0;
|
|
296
|
+
currentLine.width += itemWidth + spaceWidth;
|
|
297
|
+
} else {
|
|
298
|
+
// Add first word to line or word is too long to scaleToFit on existing line
|
|
299
|
+
const newLine = { words: [item], width: itemWidth };
|
|
300
|
+
result.push(newLine);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return result;
|
|
304
|
+
}, []);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
106
307
|
|
|
107
|
-
|
|
108
|
-
}, []);
|
|
109
|
-
$: lines = wordsByLines.length;
|
|
308
|
+
const lineCount = $derived(wordsByLines.length);
|
|
110
309
|
|
|
111
310
|
/**
|
|
112
311
|
* Convert css value to pixel value (ex. 0.71em => 11.36)
|
|
@@ -114,14 +313,11 @@
|
|
|
114
313
|
function getPixelValue(cssValue: number | string) {
|
|
115
314
|
// TODO: Properly measure pixel values using DOM (handle inherited font size, zoom, etc)
|
|
116
315
|
|
|
117
|
-
if (typeof cssValue === 'number')
|
|
118
|
-
return cssValue;
|
|
119
|
-
}
|
|
316
|
+
if (typeof cssValue === 'number') return cssValue;
|
|
120
317
|
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
switch (units) {
|
|
318
|
+
const result = cssValue.match(/([\d.]+)(\D+)/);
|
|
319
|
+
const number = Number(result?.[1]);
|
|
320
|
+
switch (result?.[2]) {
|
|
125
321
|
case 'px':
|
|
126
322
|
return number;
|
|
127
323
|
case 'em':
|
|
@@ -132,35 +328,47 @@
|
|
|
132
328
|
}
|
|
133
329
|
}
|
|
134
330
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
331
|
+
const startDy = $derived.by(() => {
|
|
332
|
+
if (verticalAnchor === 'start') {
|
|
333
|
+
return getPixelValue(capHeight);
|
|
334
|
+
} else if (verticalAnchor === 'middle') {
|
|
335
|
+
return ((lineCount - 1) / 2) * -getPixelValue(lineHeight) + getPixelValue(capHeight) / 2;
|
|
336
|
+
} else {
|
|
337
|
+
return (lineCount - 1) * -getPixelValue(lineHeight);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
143
340
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
341
|
+
const pathStartDy = $derived.by(() => {
|
|
342
|
+
if (verticalAnchor === 'start') {
|
|
343
|
+
return getPixelValue(capHeight);
|
|
344
|
+
} else if (verticalAnchor === 'middle') {
|
|
345
|
+
return (0 / 2) * -getPixelValue(lineHeight) + getPixelValue(capHeight) / 2;
|
|
346
|
+
} else {
|
|
347
|
+
return 0 * -getPixelValue(lineHeight);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const scaleTransform = $derived.by(() => {
|
|
352
|
+
if (
|
|
353
|
+
scaleToFit &&
|
|
354
|
+
lineCount > 0 &&
|
|
355
|
+
typeof x == 'number' &&
|
|
356
|
+
typeof y == 'number' &&
|
|
357
|
+
typeof width == 'number'
|
|
358
|
+
) {
|
|
359
|
+
const lineWidth = wordsByLines[0].width || 1;
|
|
360
|
+
const sx = width / lineWidth;
|
|
361
|
+
const sy = sx;
|
|
362
|
+
const originX = x - sx * x;
|
|
363
|
+
const originY = y - sy * y;
|
|
364
|
+
return `matrix(${sx}, 0, 0, ${sy}, ${originX}, ${originY})`;
|
|
365
|
+
} else {
|
|
366
|
+
return '';
|
|
367
|
+
}
|
|
368
|
+
});
|
|
162
369
|
|
|
163
|
-
|
|
370
|
+
const rotateTransform = $derived(rotate ? `rotate(${rotate}, ${x}, ${y})` : '');
|
|
371
|
+
const transform = $derived(transformProp ?? `${scaleTransform} ${rotateTransform}`);
|
|
164
372
|
|
|
165
373
|
function isValidXOrY(xOrY: string | number | undefined) {
|
|
166
374
|
return (
|
|
@@ -171,102 +379,160 @@
|
|
|
171
379
|
);
|
|
172
380
|
}
|
|
173
381
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
let tweened_x = motionStore(initialX, { spring, tweened });
|
|
178
|
-
let tweened_y = motionStore(initialY, { spring, tweened });
|
|
179
|
-
|
|
180
|
-
$: tick().then(() => {
|
|
181
|
-
tweened_x.set(x);
|
|
182
|
-
tweened_y.set(y);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const renderContext = getRenderContext();
|
|
186
|
-
const canvasContext = getCanvasContext();
|
|
382
|
+
const motionX = createMotion(initialX, () => x, motion);
|
|
383
|
+
const motionY = createMotion(initialY, () => y, motion);
|
|
187
384
|
|
|
188
385
|
function render(
|
|
189
386
|
ctx: CanvasRenderingContext2D,
|
|
190
387
|
styleOverrides: ComputedStylesOptions | undefined
|
|
191
388
|
) {
|
|
192
|
-
|
|
389
|
+
const effectiveLineHeight = getPixelValue(lineHeight);
|
|
390
|
+
const baseY = getPixelValue(motionY.current) + getPixelValue(dy) + getPixelValue(startDy);
|
|
391
|
+
const baseX = getPixelValue(motionX.current) + getPixelValue(dx);
|
|
392
|
+
|
|
393
|
+
ctx.save();
|
|
394
|
+
|
|
395
|
+
if (rotate !== undefined) {
|
|
396
|
+
const centerX = getPixelValue(x);
|
|
397
|
+
const centerY = getPixelValue(y);
|
|
398
|
+
const radians = degreesToRadians(rotate);
|
|
399
|
+
|
|
400
|
+
ctx.translate(centerX, centerY);
|
|
401
|
+
ctx.rotate(radians);
|
|
402
|
+
ctx.translate(-centerX, -centerY);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const styles = styleOverrides
|
|
406
|
+
? merge({ styles: { strokeWidth } }, styleOverrides)
|
|
407
|
+
: {
|
|
408
|
+
styles: {
|
|
409
|
+
fill,
|
|
410
|
+
fillOpacity,
|
|
411
|
+
stroke,
|
|
412
|
+
strokeWidth,
|
|
413
|
+
opacity,
|
|
414
|
+
paintOrder: 'stroke',
|
|
415
|
+
textAnchor,
|
|
416
|
+
},
|
|
417
|
+
classes: cls(fill === undefined && 'fill-surface-content', className),
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const computedStyles = getComputedStyles(ctx.canvas, styles);
|
|
421
|
+
|
|
422
|
+
ctx.font = `${computedStyles.fontSize} ${computedStyles.fontFamily}`;
|
|
423
|
+
|
|
424
|
+
const textAlign = textAnchor === 'middle' ? 'center' : textAnchor === 'end' ? 'end' : 'start';
|
|
425
|
+
ctx.textAlign = textAlign;
|
|
426
|
+
|
|
427
|
+
for (let index = 0; index < wordsByLines.length; index++) {
|
|
428
|
+
const line = wordsByLines[index];
|
|
429
|
+
const text = line.words.join(' ');
|
|
430
|
+
|
|
431
|
+
// no need to manually adjust x for textAnchor since ctx.textAlign handles it
|
|
432
|
+
const xPos = baseX;
|
|
433
|
+
const yPos = baseY + index * effectiveLineHeight;
|
|
434
|
+
|
|
193
435
|
renderText(
|
|
194
436
|
ctx,
|
|
195
|
-
|
|
437
|
+
text,
|
|
196
438
|
{
|
|
197
|
-
x:
|
|
198
|
-
y:
|
|
199
|
-
getPixelValue($tweened_y) +
|
|
200
|
-
getPixelValue(dy) +
|
|
201
|
-
(index === 0 ? startDy : getPixelValue(lineHeight)),
|
|
439
|
+
x: xPos,
|
|
440
|
+
y: yPos,
|
|
202
441
|
},
|
|
203
|
-
|
|
204
|
-
? merge({ styles: { strokeWidth } }, styleOverrides)
|
|
205
|
-
: {
|
|
206
|
-
styles: {
|
|
207
|
-
fill,
|
|
208
|
-
fillOpacity,
|
|
209
|
-
stroke,
|
|
210
|
-
strokeWidth,
|
|
211
|
-
opacity,
|
|
212
|
-
paintOrder: 'stroke',
|
|
213
|
-
textAnchor,
|
|
214
|
-
},
|
|
215
|
-
classes: cls(fill === undefined && 'fill-surface-content', className),
|
|
216
|
-
}
|
|
442
|
+
styles
|
|
217
443
|
);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
444
|
+
}
|
|
220
445
|
|
|
221
|
-
|
|
222
|
-
$: fillKey = fill && typeof fill === 'object' ? objectId(fill) : fill;
|
|
223
|
-
$: strokeKey = stroke && typeof stroke === 'object' ? objectId(stroke) : stroke;
|
|
224
|
-
|
|
225
|
-
$: if (renderContext === 'canvas') {
|
|
226
|
-
// Redraw when props change
|
|
227
|
-
value &&
|
|
228
|
-
$tweened_x &&
|
|
229
|
-
$tweened_y &&
|
|
230
|
-
fillKey &&
|
|
231
|
-
strokeKey &&
|
|
232
|
-
strokeWidth &&
|
|
233
|
-
opacity &&
|
|
234
|
-
className;
|
|
235
|
-
canvasContext.invalidate();
|
|
446
|
+
ctx.restore();
|
|
236
447
|
}
|
|
237
448
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
449
|
+
// TODO: Use objectId to work around Svelte 4 reactivity issue (even when memoizing gradients)
|
|
450
|
+
const fillKey = createKey(() => fill);
|
|
451
|
+
const strokeKey = createKey(() => stroke);
|
|
452
|
+
|
|
453
|
+
if (renderCtx === 'canvas') {
|
|
454
|
+
registerCanvasComponent({
|
|
455
|
+
name: 'Text',
|
|
456
|
+
render,
|
|
457
|
+
deps: () => [
|
|
458
|
+
value,
|
|
459
|
+
motionX.current,
|
|
460
|
+
motionY.current,
|
|
461
|
+
fillKey.current,
|
|
462
|
+
strokeKey.current,
|
|
463
|
+
strokeWidth,
|
|
464
|
+
opacity,
|
|
465
|
+
className,
|
|
466
|
+
truncateConfig,
|
|
467
|
+
rotate,
|
|
468
|
+
lineHeight,
|
|
469
|
+
textAnchor,
|
|
470
|
+
verticalAnchor,
|
|
471
|
+
],
|
|
472
|
+
});
|
|
241
473
|
}
|
|
242
|
-
|
|
243
|
-
onDestroy(() => {
|
|
244
|
-
if (renderContext === 'canvas') {
|
|
245
|
-
canvasUnregister();
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
474
|
</script>
|
|
249
475
|
|
|
250
|
-
{#if
|
|
476
|
+
{#if renderCtx === 'svg'}
|
|
251
477
|
<!-- `overflow: visible` allow contents to be shown outside element -->
|
|
252
478
|
<!-- `paint-order: stroke` supports stroke outlining text -->
|
|
253
|
-
<svg
|
|
254
|
-
{
|
|
479
|
+
<svg
|
|
480
|
+
x={dx}
|
|
481
|
+
y={dy}
|
|
482
|
+
{...svgProps}
|
|
483
|
+
class={cls(layerClass('text-svg'), 'overflow-visible [paint-order:stroke]', svgProps?.class)}
|
|
484
|
+
bind:this={svgRef}
|
|
485
|
+
>
|
|
486
|
+
{#if path}
|
|
487
|
+
<defs>
|
|
488
|
+
{#key path}
|
|
489
|
+
<path bind:this={pathRef} id={pathId} d={path} />
|
|
490
|
+
{/key}
|
|
491
|
+
</defs>
|
|
492
|
+
<text
|
|
493
|
+
bind:this={ref}
|
|
494
|
+
{dy}
|
|
495
|
+
{...restProps}
|
|
496
|
+
{fill}
|
|
497
|
+
fill-opacity={fillOpacity}
|
|
498
|
+
{stroke}
|
|
499
|
+
stroke-width={strokeWidth}
|
|
500
|
+
{opacity}
|
|
501
|
+
transform={transformProp}
|
|
502
|
+
class={cls(layerClass('text'), fill === undefined && 'fill-surface-content', className)}
|
|
503
|
+
>
|
|
504
|
+
<textPath
|
|
505
|
+
style="text-anchor: {textAnchor};"
|
|
506
|
+
dominant-baseline={dominantBaseline}
|
|
507
|
+
href="#{pathId}"
|
|
508
|
+
{startOffset}
|
|
509
|
+
class={cls(layerClass('text-path'))}
|
|
510
|
+
>
|
|
511
|
+
{wordsByLines.map((line) => line.words.join(' ')).join()}
|
|
512
|
+
</textPath>
|
|
513
|
+
</text>
|
|
514
|
+
{:else if isValidXOrY(x) && isValidXOrY(y)}
|
|
255
515
|
<text
|
|
256
|
-
|
|
257
|
-
|
|
516
|
+
bind:this={ref}
|
|
517
|
+
x={motionX.current}
|
|
518
|
+
y={motionY.current}
|
|
258
519
|
{transform}
|
|
259
520
|
text-anchor={textAnchor}
|
|
260
|
-
{
|
|
521
|
+
dominant-baseline={dominantBaseline}
|
|
522
|
+
{...restProps}
|
|
261
523
|
{fill}
|
|
262
524
|
fill-opacity={fillOpacity}
|
|
263
525
|
{stroke}
|
|
264
526
|
stroke-width={strokeWidth}
|
|
265
527
|
{opacity}
|
|
266
|
-
class={cls(fill === undefined && 'fill-surface-content', className)}
|
|
528
|
+
class={cls(layerClass('text'), fill === undefined && 'fill-surface-content', className)}
|
|
267
529
|
>
|
|
268
530
|
{#each wordsByLines as line, index}
|
|
269
|
-
<tspan
|
|
531
|
+
<tspan
|
|
532
|
+
x={motionX.current}
|
|
533
|
+
dy={index === 0 ? startDy : lineHeight}
|
|
534
|
+
class={layerClass('text-tspan')}
|
|
535
|
+
>
|
|
270
536
|
{line.words.join(' ')}
|
|
271
537
|
</tspan>
|
|
272
538
|
{/each}
|