layerchart 0.93.2 → 0.93.4

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.
@@ -7,8 +7,7 @@
7
7
 
8
8
  import { motionStore } from '../stores/motionStore.js';
9
9
  import { getCanvasContext } from './layout/Canvas.svelte';
10
- import { circlePath } from '../utils/path.js';
11
- import { renderPathData, type ComputedStylesOptions } from '../utils/canvas.js';
10
+ import { renderCircle, type ComputedStylesOptions } from '../utils/canvas.js';
12
11
 
13
12
  export let cx: number = 0;
14
13
  export let initialCx = cx;
@@ -53,10 +52,9 @@
53
52
  ctx: CanvasRenderingContext2D,
54
53
  styleOverrides: ComputedStylesOptions | undefined
55
54
  ) {
56
- const pathData = circlePath({ cx: $tweened_cx, cy: $tweened_cy, r: $tweened_r });
57
- renderPathData(
55
+ renderCircle(
58
56
  ctx,
59
- pathData,
57
+ { cx: $tweened_cx, cy: $tweened_cy, r: $tweened_r },
60
58
  styleOverrides
61
59
  ? merge({ styles: { strokeWidth } }, styleOverrides)
62
60
  : {
@@ -368,13 +368,8 @@
368
368
  <slot name="bar" {bar}>
369
369
  <Bar
370
370
  spring={motion}
371
- x={typeof bar === 'object' ? bar.x : undefined}
372
- y={typeof bar === 'object' ? bar.y : undefined}
373
- insets={typeof bar === 'object' ? bar.insets : undefined}
374
- stroke={typeof bar === 'object' ? bar.stroke : undefined}
375
- strokeWidth={typeof bar === 'object' ? bar.strokeWidth : undefined}
376
- radius={typeof bar === 'object' ? bar.radius : undefined}
377
371
  bar={highlightData}
372
+ {...typeof bar === 'object' ? bar : null}
378
373
  class={cls(
379
374
  // @ts-expect-error
380
375
  !bar.fill && 'fill-primary',
@@ -346,15 +346,15 @@
346
346
  {/if}
347
347
  </slot>
348
348
 
349
- <slot name="belowMarks" {...slotProps} />
349
+ <ChartClipPath disabled={!brush}>
350
+ <slot name="belowMarks" {...slotProps} />
350
351
 
351
- <slot name="marks" {...slotProps}>
352
- <ChartClipPath disabled={!brush}>
352
+ <slot name="marks" {...slotProps}>
353
353
  {#each visibleSeries as s, i (s.key)}
354
354
  <Area {...getAreaProps(s, i)} />
355
355
  {/each}
356
- </ChartClipPath>
357
- </slot>
356
+ </slot>
357
+ </ChartClipPath>
358
358
 
359
359
  <slot name="aboveMarks" {...slotProps} />
360
360
 
@@ -390,43 +390,46 @@
390
390
  {/if}
391
391
  </slot>
392
392
 
393
- {#if points}
394
- {#each visibleSeries as s, i (s.key)}
395
- <Points {...getPointsProps(s, i)} />
396
- {/each}
397
- {/if}
393
+ <!-- Use `full` to allow labels on edge to not be cropped (bleed into padding) -->
394
+ <ChartClipPath disabled={!brush} full>
395
+ {#if points}
396
+ {#each visibleSeries as s, i (s.key)}
397
+ <Points {...getPointsProps(s, i)} />
398
+ {/each}
399
+ {/if}
398
400
 
399
- <slot name="highlight" {...slotProps}>
400
- {#each visibleSeries as s, i (s.key)}
401
- {@const seriesTooltipData =
402
- s.data && tooltip.data ? findRelatedData(s.data, tooltip.data, x) : null}
403
-
404
- <Highlight
405
- data={seriesTooltipData}
406
- y={stackSeries ? (d) => d.stackData[i][1] : (s.value ?? (s.data ? undefined : s.key))}
407
- points={{
408
- fill: s.color,
409
- class: cls(
410
- 'transition-opacity',
411
- highlightSeriesKey && highlightSeriesKey !== s.key && 'opacity-10'
412
- ),
413
- }}
414
- lines={i == 0}
415
- onpointclick={onpointclick
416
- ? (e, detail) => onpointclick(e, { ...detail, series: s })
417
- : undefined}
418
- onpointenter={() => (highlightSeriesKey = s.key)}
419
- onpointleave={() => (highlightSeriesKey = null)}
420
- {...props.highlight}
421
- />
422
- {/each}
423
- </slot>
401
+ <slot name="highlight" {...slotProps}>
402
+ {#each visibleSeries as s, i (s.key)}
403
+ {@const seriesTooltipData =
404
+ s.data && tooltip.data ? findRelatedData(s.data, tooltip.data, x) : null}
405
+
406
+ <Highlight
407
+ data={seriesTooltipData}
408
+ y={stackSeries ? (d) => d.stackData[i][1] : (s.value ?? (s.data ? undefined : s.key))}
409
+ points={{
410
+ fill: s.color,
411
+ class: cls(
412
+ 'transition-opacity',
413
+ highlightSeriesKey && highlightSeriesKey !== s.key && 'opacity-10'
414
+ ),
415
+ }}
416
+ lines={i == 0}
417
+ onpointclick={onpointclick
418
+ ? (e, detail) => onpointclick(e, { ...detail, series: s })
419
+ : undefined}
420
+ onpointenter={() => (highlightSeriesKey = s.key)}
421
+ onpointleave={() => (highlightSeriesKey = null)}
422
+ {...props.highlight}
423
+ />
424
+ {/each}
425
+ </slot>
424
426
 
425
- {#if labels}
426
- {#each visibleSeries as s, i (s.key)}
427
- <Labels {...getLabelsProps(s, i)} />
428
- {/each}
429
- {/if}
427
+ {#if labels}
428
+ {#each visibleSeries as s, i (s.key)}
429
+ <Labels {...getLabelsProps(s, i)} />
430
+ {/each}
431
+ {/if}
432
+ </ChartClipPath>
430
433
  </svelte:component>
431
434
 
432
435
  <slot name="legend" {...slotProps}>
@@ -276,17 +276,17 @@
276
276
  {/if}
277
277
  </slot>
278
278
 
279
- <slot name="belowMarks" {...slotProps} />
279
+ <ChartClipPath disabled={!brush}>
280
+ <slot name="belowMarks" {...slotProps} />
280
281
 
281
- <slot name="marks" {...slotProps}>
282
- <ChartClipPath disabled={!brush}>
282
+ <slot name="marks" {...slotProps}>
283
283
  {#each visibleSeries as s, i (s.key)}
284
284
  <Spline {...getSplineProps(s, i)} />
285
285
  {/each}
286
- </ChartClipPath>
287
- </slot>
286
+ </slot>
288
287
 
289
- <slot name="aboveMarks" {...slotProps} />
288
+ <slot name="aboveMarks" {...slotProps} />
289
+ </ChartClipPath>
290
290
 
291
291
  <slot name="axis" {...slotProps}>
292
292
  {#if axis}
@@ -314,42 +314,45 @@
314
314
  {/if}
315
315
  </slot>
316
316
 
317
- {#if points}
318
- {#each visibleSeries as s, i (s.key)}
319
- <Points {...getPointsProps(s, i)} />
320
- {/each}
321
- {/if}
317
+ <!-- Use `full` to allow labels on edge to not be cropped (bleed into padding) -->
318
+ <ChartClipPath disabled={!brush} full>
319
+ {#if points}
320
+ {#each visibleSeries as s, i (s.key)}
321
+ <Points {...getPointsProps(s, i)} />
322
+ {/each}
323
+ {/if}
322
324
 
323
- {#if labels}
324
- {#each visibleSeries as s, i (s.key)}
325
- <Labels {...getLabelsProps(s, i)} />
326
- {/each}
327
- {/if}
325
+ {#if labels}
326
+ {#each visibleSeries as s, i (s.key)}
327
+ <Labels {...getLabelsProps(s, i)} />
328
+ {/each}
329
+ {/if}
328
330
 
329
- <slot name="highlight" {...slotProps}>
330
- {#each visibleSeries as s, i (s.key)}
331
- {@const seriesTooltipData =
332
- s.data && tooltip.data ? findRelatedData(s.data, tooltip.data, x) : null}
333
- <Highlight
334
- data={seriesTooltipData}
335
- y={s.value ?? (s.data ? undefined : s.key)}
336
- points={{
337
- fill: s.color,
338
- class: cls(
339
- 'transition-opacity',
340
- highlightSeriesKey && highlightSeriesKey !== s.key && 'opacity-10'
341
- ),
342
- }}
343
- lines={i === 0}
344
- onpointclick={onpointclick
345
- ? (e, detail) => onpointclick(e, { ...detail, series: s })
346
- : undefined}
347
- onpointenter={() => (highlightSeriesKey = s.key)}
348
- onpointleave={() => (highlightSeriesKey = null)}
349
- {...props.highlight}
350
- />
351
- {/each}
352
- </slot>
331
+ <slot name="highlight" {...slotProps}>
332
+ {#each visibleSeries as s, i (s.key)}
333
+ {@const seriesTooltipData =
334
+ s.data && tooltip.data ? findRelatedData(s.data, tooltip.data, x) : null}
335
+ <Highlight
336
+ data={seriesTooltipData}
337
+ y={s.value ?? (s.data ? undefined : s.key)}
338
+ points={{
339
+ fill: s.color,
340
+ class: cls(
341
+ 'transition-opacity',
342
+ highlightSeriesKey && highlightSeriesKey !== s.key && 'opacity-10'
343
+ ),
344
+ }}
345
+ lines={i === 0}
346
+ onpointclick={onpointclick
347
+ ? (e, detail) => onpointclick(e, { ...detail, series: s })
348
+ : undefined}
349
+ onpointenter={() => (highlightSeriesKey = s.key)}
350
+ onpointleave={() => (highlightSeriesKey = null)}
351
+ {...props.highlight}
352
+ />
353
+ {/each}
354
+ </slot>
355
+ </ChartClipPath>
353
356
  </svelte:component>
354
357
 
355
358
  <slot name="legend" {...slotProps}>
@@ -242,17 +242,17 @@
242
242
  {/if}
243
243
  </slot>
244
244
 
245
- <slot name="belowMarks" {...slotProps} />
245
+ <ChartClipPath disabled={!brush}>
246
+ <slot name="belowMarks" {...slotProps} />
246
247
 
247
- <slot name="marks" {...slotProps}>
248
- <ChartClipPath disabled={!brush}>
248
+ <slot name="marks" {...slotProps}>
249
249
  {#each visibleSeries as s, i (s.key)}
250
250
  <Points {...getPointsProps(s, i)} />
251
251
  {/each}
252
- </ChartClipPath>
253
- </slot>
252
+ </slot>
254
253
 
255
- <slot name="aboveMarks" {...slotProps} />
254
+ <slot name="aboveMarks" {...slotProps} />
255
+ </ChartClipPath>
256
256
 
257
257
  <slot name="axis" {...slotProps}>
258
258
  {#if axis}
@@ -280,15 +280,23 @@
280
280
  {/if}
281
281
  </slot>
282
282
 
283
- <slot name="highlight" {...slotProps}>
284
- <Highlight points={{ fill: activeSeries?.color }} lines axis="both" {...props.highlight} />
285
- </slot>
283
+ <!-- Use `full` to allow labels on edge to not be cropped (bleed into padding) -->
284
+ <ChartClipPath disabled={!brush} full>
285
+ <slot name="highlight" {...slotProps}>
286
+ <Highlight
287
+ points={{ fill: activeSeries?.color }}
288
+ lines
289
+ axis="both"
290
+ {...props.highlight}
291
+ />
292
+ </slot>
286
293
 
287
- {#if labels}
288
- {#each visibleSeries as s, i (s.key)}
289
- <Labels {...getLabelsProps(s, i)} />
290
- {/each}
291
- {/if}
294
+ {#if labels}
295
+ {#each visibleSeries as s, i (s.key)}
296
+ <Labels {...getLabelsProps(s, i)} />
297
+ {/each}
298
+ {/if}
299
+ </ChartClipPath>
292
300
  </svelte:component>
293
301
 
294
302
  <slot name="legend" {...slotProps}>
@@ -38,6 +38,7 @@
38
38
  <script lang="ts">
39
39
  import { onMount } from 'svelte';
40
40
  import { cls } from '@layerstack/tailwind';
41
+ import { Logger } from '@layerstack/utils';
41
42
 
42
43
  import { chartContext } from '../ChartContext.svelte';
43
44
  import { transformContext } from '../TransformContext.svelte';
@@ -85,6 +86,8 @@
85
86
  /** Show hit canvas for debugging */
86
87
  export let debug = false;
87
88
 
89
+ const logger = new Logger('Canvas');
90
+
88
91
  let components = new Map<Symbol, ComponentRender>();
89
92
  let pendingInvalidation = false;
90
93
  let frameId: number | undefined;
@@ -106,7 +109,9 @@
106
109
  const { x, y } = localPoint(e.target as HTMLCanvasElement, e) ?? { x: 0, y: 0 };
107
110
  const color = getPixelColor(hitCanvasContext!, x, y);
108
111
  const colorKey = getColorStr(color);
109
- return componentByColor.get(colorKey);
112
+ const component = componentByColor.get(colorKey);
113
+ logger.debug({ colorKey, component, componentByColor });
114
+ return component;
110
115
  }
111
116
 
112
117
  function onPointerMove(e: PointerEvent) {
@@ -76,8 +76,10 @@ function render(ctx, render, styleOptions = {}) {
76
76
  }
77
77
  paintOrder.forEach((attr) => {
78
78
  if (attr === 'fill') {
79
- const fill = styleOptions.styles?.fill instanceof CanvasGradient
80
- ? styleOptions.styles?.fill
79
+ const fill = styleOptions.styles?.fill &&
80
+ (styleOptions.styles?.fill instanceof CanvasGradient ||
81
+ !styleOptions.styles?.fill?.includes('var'))
82
+ ? styleOptions.styles.fill
81
83
  : ['none', DEFAULT_FILL].includes(computedStyles?.fill)
82
84
  ? null
83
85
  : computedStyles?.fill;
@@ -93,7 +95,9 @@ function render(ctx, render, styleOptions = {}) {
93
95
  }
94
96
  }
95
97
  else if (attr === 'stroke') {
96
- const stroke = styleOptions.styles?.stroke instanceof CanvasGradient
98
+ const stroke = styleOptions.styles?.stroke &&
99
+ (styleOptions.styles?.stroke instanceof CanvasGradient ||
100
+ !styleOptions.styles?.stroke?.includes('var'))
97
101
  ? styleOptions.styles?.stroke
98
102
  : computedStyles?.stroke === 'none'
99
103
  ? null
@@ -131,6 +135,19 @@ export function renderRect(ctx, coords, styleOptions = {}) {
131
135
  stroke: (ctx) => ctx.strokeRect(coords.x, coords.y, coords.width, coords.height),
132
136
  }, styleOptions);
133
137
  }
138
+ export function renderCircle(ctx, coords, styleOptions = {}) {
139
+ ctx.beginPath();
140
+ ctx.arc(coords.cx, coords.cy, coords.r, 0, 2 * Math.PI);
141
+ render(ctx, {
142
+ fill: (ctx) => {
143
+ ctx.fill();
144
+ },
145
+ stroke: (ctx) => {
146
+ ctx.stroke();
147
+ },
148
+ }, styleOptions);
149
+ ctx.closePath();
150
+ }
134
151
  /** Clear canvas accounting for Canvas `context.translate(...)` */
135
152
  export function clearCanvasContext(ctx, options) {
136
153
  // Clear with negative offset due to Canvas `context.translate(...)`
@@ -3,13 +3,18 @@ export declare function rgbColorGenerator(step?: number): Generator<{
3
3
  r: number;
4
4
  g: number;
5
5
  b: number;
6
+ a: number;
6
7
  }, {
7
8
  r: number;
8
9
  g: number;
9
10
  b: number;
11
+ a: number;
10
12
  }, unknown>;
11
- export declare function getColorStr(color: {
13
+ type RGBColor = {
12
14
  r: number;
13
15
  g: number;
14
16
  b: number;
15
- }): string;
17
+ a?: number;
18
+ };
19
+ export declare function getColorStr(color: RGBColor): string;
20
+ export {};
@@ -1,15 +1,20 @@
1
1
  /** Generator to create a new color on each call */
2
2
  export function* rgbColorGenerator(step = 500) {
3
- let nextColor = 1;
3
+ let nextColor = 0;
4
4
  while (nextColor < 16777216) {
5
5
  const r = nextColor & 0xff;
6
6
  const g = (nextColor & 0xff00) >> 8;
7
7
  const b = (nextColor & 0xff0000) >> 16;
8
8
  nextColor += step;
9
- yield { r, g, b };
9
+ yield { r, g, b, a: 255 };
10
10
  }
11
- return { r: 0, g: 0, b: 0 };
11
+ return { r: 0, g: 0, b: 0, a: 255 };
12
12
  }
13
13
  export function getColorStr(color) {
14
- return `rgb(${color.r},${color.g},${color.b})`;
14
+ if (color.a !== undefined) {
15
+ return `rgba(${color.r},${color.g},${color.b},${color.a})`;
16
+ }
17
+ else {
18
+ return `rgb(${color.r},${color.g},${color.b})`;
19
+ }
15
20
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "author": "Sean Lynch <techniq35@gmail.com>",
5
5
  "license": "MIT",
6
6
  "repository": "techniq/layerchart",
7
- "version": "0.93.2",
7
+ "version": "0.93.4",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.27.12",
10
10
  "@mdi/js": "^7.4.47",