@yewdiel21/motion-kit 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/auto/index.d.ts +3 -3
- package/dist/auto/index.js +2 -2
- package/dist/{chunk-6IRJYXJU.js → chunk-NFZIX3IA.js} +2 -2
- package/dist/{chunk-JXRS3OEA.js → chunk-RBEKR5UZ.js} +29 -7
- package/dist/chunk-RBEKR5UZ.js.map +1 -0
- package/dist/{chunk-A6QQCF6V.js → chunk-SDQ776LG.js} +129 -17
- package/dist/chunk-SDQ776LG.js.map +1 -0
- package/dist/css/components/chart.css +7 -0
- package/dist/css/components/heatmap-chart.css +7 -0
- package/dist/css/components/pie-chart.css +7 -0
- package/dist/css/components/radar-chart.css +7 -0
- package/dist/css/components/radial-chart.css +16 -2
- package/dist/css/components/sankey-chart.css +7 -0
- package/dist/css/components/scroll-island.css +3 -0
- package/dist/elements/index.d.ts +3 -3
- package/dist/elements/index.js +11 -6
- package/dist/elements/index.js.map +1 -1
- package/dist/index.css +19 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/react/index.d.ts +9 -9
- package/dist/react/index.js +16 -10
- package/dist/react/index.js.map +1 -1
- package/dist/{reduced-6X_bns60.d.ts → reduced-DQwVXQYb.d.ts} +1 -1
- package/dist/{reveal-BfyKKsw4.d.ts → reveal-DRpNO4KP.d.ts} +12 -0
- package/dist/{store-CA2Qcun_.d.ts → store-Da3zSh8Z.d.ts} +5 -1
- package/package.json +1 -1
- package/src/components/add-to-cart/README.md +49 -34
- package/src/components/add-to-cart/react.tsx +4 -0
- package/src/components/chart/README.md +49 -34
- package/src/components/chart/chart.css +7 -0
- package/src/components/chart/element.ts +2 -1
- package/src/components/chart/engine.ts +105 -13
- package/src/components/chart/react.tsx +2 -2
- package/src/components/radial-chart/README.md +10 -0
- package/src/components/radial-chart/element.ts +2 -2
- package/src/components/radial-chart/engine.ts +33 -6
- package/src/components/radial-chart/radial-chart.css +9 -2
- package/src/components/radial-chart/react.tsx +2 -2
- package/src/components/scroll-island/README.md +44 -34
- package/src/components/scroll-island/element.ts +1 -1
- package/src/components/scroll-island/engine.ts +25 -3
- package/src/components/scroll-island/react.tsx +3 -3
- package/src/components/scroll-island/scroll-island.css +3 -0
- package/dist/chunk-A6QQCF6V.js.map +0 -1
- package/dist/chunk-JXRS3OEA.js.map +0 -1
- /package/dist/{chunk-6IRJYXJU.js.map → chunk-NFZIX3IA.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bY as MenuOptions, bX as MenuInstance, bd as DialogOptions, bb as DialogInstance, cv as RevealSpeed } from './reveal-
|
|
1
|
+
import { bY as MenuOptions, bX as MenuInstance, bd as DialogOptions, bb as DialogInstance, cv as RevealSpeed } from './reveal-DRpNO4KP.js';
|
|
2
2
|
import { I as Instance } from './types-BkS_raL8.js';
|
|
3
3
|
import { SplitText } from 'gsap/SplitText';
|
|
4
4
|
|
|
@@ -780,6 +780,16 @@ interface ChartOptions {
|
|
|
780
780
|
points?: ChartPoint[];
|
|
781
781
|
/** Bars only: stack the series. */
|
|
782
782
|
stacked?: boolean;
|
|
783
|
+
/** Rounded ends (default) or a full capsule, including stacked columns. */
|
|
784
|
+
barStyle?: 'rounded' | 'pill';
|
|
785
|
+
/** Show the available capacity behind each column. */
|
|
786
|
+
barTrack?: boolean;
|
|
787
|
+
/** Solid (default), gradient, or a gradient selection over muted striped columns. */
|
|
788
|
+
barFill?: 'solid' | 'gradient' | 'spotlight';
|
|
789
|
+
/** Maximum column width in px (default 24; pill demos use 40). */
|
|
790
|
+
barWidth?: number;
|
|
791
|
+
/** Smooth monotone curves preserve the data's extrema (default linear). */
|
|
792
|
+
curve?: 'linear' | 'smooth';
|
|
783
793
|
formatValue?: (value: number) => string;
|
|
784
794
|
/** Accessible name (and table caption). */
|
|
785
795
|
label?: string;
|
|
@@ -2102,6 +2112,8 @@ interface ScrollIslandOptions {
|
|
|
2102
2112
|
reach?: number;
|
|
2103
2113
|
/** ms the bar stays after scrolling stops (default 900). */
|
|
2104
2114
|
idle?: number;
|
|
2115
|
+
/** Keep the thin bar visible while idle (default false). */
|
|
2116
|
+
persistent?: boolean;
|
|
2105
2117
|
/** Follow the page's scroll (default: when the root is <html> or <body>). */
|
|
2106
2118
|
page?: boolean;
|
|
2107
2119
|
/** The current section changed (its heading's text, or null before the first). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { I as Instance } from './types-BkS_raL8.js';
|
|
2
2
|
import { Flip } from 'gsap/Flip';
|
|
3
|
-
import { a3 as RevealHandle, a4 as DateInput } from './reveal-
|
|
3
|
+
import { a3 as RevealHandle, a4 as DateInput } from './reveal-DRpNO4KP.js';
|
|
4
4
|
|
|
5
5
|
interface ThemePickerOptions {
|
|
6
6
|
/** Theme ids to show, in order. Default: visible presets, or all with showHidden. */
|
|
@@ -301,6 +301,10 @@ interface RadialChartOptions {
|
|
|
301
301
|
size?: number;
|
|
302
302
|
/** Ring thickness in px (default: what fits, up to 16). */
|
|
303
303
|
thickness?: number;
|
|
304
|
+
/** Discrete sectors per ring (0: continuous, default). */
|
|
305
|
+
segments?: number;
|
|
306
|
+
/** Show values (default) or progress toward the goals in the middle. */
|
|
307
|
+
center?: 'value' | 'percent';
|
|
304
308
|
label?: string;
|
|
305
309
|
/** The middle when nothing is chosen (default 'Total'). */
|
|
306
310
|
totalLabel?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yewdiel21/motion-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Motion toolkit for vanilla, Astro and React: GSAP recipes, accessible components, 19 themes, CSS controls and optional WebGL effects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -1,34 +1,49 @@
|
|
|
1
|
-
# add-to-cart
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
# add-to-cart
|
|
2
|
+
|
|
3
|
+
El producto se empaca en una caja y vuela hasta un carrito; al llegar, el contador cambia y el carrito responde con un pulso. Cada clic tiene su propio vuelo. Con movimiento reducido, el contador se actualiza al instante.
|
|
4
|
+
|
|
5
|
+
## React
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import '@yewdiel21/motion-kit/css';
|
|
9
|
+
import { AddToCart } from '@yewdiel21/motion-kit/react';
|
|
10
|
+
|
|
11
|
+
<div id="my-cart">Carrito <span data-mk-cart-count>0</span></div>
|
|
12
|
+
<article data-mk-cart-item>
|
|
13
|
+
<img src="/product.webp" alt="Producto" data-mk-cart-image />
|
|
14
|
+
<AddToCart target="#my-cart" onLand={count => console.log(count)}>
|
|
15
|
+
<button type="button">Agregar al carrito</button>
|
|
16
|
+
</AddToCart>
|
|
17
|
+
</article>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**El botón es obligatorio.** Para ver el recorrido necesitas un destino visible y una imagen. Usa un destino único por demo o carrito para no mezclar instancias. El componente anima la interfaz; la aplicación gestiona el carrito y el inventario reales.
|
|
21
|
+
|
|
22
|
+
## HTML / Astro
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<div id="my-cart">Carrito <span data-mk-cart-count>0</span></div>
|
|
26
|
+
<article data-mk-cart-item>
|
|
27
|
+
<img src="/product.webp" alt="Producto" data-mk-cart-image>
|
|
28
|
+
<mk-add-to-cart target="#my-cart"><button type="button">Agregar</button></mk-add-to-cart>
|
|
29
|
+
</article>
|
|
30
|
+
<script>
|
|
31
|
+
import { defineElements } from '@yewdiel21/motion-kit/elements';
|
|
32
|
+
defineElements(['mk-add-to-cart']);
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
En vanilla puedes llamar a `createAddToCart(root, options)`. `destroy()` limpia los vuelos y listeners.
|
|
37
|
+
|
|
38
|
+
## Opciones y eventos
|
|
39
|
+
|
|
40
|
+
- `target`: HTMLElement o selector del carrito; por defecto busca `[data-mk-cart-target]` visible.
|
|
41
|
+
- `image`: HTMLElement o selector; por defecto `[data-mk-cart-image]` dentro del producto.
|
|
42
|
+
- `quantity`: unidades por clic, 1 por defecto.
|
|
43
|
+
- `count`: contador inicial; en React también sincroniza cambios posteriores.
|
|
44
|
+
- `label`: anuncio al llegar, por defecto “Añadido al carrito”.
|
|
45
|
+
- `onAdd(count)`: al pulsar; `onLand(count)`: al terminar el vuelo.
|
|
46
|
+
- Eventos DOM: `mk:add` y `mk:land`, con `detail.count`.
|
|
47
|
+
- Instancia: `add()`, `setCount(count)`, `count`, `destroy()`; React expone `instanceRef`.
|
|
48
|
+
|
|
49
|
+
El estado final se anuncia con `role="status"`. Usa un botón nativo con nombre accesible. Los vuelos son decorativos, no capturan el puntero y se eliminan al desmontar.
|
|
@@ -12,15 +12,19 @@ export function AddToCart({ target, image, quantity, count, label, onAdd, onLand
|
|
|
12
12
|
const ref = useRef<HTMLDivElement>(null);
|
|
13
13
|
const add = useLatest(onAdd);
|
|
14
14
|
const landed = useLatest(onLand);
|
|
15
|
+
const instance = useRef<AddToCartInstance | null>(null);
|
|
15
16
|
useIsomorphicLayoutEffect(() => {
|
|
16
17
|
const created = createAddToCart(ref.current, { target, image, quantity, count, label, onAdd: (n) => add.current?.(n), onLand: (n) => landed.current?.(n) });
|
|
18
|
+
instance.current = created;
|
|
17
19
|
if (instanceRef) instanceRef.current = created;
|
|
18
20
|
return () => {
|
|
19
21
|
created.destroy();
|
|
22
|
+
instance.current = null;
|
|
20
23
|
if (instanceRef) instanceRef.current = null;
|
|
21
24
|
};
|
|
22
25
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
23
26
|
}, [typeof target === 'string' ? target : null, typeof image === 'string' ? image : null, quantity, label]);
|
|
27
|
+
useIsomorphicLayoutEffect(() => { if (count !== undefined) instance.current?.setCount(count); }, [count]);
|
|
24
28
|
return (
|
|
25
29
|
<div {...props} ref={ref} className={['mk-add-to-cart', className].filter(Boolean).join(' ')}>
|
|
26
30
|
{children}
|
|
@@ -1,34 +1,49 @@
|
|
|
1
|
-
# chart
|
|
2
|
-
|
|
3
|
-
Desde 0.15 también puedes mezclar series con `type="composed"`. Cada serie declara `type: 'line' | 'bar' | 'area'`. Un área acepta `lowerValues` para rellenar el intervalo entre la frontera inferior y `values`; los huecos `null` interrumpen el relleno. La tabla y el tooltip muestran ambos límites.
|
|
4
|
-
|
|
5
|
-
```tsx
|
|
6
|
-
<Chart type="composed" labels={['Lun', 'Mar', 'Mié']} series={[
|
|
7
|
-
{ name: 'Ventas', type: 'bar', values: [20, 32, 28] },
|
|
8
|
-
{ name: 'Meta', type: 'line', values: [25, 30, 35] },
|
|
9
|
-
{ name: 'Rango', type: 'area', values: [24, 36, 32], lowerValues: [16, 26, 22] },
|
|
10
|
-
]} axis endLabel={false} />
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Gráfica SVG reutilizable de línea, área y barras (agrupadas o apiladas) sin motor canvas ni dependencias. Sigue las gráficas de métricas de Melon Mind: base en cero, línea de 2 px, área que se desvanece de .25 a 0, barras de hasta 24 px con extremo redondeado de 4 px y huecos de 2 px, rejilla fina y tooltip con superficie invertida.
|
|
14
|
-
|
|
15
|
-
```html
|
|
16
|
-
<mk-chart class="mk-chart" type="bar" stacked label="Sesiones por semana"
|
|
17
|
-
labels="S1,S2,S3,S4"
|
|
18
|
-
series='[{"name":"Ana","values":[4,6,5,7]},{"name":"Luis","values":[2,3,4,1]}]'></mk-chart>
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
const chart = createChart(root, { type: 'area', labels: days, series: [{ name: 'Ingresos', values }], formatValue: money, label: 'Ingresos de octubre' });
|
|
23
|
-
chart.update({ series: [{ name: 'Ingresos', values: next }] });
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
React: `<Chart type="line" labels={days} series={series} formatValue={money} label="Ingresos" onSelect={setDay} />`.
|
|
27
|
-
|
|
28
|
-
Datos: `labels` + `series: ChartSeries[]` (`{name, values: (number | null)[], color?, dash?}`; `dash` es un patrón SVG para líneas, p. ej. `'5 5'` para un ritmo o `'1 6'` para una proyección) o `points: ChartPoint[]` (`{label, value}`) para una serie. `null` es un hueco sin dato: la línea se corta y un punto aislado se muestra con marcador. Opciones: `type='line'|'area'|'bar'`, `stacked` (barras), `formatValue(n)` (ejes, tooltip y tabla), `label` (nombre accesible y título de la tabla), `height=240`, `emptyLabel`, `legend` (por defecto con dos o más series), `axis` (valores y líneas guía en el eje y; por defecto sólo la línea base), `endLabel` (líneas: el último valor de la primera serie en una píldora al final; por defecto `true`), `tooltip` (por defecto `true`; con `false` la gráfica deja la guía y los marcadores y la tarjeta la pone `chart-tooltip`), `onSelect(index | null)`. API: `update(options)` (combina y redibuja), `select(index | null)`, `selected`, `destroy()`. Evento `mk:select` con `{index, label, values, x, y, series}`: `x`/`y` son el punto señalado en píxeles del área de la gráfica y `series` trae `{name, color, value, previous}` por serie.
|
|
29
|
-
|
|
30
|
-
Puntero y toque eligen el punto más cercano (el toque mantiene la selección; el ratón la quita al salir). Con foco en la gráfica, flechas/Inicio/Fin recorren los valores y Escape los oculta; un estado educado anuncia el valor elegido. La gráfica tiene un resumen como nombre accesible y una tabla para lectores de pantalla con todos los valores (y el total en barras apiladas). Sin datos muestra `emptyLabel`.
|
|
31
|
-
|
|
32
|
-
Movimiento: el primer dibujo traza la línea de izquierda a derecha (barras: crecen desde la base) y cada `update` desliza los valores nuevos desde los anteriores; el tooltip aparece con un pop de cristal y se desliza entre puntos. Con movimiento reducido todo cambia sin transición.
|
|
33
|
-
|
|
34
|
-
Colores: una sola serie es monocroma (`--mk-chart-mono`, el color del texto, al estilo de los indicadores de Melon Mind); con varias, cada serie usa su `color` o la ranura `--mk-chart-N` en orden fijo (paleta comprobada para daltonismo, con pasos propios en oscuro); a partir de la novena serie todas comparten `--mk-chart-other`: agrúpalas en «Otros». Los textos usan los colores de texto del tema; el color identifica la marca. Se redimensiona con su contenedor (ResizeObserver) y `destroy()` quita todo lo creado. Variables: `--mk-chart-mono`, `--mk-chart-1…8`, `--mk-chart-other`, `--mk-chart-surface` (anillo de marcadores), `--mk-chart-grid`.
|
|
1
|
+
# chart
|
|
2
|
+
|
|
3
|
+
Desde 0.15 también puedes mezclar series con `type="composed"`. Cada serie declara `type: 'line' | 'bar' | 'area'`. Un área acepta `lowerValues` para rellenar el intervalo entre la frontera inferior y `values`; los huecos `null` interrumpen el relleno. La tabla y el tooltip muestran ambos límites.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
<Chart type="composed" labels={['Lun', 'Mar', 'Mié']} series={[
|
|
7
|
+
{ name: 'Ventas', type: 'bar', values: [20, 32, 28] },
|
|
8
|
+
{ name: 'Meta', type: 'line', values: [25, 30, 35] },
|
|
9
|
+
{ name: 'Rango', type: 'area', values: [24, 36, 32], lowerValues: [16, 26, 22] },
|
|
10
|
+
]} axis endLabel={false} />
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Gráfica SVG reutilizable de línea, área y barras (agrupadas o apiladas) sin motor canvas ni dependencias. Sigue las gráficas de métricas de Melon Mind: base en cero, línea de 2 px, área que se desvanece de .25 a 0, barras de hasta 24 px con extremo redondeado de 4 px y huecos de 2 px, rejilla fina y tooltip con superficie invertida.
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<mk-chart class="mk-chart" type="bar" stacked label="Sesiones por semana"
|
|
17
|
+
labels="S1,S2,S3,S4"
|
|
18
|
+
series='[{"name":"Ana","values":[4,6,5,7]},{"name":"Luis","values":[2,3,4,1]}]'></mk-chart>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const chart = createChart(root, { type: 'area', labels: days, series: [{ name: 'Ingresos', values }], formatValue: money, label: 'Ingresos de octubre' });
|
|
23
|
+
chart.update({ series: [{ name: 'Ingresos', values: next }] });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
React: `<Chart type="line" labels={days} series={series} formatValue={money} label="Ingresos" onSelect={setDay} />`.
|
|
27
|
+
|
|
28
|
+
Datos: `labels` + `series: ChartSeries[]` (`{name, values: (number | null)[], color?, dash?}`; `dash` es un patrón SVG para líneas, p. ej. `'5 5'` para un ritmo o `'1 6'` para una proyección) o `points: ChartPoint[]` (`{label, value}`) para una serie. `null` es un hueco sin dato: la línea se corta y un punto aislado se muestra con marcador. Opciones: `type='line'|'area'|'bar'`, `stacked` (barras), `formatValue(n)` (ejes, tooltip y tabla), `label` (nombre accesible y título de la tabla), `height=240`, `emptyLabel`, `legend` (por defecto con dos o más series), `axis` (valores y líneas guía en el eje y; por defecto sólo la línea base), `endLabel` (líneas: el último valor de la primera serie en una píldora al final; por defecto `true`), `tooltip` (por defecto `true`; con `false` la gráfica deja la guía y los marcadores y la tarjeta la pone `chart-tooltip`), `onSelect(index | null)`. API: `update(options)` (combina y redibuja), `select(index | null)`, `selected`, `destroy()`. Evento `mk:select` con `{index, label, values, x, y, series}`: `x`/`y` son el punto señalado en píxeles del área de la gráfica y `series` trae `{name, color, value, previous}` por serie.
|
|
29
|
+
|
|
30
|
+
Puntero y toque eligen el punto más cercano (el toque mantiene la selección; el ratón la quita al salir). Con foco en la gráfica, flechas/Inicio/Fin recorren los valores y Escape los oculta; un estado educado anuncia el valor elegido. La gráfica tiene un resumen como nombre accesible y una tabla para lectores de pantalla con todos los valores (y el total en barras apiladas). Sin datos muestra `emptyLabel`.
|
|
31
|
+
|
|
32
|
+
Movimiento: el primer dibujo traza la línea de izquierda a derecha (barras: crecen desde la base) y cada `update` desliza los valores nuevos desde los anteriores; el tooltip aparece con un pop de cristal y se desliza entre puntos. Con movimiento reducido todo cambia sin transición.
|
|
33
|
+
|
|
34
|
+
Colores: una sola serie es monocroma (`--mk-chart-mono`, el color del texto, al estilo de los indicadores de Melon Mind); con varias, cada serie usa su `color` o la ranura `--mk-chart-N` en orden fijo (paleta comprobada para daltonismo, con pasos propios en oscuro); a partir de la novena serie todas comparten `--mk-chart-other`: agrúpalas en «Otros». Los textos usan los colores de texto del tema; el color identifica la marca. Se redimensiona con su contenedor (ResizeObserver) y `destroy()` quita todo lo creado. Variables: `--mk-chart-mono`, `--mk-chart-1…8`, `--mk-chart-other`, `--mk-chart-surface` (anillo de marcadores), `--mk-chart-grid`.
|
|
35
|
+
|
|
36
|
+
## Variantes visuales · 0.16
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Chart type="bar" barStyle="pill" barTrack barFill="spotlight" barWidth={40}
|
|
40
|
+
labels={['Lun', 'Mar', 'Mié']} series={[{ name: 'Enfoque', values: [32, 56, 44] }]} />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- `barStyle`: `rounded` (compatibilidad) o `pill` (ambos extremos redondos). Las pilas comparten un recorte exterior por columna.
|
|
44
|
+
- `barTrack`: fondo de capacidad, false por defecto.
|
|
45
|
+
- `barFill`: `solid`, `gradient` o `spotlight` (selección con degradado sobre columnas rayadas). Sin selección, spotlight destaca la última columna.
|
|
46
|
+
- `barWidth`: ancho máximo, 24 px por defecto; se adapta al espacio disponible.
|
|
47
|
+
- `curve`: `linear` o `smooth`. La interpolación suave conserva los extremos reales y también funciona en áreas por rangos.
|
|
48
|
+
|
|
49
|
+
La selección de una píldora muestra un valor flotante. Pointer, tacto y teclado usan la misma selección. La entrada se escalona por columnas y los cambios de datos continúan desde los valores dibujados, también al interrumpir una transición.
|
|
@@ -15,6 +15,7 @@ mk-chart {
|
|
|
15
15
|
--mk-chart-other: var(--mk-muted);
|
|
16
16
|
--mk-chart-surface: var(--mk-surface-1);
|
|
17
17
|
--mk-chart-grid: color-mix(in srgb, var(--mk-text) 14%, transparent);
|
|
18
|
+
--mk-chart-track: color-mix(in srgb, var(--mk-text) 5%, transparent);
|
|
18
19
|
position: relative;
|
|
19
20
|
display: grid;
|
|
20
21
|
gap: 0.75rem;
|
|
@@ -120,6 +121,12 @@ mk-chart {
|
|
|
120
121
|
fill: color-mix(in srgb, var(--mk-text) 6%, transparent);
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
:is(.mk-chart, mk-chart) [data-mk-part='bar-track'] { fill: var(--mk-chart-track); }
|
|
125
|
+
:is(.mk-chart, mk-chart) [data-mk-part='bar'] { transition: opacity .22s ease, filter .22s ease; }
|
|
126
|
+
:is(.mk-chart, mk-chart) [data-mk-part='bar'][data-mk-active] { filter: brightness(1.12); }
|
|
127
|
+
:is(.mk-chart, mk-chart) [data-mk-part='bar-value'] rect { fill: var(--mk-text); }
|
|
128
|
+
:is(.mk-chart, mk-chart) [data-mk-part='bar-value'] text { fill: var(--mk-bg); font-size: 11px; font-weight: 600; }
|
|
129
|
+
|
|
123
130
|
:is(.mk-chart, mk-chart) [data-mk-part='series'] path[data-mk-index] {
|
|
124
131
|
transition: opacity 0.2s ease;
|
|
125
132
|
}
|
|
@@ -13,6 +13,7 @@ export class MkChartElement extends MkElement<ChartInstance> {
|
|
|
13
13
|
series: 'json',
|
|
14
14
|
points: 'json',
|
|
15
15
|
stacked: 'boolean',
|
|
16
|
+
barStyle: 'string', barTrack: 'boolean', barFill: 'string', barWidth: 'number', curve: 'string',
|
|
16
17
|
label: 'string',
|
|
17
18
|
height: 'number',
|
|
18
19
|
emptyLabel: 'string',
|
|
@@ -28,7 +29,7 @@ export class MkChartElement extends MkElement<ChartInstance> {
|
|
|
28
29
|
|
|
29
30
|
attributeChangedCallback(_name: string, previous: string | null, next: string | null) {
|
|
30
31
|
if (previous === next || !this.instance) return;
|
|
31
|
-
this.instance.update({ stacked: false, legend: undefined, ...(this.options as ChartOptions) });
|
|
32
|
+
this.instance.update({ stacked: false, barTrack: false, barStyle: undefined, barFill: undefined, barWidth: undefined, curve: undefined, legend: undefined, ...(this.options as ChartOptions) });
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
update(options: ChartOptions) {
|
|
@@ -47,6 +47,16 @@ export interface ChartOptions {
|
|
|
47
47
|
points?: ChartPoint[];
|
|
48
48
|
/** Bars only: stack the series. */
|
|
49
49
|
stacked?: boolean;
|
|
50
|
+
/** Rounded ends (default) or a full capsule, including stacked columns. */
|
|
51
|
+
barStyle?: 'rounded' | 'pill';
|
|
52
|
+
/** Show the available capacity behind each column. */
|
|
53
|
+
barTrack?: boolean;
|
|
54
|
+
/** Solid (default), gradient, or a gradient selection over muted striped columns. */
|
|
55
|
+
barFill?: 'solid' | 'gradient' | 'spotlight';
|
|
56
|
+
/** Maximum column width in px (default 24; pill demos use 40). */
|
|
57
|
+
barWidth?: number;
|
|
58
|
+
/** Smooth monotone curves preserve the data's extrema (default linear). */
|
|
59
|
+
curve?: 'linear' | 'smooth';
|
|
50
60
|
formatValue?: (value: number) => string;
|
|
51
61
|
/** Accessible name (and table caption). */
|
|
52
62
|
label?: string;
|
|
@@ -102,6 +112,25 @@ function barPath(x: number, width: number, base: number, end: number, rounded: b
|
|
|
102
112
|
return `M${round(x)},${round(base)}V${round(end + dir * r)}Q${round(x)},${round(end)} ${round(x + r)},${round(end)}H${round(x + width - r)}Q${round(x + width)},${round(end)} ${round(x + width)},${round(end + dir * r)}V${round(base)}Z`;
|
|
103
113
|
}
|
|
104
114
|
|
|
115
|
+
function pillPath(x: number, width: number, a: number, b: number) {
|
|
116
|
+
const top = Math.min(a, b), bottom = Math.max(a, b);
|
|
117
|
+
const r = Math.min(width / 2, (bottom - top) / 2);
|
|
118
|
+
return `M${round(x + r)},${round(top)}H${round(x + width - r)}Q${round(x + width)},${round(top)} ${round(x + width)},${round(top + r)}V${round(bottom - r)}Q${round(x + width)},${round(bottom)} ${round(x + width - r)},${round(bottom)}H${round(x + r)}Q${round(x)},${round(bottom)} ${round(x)},${round(bottom - r)}V${round(top + r)}Q${round(x)},${round(top)} ${round(x + r)},${round(top)}Z`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Cubic Hermite interpolation with bounded tangents: no invented peaks between samples. */
|
|
122
|
+
function linePath(points: number[][], smooth: boolean) {
|
|
123
|
+
if (!points.length) return '';
|
|
124
|
+
let path = `M${round(points[0][0])},${round(points[0][1])}`;
|
|
125
|
+
const slopes = points.slice(1).map((point, i) => (point[1] - points[i][1]) / (point[0] - points[i][0] || 1));
|
|
126
|
+
const tangents = points.map((_, i) => i === 0 ? slopes[0] : i === points.length - 1 ? slopes[i - 1] : slopes[i - 1] * slopes[i] <= 0 ? 0 : 2 * slopes[i - 1] * slopes[i] / (slopes[i - 1] + slopes[i]));
|
|
127
|
+
for (let i = 1; i < points.length; i++) {
|
|
128
|
+
const [x0, y0] = points[i - 1], [x, y] = points[i], dx = (x - x0) / 3;
|
|
129
|
+
path += smooth ? `C${round(x0 + dx)},${round(y0 + tangents[i - 1] * dx)} ${round(x - dx)},${round(y - tangents[i] * dx)} ${round(x)},${round(y)}` : `L${round(x)},${round(y)}`;
|
|
130
|
+
}
|
|
131
|
+
return path;
|
|
132
|
+
}
|
|
133
|
+
|
|
105
134
|
interface Model {
|
|
106
135
|
labels: string[];
|
|
107
136
|
series: Array<ChartSeries & { color: string }>;
|
|
@@ -357,6 +386,7 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
357
386
|
const slot = plotW / n;
|
|
358
387
|
const xs = model.labels.map((_, i) => (bar ? left + slot * (i + 0.5) : n === 1 ? left + plotW / 2 : left + (plotW * i) / (n - 1)));
|
|
359
388
|
geometry = { width, height, top, bottom: top + plotH, left, right: width - right, xs, y, base };
|
|
389
|
+
shown = { values, lower, lo, hi, type: type(), stacked: stacked() };
|
|
360
390
|
|
|
361
391
|
// Baseline (and, with `axis`, hairlines with their values).
|
|
362
392
|
const grid = svg('g', { 'data-mk-part': 'grid' });
|
|
@@ -401,10 +431,46 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
401
431
|
if (bar) {
|
|
402
432
|
const barIndices = model.series.flatMap((_, index) => seriesType(index) === 'bar' ? [index] : []);
|
|
403
433
|
const groups = stacked() ? 1 : barIndices.length;
|
|
404
|
-
const
|
|
434
|
+
const maxWidth = finite(options.barWidth) ? Math.max(2, Math.min(96, options.barWidth)) : BAR_MAX;
|
|
435
|
+
const barWidth = Math.max(2, Math.min(maxWidth, (slot * 0.62 - GAP * (groups - 1)) / groups));
|
|
436
|
+
const pill = options.barStyle === 'pill';
|
|
437
|
+
const trackLayer = svg('g', { 'data-mk-part': 'bar-tracks' });
|
|
438
|
+
canvas.append(trackLayer);
|
|
439
|
+
if (options.barFill && options.barFill !== 'solid') {
|
|
440
|
+
model.series.forEach((series, k) => {
|
|
441
|
+
const gradient = svg('linearGradient', { id: `${uid}-bar-${k}`, x1: 0, y1: 0, x2: 0, y2: 1 });
|
|
442
|
+
for (const [offset, opacity] of [['0', '1'], ['1', '0.4']]) {
|
|
443
|
+
const stop = svg('stop', { offset }); stop.style.stopColor = series.color; stop.style.stopOpacity = opacity; gradient.append(stop);
|
|
444
|
+
}
|
|
445
|
+
defs.append(gradient);
|
|
446
|
+
});
|
|
447
|
+
const hatch = svg('pattern', { id: `${uid}-hatch`, patternUnits: 'userSpaceOnUse', width: 6, height: 6, patternTransform: 'rotate(35)' });
|
|
448
|
+
const ground = svg('rect', { width: 6, height: 6 }); ground.style.fill = 'var(--mk-chart-track)';
|
|
449
|
+
const stripe = svg('line', { x1: 0, x2: 0, y1: 0, y2: 6 }); stripe.style.stroke = 'var(--mk-chart-grid)'; stripe.style.strokeWidth = '2';
|
|
450
|
+
hatch.append(ground, stripe); defs.append(hatch);
|
|
451
|
+
}
|
|
452
|
+
const fillBar = (path: SVGPathElement, k: number, index: number) => {
|
|
453
|
+
const fill = options.barFill && options.barFill !== 'solid' ? `url(#${uid}-bar-${k})` : model.series[k]!.color;
|
|
454
|
+
path.style.setProperty('--mk-bar-fill', fill);
|
|
455
|
+
path.style.fill = options.barFill === 'spotlight' && index !== (selected ?? n - 1) ? `url(#${uid}-hatch)` : fill;
|
|
456
|
+
};
|
|
457
|
+
const addTrack = (x: number) => {
|
|
458
|
+
if (!options.barTrack) return;
|
|
459
|
+
const path = svg('path', { d: pillPath(x, barWidth, top, base), 'data-mk-part': 'bar-track' });
|
|
460
|
+
trackLayer.append(path);
|
|
461
|
+
};
|
|
405
462
|
const totalsLayer = svg('g', { 'data-mk-part': 'totals' });
|
|
406
463
|
model.labels.forEach((_, i) => {
|
|
407
464
|
if (stacked()) {
|
|
465
|
+
const clipId = `${uid}-stack-${i}`;
|
|
466
|
+
if (pill) {
|
|
467
|
+
const sum = totalsOf(values, i);
|
|
468
|
+
const clip = svg('clipPath', { id: clipId });
|
|
469
|
+
if (sum.up) clip.append(svg('path', { d: pillPath(xs[i]! - barWidth / 2, barWidth, base, y(sum.up)) }));
|
|
470
|
+
if (sum.down) clip.append(svg('path', { d: pillPath(xs[i]! - barWidth / 2, barWidth, base, y(sum.down)) }));
|
|
471
|
+
defs.append(clip);
|
|
472
|
+
}
|
|
473
|
+
addTrack(xs[i]! - barWidth / 2);
|
|
408
474
|
let up = 0;
|
|
409
475
|
let down = 0;
|
|
410
476
|
const outer = { up: -1, down: -1 };
|
|
@@ -424,8 +490,9 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
424
490
|
const start = y(from) + (from !== 0 ? (value > 0 ? -GAP : GAP) : 0);
|
|
425
491
|
const end = y(to);
|
|
426
492
|
if ((value > 0 && end >= start) || (value < 0 && end <= start)) return;
|
|
427
|
-
const path = svg('path', { d: barPath(xs[i]! - barWidth / 2, barWidth, start, end, k === (value > 0 ? outer.up : outer.down)), 'data-mk-index': i, 'data-mk-series': k });
|
|
428
|
-
path.
|
|
493
|
+
const path = svg('path', { d: barPath(xs[i]! - barWidth / 2, barWidth, start, end, !pill && k === (value > 0 ? outer.up : outer.down)), 'data-mk-part': 'bar', 'data-mk-index': i, 'data-mk-series': k });
|
|
494
|
+
if (pill) path.setAttribute('clip-path', `url(#${clipId})`);
|
|
495
|
+
fillBar(path, k, i);
|
|
429
496
|
marks.append(path);
|
|
430
497
|
});
|
|
431
498
|
// The stack total above it, when the columns have room.
|
|
@@ -440,10 +507,11 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
440
507
|
values.forEach((list, k) => {
|
|
441
508
|
if (seriesType(k) !== 'bar') return;
|
|
442
509
|
const value = list[i];
|
|
443
|
-
if (!finite(value) || value === 0) return;
|
|
444
510
|
const x = xs[i]! - groupWidth / 2 + barIndices.indexOf(k) * (barWidth + GAP);
|
|
445
|
-
|
|
446
|
-
|
|
511
|
+
addTrack(x);
|
|
512
|
+
if (!finite(value) || value === 0) return;
|
|
513
|
+
const path = svg('path', { d: pill ? pillPath(x, barWidth, base, y(value)) : barPath(x, barWidth, base, y(value), true), 'data-mk-part': 'bar', 'data-mk-index': i, 'data-mk-series': k });
|
|
514
|
+
fillBar(path, k, i);
|
|
447
515
|
marks.append(path);
|
|
448
516
|
});
|
|
449
517
|
}
|
|
@@ -477,7 +545,9 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
477
545
|
defs.append(gradient);
|
|
478
546
|
for (const points of runs) {
|
|
479
547
|
if (points.length < 2) continue;
|
|
480
|
-
const
|
|
548
|
+
const upper = linePath(points, options.curve === 'smooth');
|
|
549
|
+
const bottom = linePath([...points].reverse().map(([px, , py]) => [px, py]), options.curve === 'smooth');
|
|
550
|
+
const d = `${upper}${bottom.replace(/^M/, 'L')}Z`;
|
|
481
551
|
const area = svg('path', { d, 'data-mk-part': 'area', 'data-mk-series': k });
|
|
482
552
|
area.style.fill = `url(#${uid}-fill-${k})`;
|
|
483
553
|
marks.append(area);
|
|
@@ -491,7 +561,7 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
491
561
|
marks.append(dot);
|
|
492
562
|
continue;
|
|
493
563
|
}
|
|
494
|
-
const line = svg('path', { d:
|
|
564
|
+
const line = svg('path', { d: linePath(points, options.curve === 'smooth'), 'data-mk-part': 'line' });
|
|
495
565
|
line.style.stroke = series.color;
|
|
496
566
|
// Dotted patterns (a first dash of 1 or less) draw round dots; dashes stay thin.
|
|
497
567
|
const dotted = Boolean(series.dash) && Number(series.dash!.trim().split(/[\s,]+/)[0]) <= 1;
|
|
@@ -531,6 +601,11 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
531
601
|
cursor.replaceChildren();
|
|
532
602
|
if (band) band.style.display = 'none';
|
|
533
603
|
for (const mark of canvas.querySelectorAll('[data-mk-index]')) mark.removeAttribute('data-mk-dim');
|
|
604
|
+
for (const mark of canvas.querySelectorAll<SVGPathElement>('[data-mk-part="bar"]')) {
|
|
605
|
+
const index = Number(mark.dataset.mkIndex);
|
|
606
|
+
mark.toggleAttribute('data-mk-active', index === selected);
|
|
607
|
+
if (options.barFill === 'spotlight') mark.style.fill = index === (selected ?? model.labels.length - 1) ? mark.style.getPropertyValue('--mk-bar-fill') : `url(#${uid}-hatch)`;
|
|
608
|
+
}
|
|
534
609
|
if (selected === null || !hasData()) {
|
|
535
610
|
if (!tooltip.hidden && !reduced()) {
|
|
536
611
|
gsap.killTweensOf(tooltip, 'opacity,scale');
|
|
@@ -555,6 +630,20 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
555
630
|
for (const mark of canvas.querySelectorAll<SVGElement>('[data-mk-index]')) if (mark.getAttribute('data-mk-index') !== String(i)) mark.setAttribute('data-mk-dim', '');
|
|
556
631
|
const { up, down } = totals(i);
|
|
557
632
|
anchorY = stacked() ? geometry.y(up || down) : Math.min(...model.series.map((series) => (finite(series.values[i]) ? geometry.y(series.values[i]!) : geometry.bottom)));
|
|
633
|
+
if (options.barStyle === 'pill') {
|
|
634
|
+
const amount = stacked() ? up + down : model.series[0]?.values[i];
|
|
635
|
+
if (finite(amount)) {
|
|
636
|
+
const label = format(amount), width = Math.max(40, label.length * 7 + 18);
|
|
637
|
+
const bx = Math.max(0, Math.min(geometry.width - width, x - width / 2));
|
|
638
|
+
const by = Math.max(0, anchorY - 32);
|
|
639
|
+
const group = svg('g', { 'data-mk-part': 'bar-value' });
|
|
640
|
+
group.append(svg('rect', { x: round(bx), y: round(by), width, height: 24, rx: 12 }));
|
|
641
|
+
const text = svg('text', { x: round(bx + width / 2), y: round(by + 12), 'text-anchor': 'middle', 'dominant-baseline': 'middle' });
|
|
642
|
+
text.textContent = label; group.append(text); cursor.append(group);
|
|
643
|
+
const marker = svg('circle', { cx: round(x), cy: round(anchorY), r: 4, 'data-mk-part': 'marker' }); marker.style.fill = model.series[0]?.color ?? 'var(--mk-text)'; cursor.append(marker);
|
|
644
|
+
if (fresh && !reduced()) keep(gsap.fromTo(group, { opacity: 0, y: 6 }, { opacity: 1, y: 0, duration: 0.3, ease: EASE.pop }));
|
|
645
|
+
}
|
|
646
|
+
}
|
|
558
647
|
} else {
|
|
559
648
|
cursor.append(svg('line', { x1: round(x), x2: round(x), y1: geometry.top, y2: geometry.bottom, 'data-mk-part': 'guide' }));
|
|
560
649
|
model.series.forEach((series) => {
|
|
@@ -644,6 +733,7 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
644
733
|
glide?.kill();
|
|
645
734
|
canvas.setAttribute('aria-label', describe());
|
|
646
735
|
scope.attr(root, 'data-mk-chart-type', type());
|
|
736
|
+
scope.attr(root, 'data-mk-bar-style', options.barStyle ?? 'rounded');
|
|
647
737
|
renderTable();
|
|
648
738
|
renderLegend();
|
|
649
739
|
const ok = hasData();
|
|
@@ -700,12 +790,14 @@ export function createChart(root: HTMLElement | null, initial: ChartOptions = {}
|
|
|
700
790
|
// First appearance: bars grow from the baseline, lines wipe in from the left.
|
|
701
791
|
finish();
|
|
702
792
|
if (type() === 'bar') {
|
|
703
|
-
const
|
|
793
|
+
const stagger = Math.min(0.045, 0.22 / Math.max(1, model.labels.length - 1));
|
|
794
|
+
const length = 0.7 + stagger * (model.labels.length - 1);
|
|
795
|
+
const state = { t: 0 }, ease = gsap.parseEase(EASE.swatch);
|
|
704
796
|
glide = gsap.to(state, {
|
|
705
|
-
t:
|
|
706
|
-
duration:
|
|
707
|
-
ease:
|
|
708
|
-
onUpdate: () => paint(target.map((list) => list.map((value) => (finite(value) ? value * state.t : value))), domain.lo, domain.hi, domain.step),
|
|
797
|
+
t: length,
|
|
798
|
+
duration: length,
|
|
799
|
+
ease: 'none',
|
|
800
|
+
onUpdate: () => paint(target.map((list) => list.map((value, i) => (finite(value) ? value * Math.max(0, ease(Math.min(1, Math.max(0, (state.t - i * stagger) / 0.7)))) : value))), domain.lo, domain.hi, domain.step),
|
|
709
801
|
onComplete: () => {
|
|
710
802
|
finish();
|
|
711
803
|
settle();
|
|
@@ -11,13 +11,13 @@ export interface ChartProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSele
|
|
|
11
11
|
* <Chart type="bar" stacked labels={weeks} series={[{ name: 'Ana', values }]} formatValue={money} label="Sesiones por semana" />.
|
|
12
12
|
* Data changes redraw in place; the selection survives when its point still exists.
|
|
13
13
|
*/
|
|
14
|
-
export function Chart({ type, labels, series, points, stacked, formatValue, label, height, emptyLabel, legend, tooltip, axis, endLabel, onSelect, instanceRef, className, ...props }: ChartProps) {
|
|
14
|
+
export function Chart({ type, labels, series, points, stacked, barStyle, barTrack, barFill, barWidth, curve, formatValue, label, height, emptyLabel, legend, tooltip, axis, endLabel, onSelect, instanceRef, className, ...props }: ChartProps) {
|
|
15
15
|
const ref = useRef<HTMLDivElement>(null);
|
|
16
16
|
const instance = useRef<ChartInstance | null>(null);
|
|
17
17
|
const format = useLatest(formatValue);
|
|
18
18
|
const select = useLatest(onSelect);
|
|
19
19
|
const formatted = formatValue !== undefined;
|
|
20
|
-
const data = { type, labels, series, points, stacked, label, height, emptyLabel, legend, tooltip, axis, endLabel };
|
|
20
|
+
const data = { type, labels, series, points, stacked, barStyle, barTrack, barFill, barWidth, curve, label, height, emptyLabel, legend, tooltip, axis, endLabel };
|
|
21
21
|
const key = JSON.stringify(data);
|
|
22
22
|
const latest = useLatest(data);
|
|
23
23
|
const options = (): ChartOptions => ({
|
|
@@ -46,3 +46,13 @@ Los nombres camelCase se escriben como atributos kebab-case. Los arrays y objeto
|
|
|
46
46
|
Variables: --mk-chart-1…8, --mk-chart-surface.
|
|
47
47
|
|
|
48
48
|
Respeta los colores del tema, foco visible y `prefers-reduced-motion`. Los gráficos incluyen una tabla accesible y selección con flechas, Home, End y Escape. Heatmap usa arriba/abajo para un día e izquierda/derecha para una semana. Toolbar usa flechas y Home/End; OrbitMenu cierra con Escape y devuelve el foco. Los controles conservan nombres accesibles; VoiceDots anuncia los estados sin leer cada fotograma.
|
|
49
|
+
|
|
50
|
+
## Medidor segmentado · 0.16
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<RadialChart sweep={180} segments={18} thickness={30} center="percent"
|
|
54
|
+
totalLabel="Crecimiento" legend={false}
|
|
55
|
+
data={[{ label: 'Ventas', value: 70.8, max: 100 }]} />
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`segments` divide cada anillo en sectores (0 conserva el trazo continuo). `center="percent"` muestra el avance hacia la meta; por defecto muestra el valor. En HTML se usan los mismos atributos. Los datos se interpolan sobre los segmentos y conservan los valores exactos en la tabla accesible.
|
|
@@ -7,7 +7,7 @@ import { createRadialChart, type RadialChartInstance, type RadialChartOptions }
|
|
|
7
7
|
* sweep="270" draws a gauge. Attribute changes glide in place. Emits mk:select ({index, label, value}).
|
|
8
8
|
*/
|
|
9
9
|
export class MkRadialChartElement extends MkElement<RadialChartInstance> {
|
|
10
|
-
static options: Record<string, OptionType> = { data: 'json', max: 'number', sweep: 'number', size: 'number', thickness: 'number', label: 'string', totalLabel: 'string', legend: 'boolean', emptyLabel: 'string' };
|
|
10
|
+
static options: Record<string, OptionType> = { data: 'json', max: 'number', sweep: 'number', size: 'number', thickness: 'number', segments: 'number', center: 'string', label: 'string', totalLabel: 'string', legend: 'boolean', emptyLabel: 'string' };
|
|
11
11
|
|
|
12
12
|
protected create(options: Record<string, unknown>) {
|
|
13
13
|
return createRadialChart(this, options as RadialChartOptions);
|
|
@@ -15,7 +15,7 @@ export class MkRadialChartElement extends MkElement<RadialChartInstance> {
|
|
|
15
15
|
|
|
16
16
|
attributeChangedCallback(_name: string, previous: string | null, next: string | null) {
|
|
17
17
|
if (previous === next || !this.instance) return;
|
|
18
|
-
this.instance.update({ legend: undefined, max: undefined, ...(this.options as RadialChartOptions) });
|
|
18
|
+
this.instance.update({ legend: undefined, max: undefined, segments: 0, center: undefined, ...(this.options as RadialChartOptions) });
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
update(options: RadialChartOptions) {
|