@rokkit/chart 1.0.0-next.133 → 1.0.0-next.135
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 +121 -111
- package/package.json +9 -4
- package/src/Texture.svelte +9 -1
- package/src/elements/Label.svelte +1 -8
- package/src/elements/SymbolGrid.svelte +1 -5
- package/src/patterns/README.md +3 -0
- package/src/symbols/RoundedSquare.svelte +12 -1
- package/src/symbols/Shape.svelte +14 -1
- package/src/template/shapes/Circles.svelte +7 -5
- package/src/template/shapes/Lines.svelte +8 -6
- package/src/template/shapes/Polygons.svelte +7 -1
package/README.md
CHANGED
|
@@ -1,149 +1,159 @@
|
|
|
1
1
|
# @rokkit/chart
|
|
2
2
|
|
|
3
|
-
Data-driven chart components for Svelte inspired by [dc.js](https://dc-js.github.io/dc.js/
|
|
3
|
+
Data-driven D3 chart components for Svelte 5, inspired by the composable approach of [dc.js](https://dc-js.github.io/dc.js/).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
bun add @rokkit/chart
|
|
9
|
+
# or
|
|
10
|
+
npm install @rokkit/chart
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
`@rokkit/chart` provides composable SVG chart components built on D3. All components are placed inside `Plot.Root`, which manages shared state (scales, dimensions, color mapping) via Svelte context. Child components read from that context — you do not wire them together manually.
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
## Usage
|
|
14
18
|
|
|
15
|
-
### Basic
|
|
19
|
+
### Basic bar chart
|
|
16
20
|
|
|
17
21
|
```svelte
|
|
18
22
|
<script>
|
|
19
23
|
import { Plot } from '@rokkit/chart'
|
|
20
|
-
import { dataset } from '@rokkit/data'
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{
|
|
25
|
-
{
|
|
26
|
-
{ model: 'Model C', name: 'Product 3', category: 'Electronics', count: 62 }
|
|
27
|
-
// More data...
|
|
25
|
+
const data = [
|
|
26
|
+
{ month: 'Jan', sales: 120, returns: 30 },
|
|
27
|
+
{ month: 'Feb', sales: 150, returns: 20 },
|
|
28
|
+
{ month: 'Mar', sales: 90, returns: 40 }
|
|
28
29
|
]
|
|
29
|
-
|
|
30
|
-
// Use the dataset class to process the data
|
|
31
|
-
let data = dataset(sampleData)
|
|
32
|
-
.groupBy('model')
|
|
33
|
-
.summarize('name', { count: (values) => values.length })
|
|
34
|
-
.rollup()
|
|
35
30
|
</script>
|
|
36
31
|
|
|
37
|
-
<Plot.Root {data} width={600} height={400}
|
|
38
|
-
<Plot.Grid
|
|
39
|
-
<Plot.Axis type="x" field="
|
|
40
|
-
<Plot.Axis type="y" field="
|
|
41
|
-
<Plot.Bar x="
|
|
42
|
-
<Plot.Legend
|
|
32
|
+
<Plot.Root {data} width={600} height={400} fill="month">
|
|
33
|
+
<Plot.Grid />
|
|
34
|
+
<Plot.Axis type="x" field="month" label="Month" />
|
|
35
|
+
<Plot.Axis type="y" field="sales" label="Sales" />
|
|
36
|
+
<Plot.Bar x="month" y="sales" />
|
|
37
|
+
<Plot.Legend />
|
|
43
38
|
</Plot.Root>
|
|
44
39
|
```
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### Plot.Root
|
|
49
|
-
|
|
50
|
-
The container component for all charts.
|
|
51
|
-
|
|
52
|
-
**Props:**
|
|
53
|
-
|
|
54
|
-
- `data` - The dataset to visualize (array or dataset object)
|
|
55
|
-
- `width` - Width of the chart in pixels (default: 600)
|
|
56
|
-
- `height` - Height of the chart in pixels (default: 400)
|
|
57
|
-
- `margin` - Object with top, right, bottom, left margins (default: `{ top: 20, right: 30, bottom: 40, left: 50 }`)
|
|
58
|
-
- `fill` - Field to use for color mapping (optional)
|
|
59
|
-
- `responsive` - Whether to make the chart responsive (default: true)
|
|
60
|
-
- `animationDuration` - Duration of animations in milliseconds (default: 300)
|
|
61
|
-
|
|
62
|
-
### Plot.Axis
|
|
63
|
-
|
|
64
|
-
Renders an axis for the chart.
|
|
65
|
-
|
|
66
|
-
**Props:**
|
|
67
|
-
|
|
68
|
-
- `type` - Type of axis ('x' or 'y')
|
|
69
|
-
- `field` - Data field to use for this axis
|
|
70
|
-
- `label` - Axis label text
|
|
71
|
-
- `ticks` - Number of ticks to display (optional)
|
|
72
|
-
- `tickFormat` - Function to format tick labels (optional)
|
|
73
|
-
- `grid` - Whether to show grid lines (default: false)
|
|
74
|
-
|
|
75
|
-
### Plot.Bar
|
|
76
|
-
|
|
77
|
-
Renders a bar chart.
|
|
78
|
-
|
|
79
|
-
**Props:**
|
|
80
|
-
|
|
81
|
-
- `x` - Field to use for x-axis values
|
|
82
|
-
- `y` - Field to use for y-axis values
|
|
83
|
-
- `fill` - Field to use for coloring the bars (optional)
|
|
84
|
-
- `color` - Fixed color for bars if fill is not provided (default: "#4682b4")
|
|
85
|
-
- `opacity` - Opacity of the bars (default: 1)
|
|
86
|
-
- `animationDuration` - Duration of animations in milliseconds (default: 300)
|
|
87
|
-
- `onClick` - Callback for click events on bars (optional)
|
|
88
|
-
|
|
89
|
-
### Plot.Grid
|
|
90
|
-
|
|
91
|
-
Renders grid lines for the chart.
|
|
92
|
-
|
|
93
|
-
**Props:**
|
|
94
|
-
|
|
95
|
-
- `direction` - Direction of grid lines ('x', 'y', or 'both') (default: 'both')
|
|
96
|
-
- `xTicks` - Number of ticks for x-axis grid (optional)
|
|
97
|
-
- `yTicks` - Number of ticks for y-axis grid (optional)
|
|
98
|
-
- `color` - Color of grid lines (default: 'currentColor')
|
|
99
|
-
- `opacity` - Opacity of grid lines (default: 0.1)
|
|
100
|
-
- `lineStyle` - Line style for grid lines ('solid', 'dashed', 'dotted') (default: 'solid')
|
|
101
|
-
|
|
102
|
-
### Plot.Legend
|
|
103
|
-
|
|
104
|
-
Renders a legend for the chart.
|
|
105
|
-
|
|
106
|
-
**Props:**
|
|
107
|
-
|
|
108
|
-
- `title` - Title for the legend (optional)
|
|
109
|
-
- `align` - Alignment of the legend ('left', 'right', 'center') (default: 'right')
|
|
110
|
-
- `verticalAlign` - Vertical position of the legend ('top', 'bottom') (default: 'top')
|
|
111
|
-
- `shape` - Shape for legend items ('circle', 'rect') (default: 'rect')
|
|
112
|
-
- `markerSize` - Size of the legend markers (default: 10)
|
|
113
|
-
- `onClick` - Callback when a legend item is clicked (optional)
|
|
114
|
-
|
|
115
|
-
## Using with Rokkit Dataset Class
|
|
116
|
-
|
|
117
|
-
The chart components work seamlessly with the `@rokkit/data` package, allowing for powerful data transformations:
|
|
41
|
+
### Using `@rokkit/data` for preprocessing
|
|
118
42
|
|
|
119
43
|
```svelte
|
|
120
44
|
<script>
|
|
121
45
|
import { Plot } from '@rokkit/chart'
|
|
122
46
|
import { dataset } from '@rokkit/data'
|
|
123
47
|
|
|
124
|
-
|
|
125
|
-
|
|
48
|
+
const raw = [
|
|
49
|
+
{ category: 'Electronics', name: 'A', revenue: 450 },
|
|
50
|
+
{ category: 'Clothing', name: 'B', revenue: 320 },
|
|
51
|
+
{ category: 'Electronics', name: 'C', revenue: 620 }
|
|
126
52
|
]
|
|
127
53
|
|
|
128
|
-
|
|
54
|
+
const data = dataset(raw)
|
|
129
55
|
.groupBy('category')
|
|
130
|
-
.summarize('name', {
|
|
131
|
-
count: (values) => values.length,
|
|
132
|
-
total: (values) => values.reduce((a, b) => a + b, 0)
|
|
133
|
-
})
|
|
56
|
+
.summarize('name', { total: (vals) => vals.reduce((s, v) => s + v.revenue, 0) })
|
|
134
57
|
.rollup()
|
|
135
58
|
</script>
|
|
136
59
|
|
|
137
|
-
<Plot.Root data
|
|
60
|
+
<Plot.Root {data} fill="category" width={500} height={350}>
|
|
138
61
|
<Plot.Axis type="x" field="category" />
|
|
139
|
-
<Plot.Axis type="y" field="
|
|
140
|
-
<Plot.Bar x="category" y="
|
|
62
|
+
<Plot.Axis type="y" field="total" />
|
|
63
|
+
<Plot.Bar x="category" y="total" />
|
|
64
|
+
<Plot.Legend />
|
|
141
65
|
</Plot.Root>
|
|
142
66
|
```
|
|
143
67
|
|
|
144
|
-
|
|
68
|
+
### Using `ChartBrewer` for advanced control
|
|
69
|
+
|
|
70
|
+
`ChartBrewer` is the reactive state manager that `Plot.Root` uses internally. Use it directly when you need programmatic access to scales, axes, or legend state outside of the component tree.
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
import { ChartBrewer, createScales, createBars } from '@rokkit/chart'
|
|
74
|
+
|
|
75
|
+
const brewer = new ChartBrewer({
|
|
76
|
+
width: 600,
|
|
77
|
+
height: 400,
|
|
78
|
+
margin: { top: 20, right: 30, bottom: 40, left: 50 },
|
|
79
|
+
padding: 0.2,
|
|
80
|
+
animationDuration: 300
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
brewer.setData(data)
|
|
84
|
+
brewer.setFields({ x: 'month', y: 'sales', color: 'month' })
|
|
85
|
+
brewer.createScales()
|
|
86
|
+
|
|
87
|
+
const scales = brewer.getScales()
|
|
88
|
+
const dimensions = brewer.getDimensions()
|
|
89
|
+
```
|
|
145
90
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
91
|
+
## API
|
|
92
|
+
|
|
93
|
+
### Components (`Plot` namespace)
|
|
94
|
+
|
|
95
|
+
| Component | Description |
|
|
96
|
+
| ------------- | --------------------------------------------------------- |
|
|
97
|
+
| `Plot.Root` | Chart container. Manages dimensions, scales, and context. |
|
|
98
|
+
| `Plot.Bar` | Bar series. Reads x/y fields and renders SVG rects. |
|
|
99
|
+
| `Plot.Axis` | X or Y axis with optional label and tick formatting. |
|
|
100
|
+
| `Plot.Grid` | Background grid lines derived from axis scales. |
|
|
101
|
+
| `Plot.Legend` | Color legend; clicking items filters the visible series. |
|
|
102
|
+
|
|
103
|
+
### `Plot.Root` props
|
|
104
|
+
|
|
105
|
+
| Prop | Type | Default | Description |
|
|
106
|
+
| ------------------- | ------------------ | ------------------------------------- | --------------------------------------------------------------------- |
|
|
107
|
+
| `data` | `array \| dataset` | `[]` | Chart data. Accepts a plain array or a `@rokkit/data` dataset object. |
|
|
108
|
+
| `width` | `number` | `600` | SVG width in pixels. |
|
|
109
|
+
| `height` | `number` | `400` | SVG height in pixels. |
|
|
110
|
+
| `margin` | `object` | `{top:20,right:30,bottom:40,left:50}` | Chart margins. |
|
|
111
|
+
| `fill` | `string` | `null` | Field name used for color mapping. |
|
|
112
|
+
| `responsive` | `boolean` | `true` | Resize with the container. |
|
|
113
|
+
| `animationDuration` | `number` | `300` | Transition duration in ms. |
|
|
114
|
+
|
|
115
|
+
### `Plot.Bar` props
|
|
116
|
+
|
|
117
|
+
| Prop | Type | Default | Description |
|
|
118
|
+
| ------------------- | ---------- | ----------- | --------------------------------------------- |
|
|
119
|
+
| `x` | `string` | — | Field for x-axis values. |
|
|
120
|
+
| `y` | `string` | — | Field for y-axis values. |
|
|
121
|
+
| `fill` | `string` | — | Field for color mapping (overrides root). |
|
|
122
|
+
| `color` | `string` | `'#4682b4'` | Fallback bar color when no fill field is set. |
|
|
123
|
+
| `opacity` | `number` | `1` | Bar opacity. |
|
|
124
|
+
| `animationDuration` | `number` | `300` | Per-bar transition duration in ms. |
|
|
125
|
+
| `onClick` | `function` | `null` | Click handler; receives the data row. |
|
|
126
|
+
|
|
127
|
+
### `Plot.Axis` props
|
|
128
|
+
|
|
129
|
+
| Prop | Type | Default | Description |
|
|
130
|
+
| ------------ | ------------ | ------- | --------------------------------- |
|
|
131
|
+
| `type` | `'x' \| 'y'` | `'x'` | Axis orientation. |
|
|
132
|
+
| `field` | `string` | — | Data field this axis represents. |
|
|
133
|
+
| `label` | `string` | `''` | Axis label. |
|
|
134
|
+
| `ticks` | `number` | — | Suggested tick count. |
|
|
135
|
+
| `tickFormat` | `function` | — | D3 tick formatter. |
|
|
136
|
+
| `grid` | `boolean` | `false` | Render grid lines from this axis. |
|
|
137
|
+
|
|
138
|
+
### Utility functions
|
|
139
|
+
|
|
140
|
+
| Export | Description |
|
|
141
|
+
| ----------------------------------------- | ------------------------------------------- |
|
|
142
|
+
| `createDimensions(width, height, margin)` | Compute chart area dimensions with margins |
|
|
143
|
+
| `createScales(data, fields, dimensions)` | Generate D3 band/linear scales |
|
|
144
|
+
| `createBars(data, scales, fields)` | Compute bar x/y/width/height attributes |
|
|
145
|
+
| `createGroupedBars(data, scales, fields)` | Compute grouped bar layout |
|
|
146
|
+
| `createLegend(data, colorScale)` | Build legend item array |
|
|
147
|
+
| `filterByLegend(data, activeItems)` | Filter data rows by active legend selection |
|
|
148
|
+
| `createXAxis(scale, options)` | Build D3 x-axis descriptor |
|
|
149
|
+
| `createYAxis(scale, options)` | Build D3 y-axis descriptor |
|
|
150
|
+
| `createGrid(scales, dimensions)` | Build grid line descriptors |
|
|
151
|
+
|
|
152
|
+
## Dependencies
|
|
153
|
+
|
|
154
|
+
- `d3-scale`, `d3-axis`, `d3-format`, `d3-selection`, `d3-array`, `d3-transition`, `d3-scale-chromatic`
|
|
155
|
+
- `@rokkit/core`, `@rokkit/data`, `@rokkit/states`
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
Part of [Rokkit](https://github.com/jerrythomas/rokkit) — a Svelte 5 component library and design system.
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokkit/chart",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.135",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Data-driven chart components",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/jerrythomas/rokkit.git"
|
|
9
|
+
},
|
|
6
10
|
"author": "Jerry Thomas <me@jerrythomas.name>",
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"npm": {
|
|
@@ -13,6 +17,7 @@
|
|
|
13
17
|
},
|
|
14
18
|
"scripts": {
|
|
15
19
|
"prepublishOnly": "cp ../../LICENSE . && bun clean && bun tsc --project tsconfig.build.json",
|
|
20
|
+
"postpublish": "rm -f LICENSE",
|
|
16
21
|
"clean": "rm -rf dist",
|
|
17
22
|
"build": "bun prepublishOnly"
|
|
18
23
|
},
|
|
@@ -33,9 +38,9 @@
|
|
|
33
38
|
}
|
|
34
39
|
},
|
|
35
40
|
"dependencies": {
|
|
36
|
-
"@rokkit/core": "latest",
|
|
37
|
-
"@rokkit/data": "latest",
|
|
38
|
-
"@rokkit/states": "latest",
|
|
41
|
+
"@rokkit/core": "workspace:latest",
|
|
42
|
+
"@rokkit/data": "workspace:latest",
|
|
43
|
+
"@rokkit/states": "workspace:latest",
|
|
39
44
|
"d3-array": "^3.2.4",
|
|
40
45
|
"d3-format": "^3.1.2",
|
|
41
46
|
"d3-axis": "^3.0.0",
|
package/src/Texture.svelte
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
let {
|
|
2
|
+
let {
|
|
3
|
+
id,
|
|
4
|
+
path,
|
|
5
|
+
fill = 'currentColor',
|
|
6
|
+
stroke = 'currentColor',
|
|
7
|
+
thickness = 0.5,
|
|
8
|
+
patternUnits = 'userSpaceOnUse',
|
|
9
|
+
size = 10
|
|
10
|
+
} = $props()
|
|
3
11
|
</script>
|
|
4
12
|
|
|
5
13
|
<pattern {id} {patternUnits} width={size} height={size}>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
let {
|
|
3
|
-
x,
|
|
4
|
-
y,
|
|
5
|
-
text,
|
|
6
|
-
angle = 0,
|
|
7
|
-
small = false,
|
|
8
|
-
anchor = 'middle'
|
|
9
|
-
} = $props()
|
|
2
|
+
let { x, y, text, angle = 0, small = false, anchor = 'middle' } = $props()
|
|
10
3
|
|
|
11
4
|
let transform = $derived(`translate(${x},${y}) rotate(${angle})`)
|
|
12
5
|
let validAnchor = $derived(['start', 'middle', 'end'].includes(anchor) ? anchor : 'middle')
|
|
@@ -3,11 +3,7 @@
|
|
|
3
3
|
import { swatch, swatchGrid } from '../old_lib'
|
|
4
4
|
import Symbol from '../Symbol.svelte'
|
|
5
5
|
|
|
6
|
-
let {
|
|
7
|
-
base = 'teal',
|
|
8
|
-
size = 4,
|
|
9
|
-
shade = 600
|
|
10
|
-
} = $props()
|
|
6
|
+
let { base = 'teal', size = 4, shade = 600 } = $props()
|
|
11
7
|
|
|
12
8
|
let swatchValue = $derived(get(swatch))
|
|
13
9
|
let grid = $derived(swatchGrid(swatchValue.keys.symbol.length, size, 10))
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
let {
|
|
2
|
+
let {
|
|
3
|
+
x = 0,
|
|
4
|
+
y = 0,
|
|
5
|
+
size = 1,
|
|
6
|
+
fill = 'currentColor',
|
|
7
|
+
stroke = 'currentColor',
|
|
8
|
+
onclick,
|
|
9
|
+
onmouseover,
|
|
10
|
+
onmouseleave,
|
|
11
|
+
onfocus,
|
|
12
|
+
...restProps
|
|
13
|
+
} = $props()
|
|
3
14
|
|
|
4
15
|
let r = $derived(size * 3.534)
|
|
5
16
|
let props = $derived({ rx: r * 0.1, ry: r * 0.1, ...restProps })
|
package/src/symbols/Shape.svelte
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { namedShapes } from './constants'
|
|
3
3
|
|
|
4
|
-
let {
|
|
4
|
+
let {
|
|
5
|
+
x = 0,
|
|
6
|
+
y = 0,
|
|
7
|
+
size = 1,
|
|
8
|
+
fill = 'none',
|
|
9
|
+
stroke = 'currentColor',
|
|
10
|
+
thickness = 1,
|
|
11
|
+
name = 'circle',
|
|
12
|
+
onclick,
|
|
13
|
+
onmouseover,
|
|
14
|
+
onmouseleave,
|
|
15
|
+
onfocus,
|
|
16
|
+
onblur
|
|
17
|
+
} = $props()
|
|
5
18
|
|
|
6
19
|
let d = $derived(name in namedShapes ? namedShapes[name](size) : namedShapes['circle'](size))
|
|
7
20
|
</script>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
let { size = 10, fill = 'currentColor', stroke = 'currentColor', data } = $props()
|
|
3
3
|
|
|
4
|
-
let circles = $derived(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
let circles = $derived(
|
|
5
|
+
data.map(({ cx, cy, r }) => ({
|
|
6
|
+
cx: cx * size,
|
|
7
|
+
cy: cy * size,
|
|
8
|
+
r: r * size
|
|
9
|
+
}))
|
|
10
|
+
)
|
|
9
11
|
</script>
|
|
10
12
|
|
|
11
13
|
{#each circles as { cx, cy, r }, index (index)}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
let { size = 10, thickness = 0.5, stroke = 'currentColor', data = [] } = $props()
|
|
3
3
|
|
|
4
|
-
let lines = $derived(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
let lines = $derived(
|
|
5
|
+
data.map(({ x1, y1, x2, y2 }) => ({
|
|
6
|
+
x1: x1 * size,
|
|
7
|
+
y1: y1 * size,
|
|
8
|
+
x2: x2 * size,
|
|
9
|
+
y2: y2 * size
|
|
10
|
+
}))
|
|
11
|
+
)
|
|
10
12
|
</script>
|
|
11
13
|
|
|
12
14
|
{#each lines as line, index (index)}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
let {
|
|
2
|
+
let {
|
|
3
|
+
size = 10,
|
|
4
|
+
thickness = 0.5,
|
|
5
|
+
fill = 'currentColor',
|
|
6
|
+
stroke = 'currentColor',
|
|
7
|
+
data = []
|
|
8
|
+
} = $props()
|
|
3
9
|
|
|
4
10
|
let polygons = $derived(data.map((points) => points.map((point) => point * size).join(', ')))
|
|
5
11
|
</script>
|