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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { Placement } from './types.js';
|
|
4
|
-
import type
|
|
4
|
+
import { asAny, type Without } from '../utils/types.js';
|
|
5
5
|
|
|
6
6
|
export type LegendItem = {
|
|
7
7
|
value: any;
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* @default width / 64
|
|
38
38
|
*/
|
|
39
39
|
ticks?: number;
|
|
40
|
-
tickFormat?: FormatType;
|
|
40
|
+
tickFormat?: FormatType | FormatConfig;
|
|
41
41
|
tickValues?: any[];
|
|
42
42
|
/**
|
|
43
43
|
* The font size of the tick labels.
|
|
@@ -65,10 +65,6 @@
|
|
|
65
65
|
*/
|
|
66
66
|
orientation?: 'horizontal' | 'vertical';
|
|
67
67
|
|
|
68
|
-
onclick?: (e: MouseEvent, detail: LegendItem) => any;
|
|
69
|
-
onpointerenter?: (e: MouseEvent, detail: LegendItem) => any;
|
|
70
|
-
onpointerleave?: (e: MouseEvent, detail: LegendItem) => any;
|
|
71
|
-
|
|
72
68
|
/**
|
|
73
69
|
* Determine display ramp (individual color swatches or continuous ramp)
|
|
74
70
|
*
|
|
@@ -76,6 +72,11 @@
|
|
|
76
72
|
*/
|
|
77
73
|
variant?: 'ramp' | 'swatches';
|
|
78
74
|
|
|
75
|
+
/**
|
|
76
|
+
* An array of selected items. If provided, the legend fades unselected items.
|
|
77
|
+
*/
|
|
78
|
+
selected?: string[];
|
|
79
|
+
|
|
79
80
|
/**
|
|
80
81
|
* Classes to apply to the elements.
|
|
81
82
|
*
|
|
@@ -86,11 +87,15 @@
|
|
|
86
87
|
title?: string;
|
|
87
88
|
label?: string;
|
|
88
89
|
tick?: string;
|
|
89
|
-
|
|
90
|
+
items?: string;
|
|
90
91
|
swatch?: string;
|
|
91
|
-
item?: (item: LegendItem) => string;
|
|
92
|
+
item?: string | ((item: LegendItem) => string);
|
|
92
93
|
};
|
|
93
94
|
|
|
95
|
+
onclick?: (e: MouseEvent, detail: LegendItem) => any;
|
|
96
|
+
onpointerenter?: (e: MouseEvent, detail: LegendItem) => any;
|
|
97
|
+
onpointerleave?: (e: MouseEvent, detail: LegendItem) => any;
|
|
98
|
+
|
|
94
99
|
/**
|
|
95
100
|
* A bindable reference to the wrapping `<div>` element.
|
|
96
101
|
*
|
|
@@ -110,13 +115,14 @@
|
|
|
110
115
|
import { scaleBand, scaleLinear } from 'd3-scale';
|
|
111
116
|
import { quantize, interpolate, interpolateRound } from 'd3-interpolate';
|
|
112
117
|
import { quantile, range } from 'd3-array';
|
|
113
|
-
import { format, type FormatType } from '@layerstack/utils';
|
|
118
|
+
import { format, type FormatType, type FormatConfig } from '@layerstack/utils';
|
|
114
119
|
|
|
115
120
|
import ColorRamp from './ColorRamp.svelte';
|
|
116
121
|
import { cls } from '@layerstack/tailwind';
|
|
117
122
|
import type { AnyScale } from '../utils/scales.svelte.js';
|
|
118
123
|
import { getChartContext } from './Chart.svelte';
|
|
119
|
-
import { extractLayerProps
|
|
124
|
+
import { extractLayerProps } from '../utils/attributes.js';
|
|
125
|
+
import { resolveMaybeFn } from '../utils/common.js';
|
|
120
126
|
|
|
121
127
|
let {
|
|
122
128
|
scale: scaleProp,
|
|
@@ -134,6 +140,7 @@
|
|
|
134
140
|
onpointerenter,
|
|
135
141
|
onpointerleave,
|
|
136
142
|
variant = 'ramp',
|
|
143
|
+
selected = [],
|
|
137
144
|
classes = {},
|
|
138
145
|
ref: refProp = $bindable(),
|
|
139
146
|
class: className,
|
|
@@ -245,6 +252,7 @@
|
|
|
245
252
|
const tickValues = range(thresholds.length);
|
|
246
253
|
const tickFormat = (i: number) => {
|
|
247
254
|
const value = thresholds[i];
|
|
255
|
+
// @ts-expect-error - improve types
|
|
248
256
|
return tickFormatProp ? format(value, tickFormatProp) : value;
|
|
249
257
|
};
|
|
250
258
|
|
|
@@ -295,29 +303,9 @@
|
|
|
295
303
|
bind:this={ref}
|
|
296
304
|
{...restProps}
|
|
297
305
|
data-placement={placement}
|
|
298
|
-
class={cls(
|
|
299
|
-
layerClass('legend-container'),
|
|
300
|
-
'inline-block',
|
|
301
|
-
'z-1', // stack above tooltip context layers (band rects, voronoi, ...)
|
|
302
|
-
placement && [
|
|
303
|
-
'absolute',
|
|
304
|
-
{
|
|
305
|
-
'top-left': 'top-0 left-0',
|
|
306
|
-
top: 'top-0 left-1/2 -translate-x-1/2',
|
|
307
|
-
'top-right': 'top-0 right-0',
|
|
308
|
-
left: 'top-1/2 left-0 -translate-y-1/2',
|
|
309
|
-
center: 'top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
|
|
310
|
-
right: 'top-1/2 right-0 -translate-y-1/2',
|
|
311
|
-
'bottom-left': 'bottom-0 left-0',
|
|
312
|
-
bottom: 'bottom-0 left-1/2 -translate-x-1/2',
|
|
313
|
-
'bottom-right': 'bottom-0 right-0',
|
|
314
|
-
}[placement],
|
|
315
|
-
],
|
|
316
|
-
className,
|
|
317
|
-
classes.root
|
|
318
|
-
)}
|
|
306
|
+
class={cls('lc-legend-container', className, classes.root)}
|
|
319
307
|
>
|
|
320
|
-
<div class={cls(
|
|
308
|
+
<div class={cls('lc-legend-title', classes.title)}>
|
|
321
309
|
{title}
|
|
322
310
|
</div>
|
|
323
311
|
{#if children}
|
|
@@ -330,37 +318,34 @@
|
|
|
330
318
|
{width}
|
|
331
319
|
height={height + tickLengthProp + tickFontSize}
|
|
332
320
|
viewBox="0 0 {width} {height + tickLengthProp + tickFontSize}"
|
|
333
|
-
class={cls(
|
|
321
|
+
class={cls('lc-legend-ramp-svg')}
|
|
334
322
|
>
|
|
335
|
-
<g class=
|
|
323
|
+
<g class="lc-legend-ramp-g">
|
|
336
324
|
{#if scaleConfig.interpolator}
|
|
337
325
|
<ColorRamp
|
|
338
326
|
{width}
|
|
339
327
|
{height}
|
|
340
328
|
interpolator={scaleConfig.interpolator}
|
|
341
|
-
class=
|
|
329
|
+
class="lc-legend-color-ramp"
|
|
342
330
|
/>
|
|
343
331
|
{:else if scaleConfig.swatches}
|
|
344
332
|
{#each scaleConfig.swatches as swatch, i}
|
|
345
|
-
<rect {...extractLayerProps(swatch, 'legend-swatch')} />
|
|
333
|
+
<rect {...extractLayerProps(swatch, 'lc-legend-ramp-swatch')} />
|
|
346
334
|
{/each}
|
|
347
335
|
{/if}
|
|
348
336
|
</g>
|
|
349
337
|
|
|
350
|
-
<g class=
|
|
338
|
+
<g class="lc-legend-tick-group">
|
|
351
339
|
{#each tickValuesProp ?? scaleConfig.xScale?.ticks?.(ticks) ?? [] as tick, i}
|
|
352
340
|
<text
|
|
353
341
|
text-anchor="middle"
|
|
354
342
|
x={scaleConfig.xScale?.(tick) + scaleConfig.tickLabelOffset}
|
|
355
343
|
y={height + tickLengthProp + tickFontSize}
|
|
356
344
|
style:font-size={tickFontSize}
|
|
357
|
-
class={cls(
|
|
358
|
-
layerClass('legend-tick-text'),
|
|
359
|
-
'text-[10px] fill-surface-content',
|
|
360
|
-
classes.label
|
|
361
|
-
)}
|
|
345
|
+
class={cls('lc-legend-tick-text', classes.label)}
|
|
362
346
|
>
|
|
363
|
-
|
|
347
|
+
<!-- @ts-expect-error - improve types -->
|
|
348
|
+
{tickFormatProp ? format(tick, asAny(tickFormatProp)) : tick}
|
|
364
349
|
</text>
|
|
365
350
|
|
|
366
351
|
{#if scaleConfig.tickLine}
|
|
@@ -369,50 +354,138 @@
|
|
|
369
354
|
y1={0}
|
|
370
355
|
x2={scaleConfig.xScale?.(tick)}
|
|
371
356
|
y2={height + tickLengthProp}
|
|
372
|
-
class={cls(
|
|
357
|
+
class={cls('lc-legend-tick-line', classes.tick)}
|
|
373
358
|
/>
|
|
374
359
|
{/if}
|
|
375
360
|
{/each}
|
|
376
361
|
</g>
|
|
377
362
|
</svg>
|
|
378
363
|
{:else if variant === 'swatches'}
|
|
379
|
-
<div
|
|
380
|
-
class={cls(
|
|
381
|
-
layerClass('legend-swatch-group'),
|
|
382
|
-
'flex gap-x-4 gap-y-1',
|
|
383
|
-
orientation === 'vertical' && 'flex-col',
|
|
384
|
-
classes.swatches
|
|
385
|
-
)}
|
|
386
|
-
>
|
|
364
|
+
<div class={cls('lc-legend-swatch-group', classes.items)} data-orientation={orientation}>
|
|
387
365
|
{#each scaleConfig.tickValues ?? scaleConfig.xScale?.ticks?.(ticks) ?? [] as tick}
|
|
388
366
|
{@const color = scale?.(tick) ?? ''}
|
|
389
367
|
{@const item = { value: tick, color }}
|
|
390
368
|
<button
|
|
391
|
-
class={cls(
|
|
392
|
-
|
|
393
|
-
'flex gap-1',
|
|
394
|
-
!onclick && 'cursor-auto',
|
|
395
|
-
classes.item?.(item)
|
|
396
|
-
)}
|
|
369
|
+
class={cls('lc-legend-swatch-button', resolveMaybeFn(classes?.item, item))}
|
|
370
|
+
style:opacity={selected.length === 0 || selected.includes(tick) ? 1 : 0.3}
|
|
397
371
|
onclick={(e) => onclick?.(e, item)}
|
|
398
372
|
onpointerenter={(e) => onpointerenter?.(e, item)}
|
|
399
373
|
onpointerleave={(e) => onpointerleave?.(e, item)}
|
|
400
374
|
>
|
|
401
|
-
<div
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
<div
|
|
406
|
-
class={cls(
|
|
407
|
-
layerClass('legend-swatch-label'),
|
|
408
|
-
'text-xs text-surface-content whitespace-nowrap',
|
|
409
|
-
classes.label
|
|
410
|
-
)}
|
|
411
|
-
>
|
|
412
|
-
{tickFormatProp ? format(tick, tickFormatProp) : tick}
|
|
375
|
+
<div class={cls('lc-legend-swatch', classes.swatch)} style:background-color={color}></div>
|
|
376
|
+
<div class={cls('lc-legend-swatch-label', classes.label)}>
|
|
377
|
+
<!-- @ts-expect-error - improve types -->
|
|
378
|
+
{tickFormatProp ? format(tick, asAny(tickFormatProp)) : tick}
|
|
413
379
|
</div>
|
|
414
380
|
</button>
|
|
415
381
|
{/each}
|
|
416
382
|
</div>
|
|
417
383
|
{/if}
|
|
418
384
|
</div>
|
|
385
|
+
|
|
386
|
+
<style>
|
|
387
|
+
@layer components {
|
|
388
|
+
:where(.lc-legend-container) {
|
|
389
|
+
display: inline-block;
|
|
390
|
+
z-index: 1; /*stack above tooltip context layers (band rects, voronoi, ...) */
|
|
391
|
+
|
|
392
|
+
&[data-placement] {
|
|
393
|
+
position: absolute;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
&[data-placement='top-left'] {
|
|
397
|
+
top: 0;
|
|
398
|
+
left: 0;
|
|
399
|
+
}
|
|
400
|
+
&[data-placement='top'] {
|
|
401
|
+
top: 0;
|
|
402
|
+
left: 50%;
|
|
403
|
+
transform: translateX(-50%);
|
|
404
|
+
}
|
|
405
|
+
&[data-placement='top-right'] {
|
|
406
|
+
top: 0;
|
|
407
|
+
right: 0;
|
|
408
|
+
}
|
|
409
|
+
&[data-placement='left'] {
|
|
410
|
+
top: 50%;
|
|
411
|
+
left: 0;
|
|
412
|
+
transform: translateY(-50%);
|
|
413
|
+
}
|
|
414
|
+
&[data-placement='center'] {
|
|
415
|
+
top: 50%;
|
|
416
|
+
left: 50%;
|
|
417
|
+
transform: translate(-50%, -50%);
|
|
418
|
+
}
|
|
419
|
+
&[data-placement='right'] {
|
|
420
|
+
top: 50%;
|
|
421
|
+
right: 0;
|
|
422
|
+
transform: translateY(-50%);
|
|
423
|
+
}
|
|
424
|
+
&[data-placement='bottom-left'] {
|
|
425
|
+
bottom: 0;
|
|
426
|
+
left: 0;
|
|
427
|
+
}
|
|
428
|
+
&[data-placement='bottom'] {
|
|
429
|
+
bottom: 0;
|
|
430
|
+
left: 50%;
|
|
431
|
+
transform: translateX(-50%);
|
|
432
|
+
}
|
|
433
|
+
&[data-placement='bottom-right'] {
|
|
434
|
+
bottom: 0;
|
|
435
|
+
right: 0;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
:where(.lc-legend-title) {
|
|
440
|
+
font-size: 10px;
|
|
441
|
+
font-weight: 600;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
:where(.lc-legend-ramp-svg) {
|
|
445
|
+
overflow: visible;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
:where(.lc-legend-tick-text) {
|
|
449
|
+
font-size: 10px;
|
|
450
|
+
fill: var(--color-surface-content, currentColor);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
:where(.lc-legend-tick-line) {
|
|
454
|
+
stroke: var(--color-surface-content, currentColor);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
:where(.lc-legend-swatch-group) {
|
|
458
|
+
display: flex;
|
|
459
|
+
gap: 0.25rem 1rem;
|
|
460
|
+
|
|
461
|
+
&[data-orientation='vertical'] {
|
|
462
|
+
flex-direction: column;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
:where(.lc-legend-swatch-button) {
|
|
467
|
+
display: flex;
|
|
468
|
+
align-items: center;
|
|
469
|
+
gap: 0.25rem;
|
|
470
|
+
white-space: nowrap;
|
|
471
|
+
overflow: hidden;
|
|
472
|
+
text-overflow: ellipsis;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
:where(.lc-legend-swatch) {
|
|
476
|
+
width: 16px;
|
|
477
|
+
height: 16px;
|
|
478
|
+
flex-shrink: 0;
|
|
479
|
+
border-radius: 9999px; /* full */
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
:where(.lc-legend-swatch-label) {
|
|
483
|
+
font-size: 0.75rem; /* text-xs */
|
|
484
|
+
line-height: calc(1 / 0.75);
|
|
485
|
+
color: var(--color-surface-content, currentColor);
|
|
486
|
+
overflow: hidden;
|
|
487
|
+
text-overflow: ellipsis;
|
|
488
|
+
white-space: nowrap;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { Placement } from './types.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type Without } from '../utils/types.js';
|
|
4
4
|
export type LegendItem = {
|
|
5
5
|
value: any;
|
|
6
6
|
color: string;
|
|
@@ -30,7 +30,7 @@ export type LegendPropsWithoutHTML = {
|
|
|
30
30
|
* @default width / 64
|
|
31
31
|
*/
|
|
32
32
|
ticks?: number;
|
|
33
|
-
tickFormat?: FormatType;
|
|
33
|
+
tickFormat?: FormatType | FormatConfig;
|
|
34
34
|
tickValues?: any[];
|
|
35
35
|
/**
|
|
36
36
|
* The font size of the tick labels.
|
|
@@ -54,15 +54,16 @@ export type LegendPropsWithoutHTML = {
|
|
|
54
54
|
* @default 'horizontal'
|
|
55
55
|
*/
|
|
56
56
|
orientation?: 'horizontal' | 'vertical';
|
|
57
|
-
onclick?: (e: MouseEvent, detail: LegendItem) => any;
|
|
58
|
-
onpointerenter?: (e: MouseEvent, detail: LegendItem) => any;
|
|
59
|
-
onpointerleave?: (e: MouseEvent, detail: LegendItem) => any;
|
|
60
57
|
/**
|
|
61
58
|
* Determine display ramp (individual color swatches or continuous ramp)
|
|
62
59
|
*
|
|
63
60
|
* @default 'ramp'
|
|
64
61
|
*/
|
|
65
62
|
variant?: 'ramp' | 'swatches';
|
|
63
|
+
/**
|
|
64
|
+
* An array of selected items. If provided, the legend fades unselected items.
|
|
65
|
+
*/
|
|
66
|
+
selected?: string[];
|
|
66
67
|
/**
|
|
67
68
|
* Classes to apply to the elements.
|
|
68
69
|
*
|
|
@@ -73,10 +74,13 @@ export type LegendPropsWithoutHTML = {
|
|
|
73
74
|
title?: string;
|
|
74
75
|
label?: string;
|
|
75
76
|
tick?: string;
|
|
76
|
-
|
|
77
|
+
items?: string;
|
|
77
78
|
swatch?: string;
|
|
78
|
-
item?: (item: LegendItem) => string;
|
|
79
|
+
item?: string | ((item: LegendItem) => string);
|
|
79
80
|
};
|
|
81
|
+
onclick?: (e: MouseEvent, detail: LegendItem) => any;
|
|
82
|
+
onpointerenter?: (e: MouseEvent, detail: LegendItem) => any;
|
|
83
|
+
onpointerleave?: (e: MouseEvent, detail: LegendItem) => any;
|
|
80
84
|
/**
|
|
81
85
|
* A bindable reference to the wrapping `<div>` element.
|
|
82
86
|
*
|
|
@@ -90,7 +94,7 @@ export type LegendPropsWithoutHTML = {
|
|
|
90
94
|
};
|
|
91
95
|
export type LegendProps = LegendPropsWithoutHTML & Without<HTMLAttributes<HTMLElement>, LegendPropsWithoutHTML>;
|
|
92
96
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
93
|
-
import { type FormatType } from '@layerstack/utils';
|
|
97
|
+
import { type FormatType, type FormatConfig } from '@layerstack/utils';
|
|
94
98
|
import type { AnyScale } from '../utils/scales.svelte.js';
|
|
95
99
|
declare const Legend: import("svelte").Component<LegendProps, {}, "ref">;
|
|
96
100
|
type Legend = ReturnType<typeof Legend>;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { renderPathData, type ComputedStylesOptions } from '../utils/canvas.js';
|
|
5
5
|
import MarkerWrapper, { type MarkerOptions } from './MarkerWrapper.svelte';
|
|
6
6
|
import type { CommonStyleProps, Without } from '../utils/types.js';
|
|
7
|
+
import { pointsToAngleAndLength } from '../utils/math.js';
|
|
7
8
|
|
|
8
9
|
export type LinePropsWithoutHTML = {
|
|
9
10
|
/**
|
|
@@ -98,7 +99,6 @@
|
|
|
98
99
|
|
|
99
100
|
import { createKey } from '../utils/key.svelte.js';
|
|
100
101
|
import { createId } from '../utils/createId.js';
|
|
101
|
-
import { layerClass } from '../utils/attributes.js';
|
|
102
102
|
|
|
103
103
|
const uid = $props.id();
|
|
104
104
|
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
? merge({ styles: { strokeWidth } }, styleOverrides)
|
|
149
149
|
: {
|
|
150
150
|
styles: { fill, stroke, strokeWidth, opacity },
|
|
151
|
-
classes: className,
|
|
151
|
+
classes: cls('lc-line', className),
|
|
152
152
|
}
|
|
153
153
|
);
|
|
154
154
|
}
|
|
@@ -195,10 +195,47 @@
|
|
|
195
195
|
marker-start={markerStartId ? `url(#${markerStartId})` : undefined}
|
|
196
196
|
marker-mid={markerMidId ? `url(#${markerMidId})` : undefined}
|
|
197
197
|
marker-end={markerEndId ? `url(#${markerEndId})` : undefined}
|
|
198
|
-
class={cls(
|
|
198
|
+
class={cls('lc-line', className)}
|
|
199
199
|
{...restProps}
|
|
200
200
|
/>
|
|
201
201
|
<MarkerWrapper id={markerStartId} marker={markerStart ?? marker} />
|
|
202
202
|
<MarkerWrapper id={markerMidId} marker={markerMid ?? marker} />
|
|
203
203
|
<MarkerWrapper id={markerEndId} marker={markerEnd ?? marker} />
|
|
204
|
+
{:else if renderCtx === 'html'}
|
|
205
|
+
{@const { angle, length } = pointsToAngleAndLength(
|
|
206
|
+
{ x: motionX1.current, y: motionY1.current },
|
|
207
|
+
{ x: motionX2.current, y: motionY2.current }
|
|
208
|
+
)}
|
|
209
|
+
<!-- STYLE-TODO: Should html use stroke for fill? -->
|
|
210
|
+
<div
|
|
211
|
+
style:position="absolute"
|
|
212
|
+
style:left="{motionX1.current}px"
|
|
213
|
+
style:top="{motionY1.current}px"
|
|
214
|
+
style:width="{length}px"
|
|
215
|
+
style:height="{strokeWidth ?? 1}px"
|
|
216
|
+
style:transform="translateY(-50%) rotate({angle}deg)"
|
|
217
|
+
style:transform-origin="0 50%"
|
|
218
|
+
style:opacity
|
|
219
|
+
style:background-color={stroke}
|
|
220
|
+
class={cls('lc-line', className)}
|
|
221
|
+
style={restProps.style}
|
|
222
|
+
></div>
|
|
204
223
|
{/if}
|
|
224
|
+
|
|
225
|
+
<style>
|
|
226
|
+
@layer base {
|
|
227
|
+
:global(:where(.lc-line)) {
|
|
228
|
+
--stroke-color: var(--color-surface-content, currentColor);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* Svg | Canvas layers */
|
|
232
|
+
:global(:where(.lc-layout-svg .lc-line, svg.lc-line):not([stroke])) {
|
|
233
|
+
stroke: var(--stroke-color);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Html layers */
|
|
237
|
+
:global(:where(.lc-layout-html .lc-line):not([background-color])) {
|
|
238
|
+
background-color: var(--stroke-color);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
</style>
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
import { createLinearGradient, getComputedStyles } from '../utils/canvas.js';
|
|
82
82
|
import { parsePercent } from '../utils/math.js';
|
|
83
83
|
import { createId } from '../utils/createId.js';
|
|
84
|
-
import { extractLayerProps
|
|
84
|
+
import { extractLayerProps } from '../utils/attributes.js';
|
|
85
85
|
import { cls } from '@layerstack/tailwind';
|
|
86
86
|
|
|
87
87
|
const uid = $props.id();
|
|
@@ -113,6 +113,35 @@
|
|
|
113
113
|
|
|
114
114
|
let canvasGradient = $state<CanvasGradient>();
|
|
115
115
|
|
|
116
|
+
function createCSSGradient(): string {
|
|
117
|
+
if (!stops?.length) return '';
|
|
118
|
+
|
|
119
|
+
let direction: string;
|
|
120
|
+
if (rotate !== undefined) {
|
|
121
|
+
// Convert SVG rotation to CSS linear-gradient angle
|
|
122
|
+
// SVG: rotate(0) on horizontal gradient = left-to-right = CSS 90deg
|
|
123
|
+
// SVG: rotate(0) on vertical gradient = top-to-bottom = CSS 180deg
|
|
124
|
+
const baseAngle = vertical ? 180 : 90;
|
|
125
|
+
const cssAngle = baseAngle + rotate;
|
|
126
|
+
direction = `${cssAngle}deg`;
|
|
127
|
+
} else {
|
|
128
|
+
// Use direction keywords when no rotation is specified
|
|
129
|
+
direction = vertical ? 'to bottom' : 'to right';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const cssStops = stops
|
|
133
|
+
.map((stop, i) => {
|
|
134
|
+
if (Array.isArray(stop)) {
|
|
135
|
+
return `${stop[1]} ${stop[0]}`;
|
|
136
|
+
} else {
|
|
137
|
+
return `${stop} ${i * (100 / (stops.length - 1))}%`;
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
.join(', ');
|
|
141
|
+
|
|
142
|
+
return `linear-gradient(${direction}, ${cssStops})`;
|
|
143
|
+
}
|
|
144
|
+
|
|
116
145
|
function render(_ctx: CanvasRenderingContext2D) {
|
|
117
146
|
// Use `getComputedStyles()` to convert each stop (if using CSS variables and/or classes) to color values
|
|
118
147
|
const _stops = stops.map((stop, i) => {
|
|
@@ -170,7 +199,7 @@
|
|
|
170
199
|
{y2}
|
|
171
200
|
gradientTransform={rotate ? `rotate(${rotate})` : ''}
|
|
172
201
|
gradientUnits={units}
|
|
173
|
-
{...extractLayerProps(restProps, 'linear-gradient')}
|
|
202
|
+
{...extractLayerProps(restProps, 'lc-linear-gradient')}
|
|
174
203
|
>
|
|
175
204
|
{#if stopsContent}
|
|
176
205
|
{@render stopsContent?.()}
|
|
@@ -180,13 +209,13 @@
|
|
|
180
209
|
<stop
|
|
181
210
|
offset={stop[0]}
|
|
182
211
|
stop-color={stop[1]}
|
|
183
|
-
class={cls(
|
|
212
|
+
class={cls('lc-linear-gradient-stop', className)}
|
|
184
213
|
/>
|
|
185
214
|
{:else}
|
|
186
215
|
<stop
|
|
187
216
|
offset="{i * (100 / (stops.length - 1))}%"
|
|
188
217
|
stop-color={stop}
|
|
189
|
-
class={cls(
|
|
218
|
+
class={cls('lc-linear-gradient-stop', className)}
|
|
190
219
|
/>
|
|
191
220
|
{/if}
|
|
192
221
|
{/each}
|
|
@@ -195,4 +224,6 @@
|
|
|
195
224
|
</defs>
|
|
196
225
|
|
|
197
226
|
{@render children?.({ id, gradient: `url(#${id})` })}
|
|
227
|
+
{:else if renderCtx === 'html'}
|
|
228
|
+
{@render children?.({ id, gradient: createCSSGradient() })}
|
|
198
229
|
{/if}
|
|
@@ -73,7 +73,6 @@
|
|
|
73
73
|
<script lang="ts">
|
|
74
74
|
import { cls } from '@layerstack/tailwind';
|
|
75
75
|
import { createId } from '../utils/createId.js';
|
|
76
|
-
import { layerClass } from '../utils/attributes.js';
|
|
77
76
|
|
|
78
77
|
const uid = $props.id();
|
|
79
78
|
|
|
@@ -104,39 +103,51 @@
|
|
|
104
103
|
{refX}
|
|
105
104
|
{refY}
|
|
106
105
|
{viewBox}
|
|
106
|
+
data-type={type}
|
|
107
107
|
{...restProps}
|
|
108
|
-
class={cls(
|
|
109
|
-
layerClass('marker'),
|
|
110
|
-
'overflow-visible',
|
|
111
|
-
// stroke
|
|
112
|
-
restProps.stroke == null &&
|
|
113
|
-
(['arrow', 'circle-stroke', 'line'].includes(type ?? '')
|
|
114
|
-
? 'stroke-[context-stroke]'
|
|
115
|
-
: type === 'circle'
|
|
116
|
-
? 'stroke-surface-100'
|
|
117
|
-
: 'stroke-none'),
|
|
118
|
-
// extra stroke attrs
|
|
119
|
-
'[stroke-linecap:round] [stroke-linejoin:round]',
|
|
120
|
-
//fill
|
|
121
|
-
restProps.fill == null &&
|
|
122
|
-
(['triangle', 'dot', 'circle'].includes(type ?? '')
|
|
123
|
-
? 'fill-[context-stroke]'
|
|
124
|
-
: type === 'circle-stroke'
|
|
125
|
-
? 'fill-surface-100'
|
|
126
|
-
: 'fill-none'),
|
|
127
|
-
className
|
|
128
|
-
)}
|
|
108
|
+
class={cls('lc-marker', className)}
|
|
129
109
|
>
|
|
130
110
|
{#if children}
|
|
131
111
|
{@render children()}
|
|
132
112
|
{:else if type === 'triangle'}
|
|
133
|
-
<path d="M 0 0 L 10 5 L 0 10 z" class=
|
|
113
|
+
<path d="M 0 0 L 10 5 L 0 10 z" class="lc-marker-triangle" />
|
|
134
114
|
{:else if type === 'arrow'}
|
|
135
|
-
<polyline points="0 0, 10 5, 0 10" class=
|
|
115
|
+
<polyline points="0 0, 10 5, 0 10" class="lc-marker-arrow" />
|
|
136
116
|
{:else if type === 'circle' || type === 'circle-stroke' || type === 'dot'}
|
|
137
|
-
<circle cx={5} cy={5} r={5} class=
|
|
117
|
+
<circle cx={5} cy={5} r={5} class="lc-marker-circle" />
|
|
138
118
|
{:else if type === 'line'}
|
|
139
|
-
<polyline points="5 0, 5 10" class=
|
|
119
|
+
<polyline points="5 0, 5 10" class="lc-marker-line" />
|
|
140
120
|
{/if}
|
|
141
121
|
</marker>
|
|
142
122
|
</defs>
|
|
123
|
+
|
|
124
|
+
<style>
|
|
125
|
+
@layer base {
|
|
126
|
+
:global(:where(.lc-marker)) {
|
|
127
|
+
overflow: visible;
|
|
128
|
+
|
|
129
|
+
&[data-type='arrow'],
|
|
130
|
+
&[data-type='circle-stroke'],
|
|
131
|
+
&[data-type='line'] {
|
|
132
|
+
fill: none;
|
|
133
|
+
stroke: context-stroke;
|
|
134
|
+
stroke-linecap: round;
|
|
135
|
+
stroke-linejoin: round;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&[data-type='circle'] {
|
|
139
|
+
stroke: var(--color-surface-100, light-dark(white, black));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&[data-type='triangle'],
|
|
143
|
+
&[data-type='dot'],
|
|
144
|
+
&[data-type='circle'] {
|
|
145
|
+
fill: context-stroke;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&[data-type='circle-stroke'] {
|
|
149
|
+
fill: var(--color-surface-100, light-dark(white, black));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
</style>
|