@rokkit/chart 1.0.0-next.132 → 1.0.0-next.134

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jerry Thomas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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/docs/stock.html). This package combines the power of D3.js with the reactivity and component-based approach of Svelte.
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
- ## Installation
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
- ## Usage
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
- The chart package provides a set of composable components that can be combined to create various chart types.
17
+ ## Usage
14
18
 
15
- ### Basic Bar Chart Example
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
- // Sample data
23
- const sampleData = [
24
- { model: 'Model A', name: 'Product 1', category: 'Electronics', count: 45 },
25
- { model: 'Model B', name: 'Product 2', category: 'Clothing', count: 32 },
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} margin={{ top: 20, right: 30, bottom: 40, left: 50 }}>
38
- <Plot.Grid direction="y" />
39
- <Plot.Axis type="x" field="model" label="Model" />
40
- <Plot.Axis type="y" field="count" label="Count" />
41
- <Plot.Bar x="model" y="count" fill="category" />
42
- <Plot.Legend title="Categories" />
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
- ## Available Components
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
- let input = [
125
- // Your raw data here
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
- $: processedData = dataset(input)
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={processedData} fill="category">
60
+ <Plot.Root {data} fill="category" width={500} height={350}>
138
61
  <Plot.Axis type="x" field="category" />
139
- <Plot.Axis type="y" field="count" />
140
- <Plot.Bar x="category" y="count" />
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
- ## Advanced Features
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
- - Tooltips are automatically generated for data points
147
- - Interactive legends for filtering data
148
- - Responsive design by default
149
- - Animated transitions when data changes
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/chart",
3
- "version": "1.0.0-next.132",
3
+ "version": "1.0.0-next.134",
4
4
  "type": "module",
5
5
  "description": "Data-driven chart components",
6
6
  "author": "Jerry Thomas <me@jerrythomas.name>",
@@ -12,7 +12,8 @@
12
12
  "access": "public"
13
13
  },
14
14
  "scripts": {
15
- "prepublishOnly": "bun clean && bun tsc --project tsconfig.build.json",
15
+ "prepublishOnly": "cp ../../LICENSE . && bun clean && bun tsc --project tsconfig.build.json",
16
+ "postpublish": "rm -f LICENSE",
16
17
  "clean": "rm -rf dist",
17
18
  "build": "bun prepublishOnly"
18
19
  },
@@ -21,7 +22,8 @@
21
22
  "src/**/*.svelte",
22
23
  "dist/**/*.d.ts",
23
24
  "README.md",
24
- "package.json"
25
+ "package.json",
26
+ "LICENSE"
25
27
  ],
26
28
  "exports": {
27
29
  "./package.json": "./package.json",
@@ -1,5 +1,13 @@
1
1
  <script>
2
- let { id, path, fill = 'currentColor', stroke = 'currentColor', thickness = 0.5, patternUnits = 'userSpaceOnUse', size = 10 } = $props()
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 { x = 0, y = 0, size = 1, fill = 'currentColor', stroke = 'currentColor', onclick, onmouseover, onmouseleave, onfocus, ...restProps } = $props()
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 })
@@ -1,7 +1,20 @@
1
1
  <script>
2
2
  import { namedShapes } from './constants'
3
3
 
4
- let { x = 0, y = 0, size = 1, fill = 'none', stroke = 'currentColor', thickness = 1, name = 'circle', onclick, onmouseover, onmouseleave, onfocus, onblur } = $props()
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(data.map(({ cx, cy, r }) => ({
5
- cx: cx * size,
6
- cy: cy * size,
7
- r: r * size
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(data.map(({ x1, y1, x2, y2 }) => ({
5
- x1: x1 * size,
6
- y1: y1 * size,
7
- x2: x2 * size,
8
- y2: y2 * size
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 { size = 10, thickness = 0.5, fill = 'currentColor', stroke = 'currentColor', data = [] } = $props()
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>