@inglorious/charts 1.0.1
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 +9 -0
- package/README.md +554 -0
- package/package.json +64 -0
- package/src/base.css +86 -0
- package/src/cartesian/area.js +392 -0
- package/src/cartesian/area.test.js +366 -0
- package/src/cartesian/bar.js +445 -0
- package/src/cartesian/bar.test.js +346 -0
- package/src/cartesian/line.js +823 -0
- package/src/cartesian/line.test.js +177 -0
- package/src/chart.test.js +444 -0
- package/src/component/brush.js +264 -0
- package/src/component/empty-state.js +33 -0
- package/src/component/empty-state.test.js +81 -0
- package/src/component/grid.js +123 -0
- package/src/component/grid.test.js +123 -0
- package/src/component/legend.js +76 -0
- package/src/component/legend.test.js +103 -0
- package/src/component/tooltip.js +65 -0
- package/src/component/tooltip.test.js +96 -0
- package/src/component/x-axis.js +212 -0
- package/src/component/x-axis.test.js +148 -0
- package/src/component/y-axis.js +77 -0
- package/src/component/y-axis.test.js +107 -0
- package/src/handlers.js +150 -0
- package/src/index.js +264 -0
- package/src/polar/donut.js +181 -0
- package/src/polar/donut.test.js +152 -0
- package/src/polar/pie.js +758 -0
- package/src/polar/pie.test.js +268 -0
- package/src/shape/curve.js +55 -0
- package/src/shape/dot.js +104 -0
- package/src/shape/rectangle.js +46 -0
- package/src/shape/sector.js +58 -0
- package/src/template.js +25 -0
- package/src/theme.css +90 -0
- package/src/utils/cartesian-layout.js +164 -0
- package/src/utils/chart-utils.js +30 -0
- package/src/utils/colors.js +77 -0
- package/src/utils/data-utils.js +155 -0
- package/src/utils/data-utils.test.js +210 -0
- package/src/utils/extract-data-keys.js +22 -0
- package/src/utils/padding.js +16 -0
- package/src/utils/paths.js +279 -0
- package/src/utils/process-declarative-child.js +46 -0
- package/src/utils/scales.js +250 -0
- package/src/utils/shared-context.js +166 -0
- package/src/utils/shared-context.test.js +237 -0
- package/src/utils/tooltip-handlers.js +129 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Inglorious Coderz Srl.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
# Inglorious Charts
|
|
2
|
+
|
|
3
|
+
A powerful, declarative charting library for Inglorious Web, inspired by Recharts. Built with SVG and `lit-html`, Inglorious Charts provides a flexible and composable way to create beautiful data visualizations.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📊 **Multiple Chart Types**: Line, Area, Bar, Pie, and Donut charts
|
|
8
|
+
- 🎨 **Two Rendering Modes**: Config-first (declarative) and Composition (Recharts-style)
|
|
9
|
+
- 🧩 **Pure & Stateless**: Core logic built with pure functions for predictable rendering and easy testing
|
|
10
|
+
- 🎯 **Interactive Tooltips**: Smart tooltip positioning with automatic overflow detection
|
|
11
|
+
- 📈 **Multiple Series Support**: Render multiple data series in a single chart
|
|
12
|
+
- 🎨 **Customizable Styling**: Full control over colors, sizes, and appearance
|
|
13
|
+
- 📱 **Responsive**: Works seamlessly across different screen sizes
|
|
14
|
+
- 🔧 **Type-Safe**: Built with TypeScript definitions
|
|
15
|
+
- 🛡️ **Memory-Safe**: No global caches or Singletons, preventing memory leaks in complex SPAs
|
|
16
|
+
- 🚀 **Deterministic Rendering**: Optimized rendering engine that avoids expensive try/catch operations and ensures visual stability
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @inglorious/charts
|
|
22
|
+
# or
|
|
23
|
+
pnpm add @inglorious/charts
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### Config-First Mode
|
|
29
|
+
|
|
30
|
+
The simplest way to create charts is using the config-first approach. First, register the chart types in your store:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// In your store/index.js
|
|
34
|
+
import { createStore } from "@inglorious/web"
|
|
35
|
+
import {
|
|
36
|
+
lineChart,
|
|
37
|
+
areaChart,
|
|
38
|
+
barChart,
|
|
39
|
+
pieChart,
|
|
40
|
+
donutChart,
|
|
41
|
+
} from "@inglorious/charts"
|
|
42
|
+
|
|
43
|
+
export const store = createStore({
|
|
44
|
+
types: {
|
|
45
|
+
line: lineChart,
|
|
46
|
+
area: areaChart,
|
|
47
|
+
bar: barChart,
|
|
48
|
+
pie: pieChart,
|
|
49
|
+
donut: donutChart,
|
|
50
|
+
},
|
|
51
|
+
entities,
|
|
52
|
+
middlewares,
|
|
53
|
+
})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then define your chart entity in the store:
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
// In your store/entities.js
|
|
60
|
+
export const entities = {
|
|
61
|
+
myLineChart: {
|
|
62
|
+
type: "line",
|
|
63
|
+
data: [
|
|
64
|
+
{ name: "Jan", value: 400 },
|
|
65
|
+
{ name: "Feb", value: 300 },
|
|
66
|
+
{ name: "Mar", value: 500 },
|
|
67
|
+
],
|
|
68
|
+
width: 800,
|
|
69
|
+
height: 400,
|
|
70
|
+
showGrid: true,
|
|
71
|
+
showTooltip: true,
|
|
72
|
+
showLegend: true,
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Finally, render the chart in your component:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
// In your app.js
|
|
81
|
+
import { html } from "@inglorious/web"
|
|
82
|
+
|
|
83
|
+
export const app = {
|
|
84
|
+
render(api) {
|
|
85
|
+
return html` ${api.render("myLineChart")} `
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Composition Mode
|
|
91
|
+
|
|
92
|
+
For more control and flexibility, use the composition approach. First, define your chart entity in the store:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// In your store/entities.js
|
|
96
|
+
export const entities = {
|
|
97
|
+
myLineChart: {
|
|
98
|
+
type: "line",
|
|
99
|
+
data: [
|
|
100
|
+
{ name: "Jan", value: 400 },
|
|
101
|
+
{ name: "Feb", value: 300 },
|
|
102
|
+
{ name: "Mar", value: 500 },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Then use the `chart` helper in your component:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
import { html } from "@inglorious/web"
|
|
112
|
+
import { chart } from "@inglorious/charts"
|
|
113
|
+
|
|
114
|
+
export const app = {
|
|
115
|
+
render(api) {
|
|
116
|
+
return html`
|
|
117
|
+
${chart(api, "myLineChart", (c) =>
|
|
118
|
+
c.renderLineChart(
|
|
119
|
+
[
|
|
120
|
+
c.renderCartesianGrid({ stroke: "#eee", strokeDasharray: "5 5" }),
|
|
121
|
+
c.renderXAxis({ dataKey: "name" }),
|
|
122
|
+
c.renderYAxis({ width: "auto" }),
|
|
123
|
+
c.renderLine({
|
|
124
|
+
dataKey: "value",
|
|
125
|
+
stroke: "#8884d8",
|
|
126
|
+
showDots: true,
|
|
127
|
+
}),
|
|
128
|
+
c.renderTooltip({}),
|
|
129
|
+
],
|
|
130
|
+
{
|
|
131
|
+
width: 800,
|
|
132
|
+
height: 400,
|
|
133
|
+
dataKeys: ["value"], // Required to sync Y-axis scale across multiple series
|
|
134
|
+
stacked: false, // Set to true to automatically sum values (Area/Bar)
|
|
135
|
+
},
|
|
136
|
+
),
|
|
137
|
+
)}
|
|
138
|
+
`
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Note:** The `chart` helper takes the `entityId` (e.g., `"myLineChart"`) and fetches the data from your store. You can also override the data by passing it in the config:
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
c.renderLineChart(
|
|
147
|
+
[
|
|
148
|
+
/* components */
|
|
149
|
+
],
|
|
150
|
+
{
|
|
151
|
+
width: 800,
|
|
152
|
+
height: 400,
|
|
153
|
+
dataKeys: ["value"], // Required to sync Y-axis scale across multiple series
|
|
154
|
+
stacked: false, // Set to true to automatically sum values (Area/Bar)
|
|
155
|
+
data: [
|
|
156
|
+
{ name: "Jan", value: 400 },
|
|
157
|
+
{ name: "Feb", value: 300 },
|
|
158
|
+
], // Override entity data
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
💡 **Smart Layering**: The library uses an internal flag system (`isGrid`, `isAxis`, etc.) to ensure elements are rendered in the correct visual order (Z-index). The Grid will always be at the back and Axes always at the front, regardless of the order you declare them in the array.
|
|
164
|
+
|
|
165
|
+
## Chart Types
|
|
166
|
+
|
|
167
|
+
### Line Chart
|
|
168
|
+
|
|
169
|
+
Displays data as a connected line, ideal for showing trends over time.
|
|
170
|
+
|
|
171
|
+
**Config Mode:**
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
{
|
|
175
|
+
type: "line",
|
|
176
|
+
data: [
|
|
177
|
+
{ name: "Jan", value: 100 },
|
|
178
|
+
{ name: "Feb", value: 200 },
|
|
179
|
+
{ name: "Mar", value: 150 },
|
|
180
|
+
],
|
|
181
|
+
showPoints: true, // Show dots on data points
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Composition Mode:**
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
c.renderLineChart([
|
|
189
|
+
c.renderLine({ dataKey: "value", stroke: "#8884d8", showDots: true }),
|
|
190
|
+
// ... other components
|
|
191
|
+
])
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Area Chart
|
|
195
|
+
|
|
196
|
+
Similar to line charts but with filled areas under the line.
|
|
197
|
+
|
|
198
|
+
**Config Mode:**
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
{
|
|
202
|
+
type: "area",
|
|
203
|
+
data: [
|
|
204
|
+
{ name: "Jan", value: 100 },
|
|
205
|
+
{ name: "Feb", value: 200 },
|
|
206
|
+
{ name: "Mar", value: 150 },
|
|
207
|
+
],
|
|
208
|
+
stacked: false, // Set to true for stacked areas
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Composition Mode:**
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
c.renderAreaChart([
|
|
216
|
+
c.renderArea({
|
|
217
|
+
dataKey: "value",
|
|
218
|
+
fill: "#8884d8",
|
|
219
|
+
fillOpacity: "0.6",
|
|
220
|
+
stroke: "#8884d8",
|
|
221
|
+
}),
|
|
222
|
+
c.renderDots({ dataKey: "value", fill: "#8884d8" }),
|
|
223
|
+
// ... other components
|
|
224
|
+
])
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Bar Chart
|
|
228
|
+
|
|
229
|
+
Displays data as rectangular bars, perfect for comparing categories.
|
|
230
|
+
|
|
231
|
+
**Config Mode:**
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
{
|
|
235
|
+
type: "bar",
|
|
236
|
+
data: [
|
|
237
|
+
{ name: "A", value: 100 },
|
|
238
|
+
{ name: "B", value: 200 },
|
|
239
|
+
{ name: "C", value: 150 },
|
|
240
|
+
],
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Composition Mode:**
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
c.renderBarChart([
|
|
248
|
+
c.renderBar({ dataKey: "value", fill: "#8884d8" }),
|
|
249
|
+
// ... other components
|
|
250
|
+
])
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Pie Chart
|
|
254
|
+
|
|
255
|
+
Circular chart showing proportions of a whole.
|
|
256
|
+
|
|
257
|
+
**Config Mode:**
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
{
|
|
261
|
+
type: "pie",
|
|
262
|
+
data: [
|
|
263
|
+
{ label: "A", value: 30 },
|
|
264
|
+
{ label: "B", value: 40 },
|
|
265
|
+
{ label: "C", value: 30 },
|
|
266
|
+
],
|
|
267
|
+
cx: "50%", // Center X
|
|
268
|
+
cy: "50%", // Center Y
|
|
269
|
+
showTooltip: true,
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Donut Chart
|
|
274
|
+
|
|
275
|
+
Similar to pie chart but with a hollow center.
|
|
276
|
+
|
|
277
|
+
**Config Mode:**
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
{
|
|
281
|
+
type: "donut",
|
|
282
|
+
data: [
|
|
283
|
+
{ label: "A", value: 30 },
|
|
284
|
+
{ label: "B", value: 40 },
|
|
285
|
+
{ label: "C", value: 30 },
|
|
286
|
+
],
|
|
287
|
+
innerRadius: "60%", // Controls the hole size
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Composition Components
|
|
292
|
+
|
|
293
|
+
When using composition mode, you can combine these components:
|
|
294
|
+
|
|
295
|
+
**Note on Rendering:** Components like `renderLegend` and `renderTooltip` are rendered as HTML overlays, while `renderLine`, `renderArea`, or `renderBar` are rendered as SVG elements. The library handles this separation automatically to ensure accessibility and styling flexibility.
|
|
296
|
+
|
|
297
|
+
### `renderCartesianGrid`
|
|
298
|
+
|
|
299
|
+
Renders grid lines for cartesian charts.
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
c.renderCartesianGrid({
|
|
303
|
+
stroke: "#eee",
|
|
304
|
+
strokeDasharray: "5 5",
|
|
305
|
+
})
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### `renderXAxis`
|
|
309
|
+
|
|
310
|
+
Renders the X-axis with labels.
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
c.renderXAxis({ dataKey: "name" })
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### `renderYAxis`
|
|
317
|
+
|
|
318
|
+
Renders the Y-axis.
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
c.renderYAxis({ width: "auto" })
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### `renderLine`
|
|
325
|
+
|
|
326
|
+
Renders a line series.
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
c.renderLine({
|
|
330
|
+
dataKey: "value",
|
|
331
|
+
stroke: "#8884d8",
|
|
332
|
+
showDots: true, // Automatically render dots
|
|
333
|
+
type: "linear", // Curve type: "linear", "monotone", etc.
|
|
334
|
+
})
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### `renderArea`
|
|
338
|
+
|
|
339
|
+
Renders an area series.
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
c.renderArea({
|
|
343
|
+
dataKey: "value",
|
|
344
|
+
fill: "#8884d8",
|
|
345
|
+
fillOpacity: "0.6",
|
|
346
|
+
stroke: "#8884d8",
|
|
347
|
+
type: "linear",
|
|
348
|
+
})
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### `renderBar`
|
|
352
|
+
|
|
353
|
+
Renders a bar series.
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
c.renderBar({
|
|
357
|
+
dataKey: "value",
|
|
358
|
+
fill: "#8884d8",
|
|
359
|
+
})
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### `renderDots`
|
|
363
|
+
|
|
364
|
+
Renders dots on data points (alternative to `showDots` in `renderLine`).
|
|
365
|
+
|
|
366
|
+
```javascript
|
|
367
|
+
c.renderDots({
|
|
368
|
+
dataKey: "value",
|
|
369
|
+
fill: "#8884d8",
|
|
370
|
+
r: "0.25em",
|
|
371
|
+
stroke: "white",
|
|
372
|
+
strokeWidth: "0.125em",
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### `renderLegend`
|
|
377
|
+
|
|
378
|
+
Renders a legend for multiple series.
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
c.renderLegend({
|
|
382
|
+
dataKeys: ["productA", "productB"],
|
|
383
|
+
labels: ["Product A", "Product B"],
|
|
384
|
+
colors: ["#8884d8", "#82ca9d"],
|
|
385
|
+
})
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### `renderTooltip`
|
|
389
|
+
|
|
390
|
+
Renders the tooltip overlay.
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
c.renderTooltip({})
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Data Formats
|
|
397
|
+
|
|
398
|
+
Inglorious Charts supports two data formats:
|
|
399
|
+
|
|
400
|
+
**Wide Format (Recharts Style)**: Useful for composition. A single object contains multiple keys.
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
{
|
|
404
|
+
name: "Jan",
|
|
405
|
+
productA: 100,
|
|
406
|
+
productB: 200,
|
|
407
|
+
productC: 150,
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Long Format (Config Style)**: Ideal for dynamic APIs. Separate series with their own arrays.
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
{
|
|
415
|
+
name: "Product A",
|
|
416
|
+
values: [
|
|
417
|
+
{ x: 0, y: 100 },
|
|
418
|
+
{ x: 1, y: 200 },
|
|
419
|
+
],
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Multiple Series
|
|
424
|
+
|
|
425
|
+
### Config Mode
|
|
426
|
+
|
|
427
|
+
For multiple series, use nested data structure:
|
|
428
|
+
|
|
429
|
+
```javascript
|
|
430
|
+
{
|
|
431
|
+
type: "line",
|
|
432
|
+
data: [
|
|
433
|
+
{
|
|
434
|
+
name: "Product A",
|
|
435
|
+
values: [
|
|
436
|
+
{ x: 0, y: 10 },
|
|
437
|
+
{ x: 1, y: 250 },
|
|
438
|
+
],
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
name: "Product B",
|
|
442
|
+
values: [
|
|
443
|
+
{ x: 0, y: 280 },
|
|
444
|
+
{ x: 1, y: 120 },
|
|
445
|
+
],
|
|
446
|
+
},
|
|
447
|
+
],
|
|
448
|
+
showLegend: true,
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Composition Mode
|
|
453
|
+
|
|
454
|
+
Render multiple series by adding multiple components:
|
|
455
|
+
|
|
456
|
+
```javascript
|
|
457
|
+
import { html } from "@inglorious/web"
|
|
458
|
+
import { chart } from "@inglorious/charts"
|
|
459
|
+
|
|
460
|
+
// In your component
|
|
461
|
+
${chart(api, "multiSeriesChart", (c) =>
|
|
462
|
+
c.renderLineChart([
|
|
463
|
+
c.renderLegend({
|
|
464
|
+
dataKeys: ["productA", "productB"],
|
|
465
|
+
labels: ["Product A", "Product B"],
|
|
466
|
+
colors: ["#8884d8", "#82ca9d"],
|
|
467
|
+
}),
|
|
468
|
+
c.renderLine({ dataKey: "productA", stroke: "#8884d8", showDots: true }),
|
|
469
|
+
c.renderLine({ dataKey: "productB", stroke: "#82ca9d", showDots: true }),
|
|
470
|
+
c.renderTooltip({}),
|
|
471
|
+
], {
|
|
472
|
+
width: 800,
|
|
473
|
+
height: 400,
|
|
474
|
+
dataKeys: ["productA", "productB"], // Required to sync Y-axis scale across multiple series
|
|
475
|
+
stacked: false, // Set to true to automatically sum values (Area/Bar)
|
|
476
|
+
})
|
|
477
|
+
)}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Styling
|
|
481
|
+
|
|
482
|
+
Import the base styles and theme:
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
import "@inglorious/charts/base.css"
|
|
486
|
+
import "@inglorious/charts/theme.css"
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Or customize using CSS variables and classes:
|
|
490
|
+
|
|
491
|
+
- `.iw-chart` - Main chart container
|
|
492
|
+
- `.iw-chart-svg` - SVG element
|
|
493
|
+
- `.iw-chart-line` - Line elements
|
|
494
|
+
- `.iw-chart-area` - Area elements
|
|
495
|
+
- `.iw-chart-bar` - Bar elements
|
|
496
|
+
- `.iw-chart-dot` - Dot elements
|
|
497
|
+
- `.iw-chart-modal` - Tooltip element. Rendered as absolute HTML outside the SVG, giving you full freedom to use shadows, border-radius, and CSS transitions without SVG limitations.
|
|
498
|
+
- `.iw-chart-legend` - Legend element
|
|
499
|
+
|
|
500
|
+
## API Reference
|
|
501
|
+
|
|
502
|
+
### `chart(api, entityId, renderFn)`
|
|
503
|
+
|
|
504
|
+
Helper function for composition mode that provides bound chart methods.
|
|
505
|
+
|
|
506
|
+
**Parameters:**
|
|
507
|
+
|
|
508
|
+
- `api`: Inglorious Web API instance
|
|
509
|
+
- `entityId`: Entity ID from the store
|
|
510
|
+
- `renderFn`: Function that receives chart methods and returns chart configuration
|
|
511
|
+
|
|
512
|
+
**Returns:** `TemplateResult`
|
|
513
|
+
|
|
514
|
+
### `charts.render(entity, api)`
|
|
515
|
+
|
|
516
|
+
Renders a chart from an entity (config mode).
|
|
517
|
+
|
|
518
|
+
**Parameters:**
|
|
519
|
+
|
|
520
|
+
- `entity`: Chart entity object
|
|
521
|
+
- `api`: Inglorious Web API instance
|
|
522
|
+
|
|
523
|
+
**Returns:** `TemplateResult`
|
|
524
|
+
|
|
525
|
+
### Internal Render Method Signature
|
|
526
|
+
|
|
527
|
+
All render methods follow the standard signature pattern: `render<Sub>(entity, props, api)`
|
|
528
|
+
|
|
529
|
+
- `entity`: The chart entity object
|
|
530
|
+
- `props`: Configuration object with method-specific options
|
|
531
|
+
- `api`: Inglorious Web API instance
|
|
532
|
+
|
|
533
|
+
This pattern ensures consistency across all chart components and makes the API predictable for developers extending the library.
|
|
534
|
+
|
|
535
|
+
### Chart Entity Properties
|
|
536
|
+
|
|
537
|
+
Common properties for all chart entities:
|
|
538
|
+
|
|
539
|
+
- `type`: Chart type (`"line"`, `"area"`, `"bar"`, `"pie"`, `"donut"`)
|
|
540
|
+
- `data`: Array of data points
|
|
541
|
+
- `width`: Chart width in pixels (default: 800)
|
|
542
|
+
- `height`: Chart height in pixels (default: 400)
|
|
543
|
+
- `showGrid`: Show grid lines (default: true)
|
|
544
|
+
- `showTooltip`: Enable tooltips (default: true)
|
|
545
|
+
- `showLegend`: Show legend for multi-series (default: true)
|
|
546
|
+
- `colors`: Array of colors for series (optional)
|
|
547
|
+
|
|
548
|
+
## Examples
|
|
549
|
+
|
|
550
|
+
See the [examples directory](../../examples/apps/web-charts) for complete working examples of all chart types and rendering modes.
|
|
551
|
+
|
|
552
|
+
## License
|
|
553
|
+
|
|
554
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inglorious/charts",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Chart components for Inglorious Web, inspired by Recharts",
|
|
5
|
+
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/IngloriousCoderz/inglorious-forge.git",
|
|
10
|
+
"directory": "packages/charts"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/IngloriousCoderz/inglorious-forge/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"charts",
|
|
17
|
+
"visualization",
|
|
18
|
+
"svg",
|
|
19
|
+
"recharts",
|
|
20
|
+
"inglorious"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./types/index.d.ts",
|
|
26
|
+
"import": "./src/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./base.css": "./src/base.css",
|
|
29
|
+
"./theme.css": "./src/theme.css"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"src",
|
|
33
|
+
"types"
|
|
34
|
+
],
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"d3-array": "^3.2.4",
|
|
40
|
+
"d3-format": "^3.1.0",
|
|
41
|
+
"d3-scale": "^4.0.2",
|
|
42
|
+
"d3-shape": "^3.2.0",
|
|
43
|
+
"d3-time-format": "^4.1.0",
|
|
44
|
+
"@inglorious/web": "4.2.4"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@inglorious/web": "4.2.4"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"prettier": "^3.6.2",
|
|
51
|
+
"vite": "^7.1.3",
|
|
52
|
+
"vitest": "^4.0.15",
|
|
53
|
+
"@inglorious/eslint-config": "1.1.2"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">= 22"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"format": "prettier --write '**/*.{js,jsx}'",
|
|
60
|
+
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
|
61
|
+
"test:watch": "vitest",
|
|
62
|
+
"test": "vitest run"
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/base.css
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
.iw-chart {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
overflow: visible;
|
|
5
|
+
|
|
6
|
+
.iw-chart-svg {
|
|
7
|
+
display: block;
|
|
8
|
+
overflow: visible;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.iw-chart-line {
|
|
12
|
+
transition: stroke-width 0.2s ease;
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.iw-chart-point {
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
transition:
|
|
19
|
+
r 0.2s ease,
|
|
20
|
+
fill 0.2s ease;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.iw-chart-dot {
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
transition:
|
|
26
|
+
r 0.2s ease,
|
|
27
|
+
fill 0.2s ease;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.iw-chart-bar,
|
|
31
|
+
.iw-chart-bar-rectangle {
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
transition:
|
|
34
|
+
opacity 0.2s ease,
|
|
35
|
+
filter 0.2s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.iw-chart-area {
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
transition:
|
|
41
|
+
opacity 0.2s ease,
|
|
42
|
+
filter 0.2s ease;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.iw-chart-pie-slice,
|
|
46
|
+
.iw-chart-donut-slice {
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
transition:
|
|
49
|
+
opacity 0.2s ease,
|
|
50
|
+
filter 0.2s ease;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.iw-chart-tooltip {
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.iw-chart-modal {
|
|
58
|
+
position: absolute;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
z-index: 1000;
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
|
|
64
|
+
.iw-chart-modal-header {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.iw-chart-modal-color {
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.iw-chart-modal-body {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.iw-chart-legend {
|
|
80
|
+
pointer-events: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.iw-chart-legend-item {
|
|
84
|
+
cursor: default;
|
|
85
|
+
}
|
|
86
|
+
}
|