chart-factory 0.1.2
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 +21 -0
- package/README.md +162 -0
- package/dist/chart-factory-table.js +1400 -0
- package/dist/chart-factory.css +2368 -0
- package/dist/chart-factory.js +11398 -0
- package/dist/chart-factory.min.js +7 -0
- package/docs/API.md +1815 -0
- package/docs/chart-guide.md +872 -0
- package/docs/color-guide.md +134 -0
- package/docs/conformance-matrix.md +864 -0
- package/docs/theming.md +107 -0
- package/index.d.ts +10453 -0
- package/package.json +83 -0
- package/src/core/base.css +508 -0
- package/src/core/builder-metadata.generated.mjs +406 -0
- package/src/core/d3-base.js +249 -0
- package/src/core/d3-chart-factory.js +18547 -0
- package/src/core/d3-data.js +0 -0
- package/src/core/d3-suggest.js +565 -0
- package/src/core/example-nav.css +62 -0
- package/src/core/example-nav.js +249 -0
- package/src/core/palettes.js +310 -0
- package/src/core/theme-toggle.js +126 -0
- package/src/core/tokens.css +792 -0
- package/src/table/d3-table.js +1570 -0
- package/src/table/table.css +899 -0
- package/src/table/tokens.css +157 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Color guide — choosing, not configuring
|
|
2
|
+
|
|
3
|
+
How to make color *decisions* in Chart Factory. For the option reference see
|
|
4
|
+
[API.md](API.md); for the palette surface see
|
|
5
|
+
[Palettes (`ChartFactory.palettes`)](API.md#palettes-chartfactorypalettes).
|
|
6
|
+
This guide is deliberately bounded to Chart Factory's builders — it is not a
|
|
7
|
+
general visualization textbook.
|
|
8
|
+
|
|
9
|
+
## Rule zero: omit color options
|
|
10
|
+
|
|
11
|
+
**The defaults are the house style.** Single-series charts use `--chart-primary`
|
|
12
|
+
(brand blue); multi-series charts use the Set2 categorical palette
|
|
13
|
+
(`--area-color-1..8`, CVD-safe, matched across families, theme-aware). Most
|
|
14
|
+
configs should pass **no color options at all** — every color you hardcode is
|
|
15
|
+
one that stops re-theming, stops dark-mode adaptation, and drifts from the
|
|
16
|
+
house look. Reach for a color option only when one of the decisions below
|
|
17
|
+
genuinely applies.
|
|
18
|
+
|
|
19
|
+
## Pick the palette *type* from the data, not the look
|
|
20
|
+
|
|
21
|
+
| Your data is… | Type | Test | Examples |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| Ordered, one direction (counts, density, intensity) | **Sequential** | "Is 80 *more of the same thing* than 20?" | `Viridis`, `Blues`, `YlOrRd` |
|
|
24
|
+
| Ordered around a **meaningful midpoint** (zero, average, target, 50%) | **Diverging** | "Is the midpoint a real boundary — above vs below?" | `RdBu`, `Temperature`, `PuOr` |
|
|
25
|
+
| Named categories with no order | **Categorical** | "Would reordering the legend lose nothing?" | `Set2` (default), `OkabeIto`, `Dark2` |
|
|
26
|
+
| Mostly noise, a few values that must pop | **Alert** | "Do only the extremes matter?" | `OrangeAlert`, `ForestAlert` |
|
|
27
|
+
|
|
28
|
+
The classic mistake is diverging-for-sequential: a red-to-blue ramp on plain
|
|
29
|
+
counts invents a midpoint the data doesn't have. The reverse mistake hides
|
|
30
|
+
one: profit/loss on a `Blues` ramp buries the zero crossing. **Ask where the
|
|
31
|
+
midpoint is. No answer → sequential. Real answer → diverging, and pin it with
|
|
32
|
+
`colorDomain: [-max, max]` so the neutral center sits on the true zero.**
|
|
33
|
+
|
|
34
|
+
- Heatmap/hexbin/contour/calendar take `colorScheme: 'Viridis'` (or any
|
|
35
|
+
sequential/diverging palette or d3 interpolator name).
|
|
36
|
+
- `Bar.createDiverging` colors by sign (green/red trend semantics) and
|
|
37
|
+
`Bar.createLikert` builds its own diverging ramp from the temperature
|
|
38
|
+
tokens — both already encode direction; don't override either with a
|
|
39
|
+
categorical palette.
|
|
40
|
+
- Never use a sequential ramp for categories — adjacent steps are
|
|
41
|
+
indistinguishable as fills; that's what categorical palettes are for.
|
|
42
|
+
|
|
43
|
+
## Categories: fewer, then gray the rest
|
|
44
|
+
|
|
45
|
+
Legibility collapses past **6–8 categories** — that's why Set2 has 8 colors,
|
|
46
|
+
not 20. Past that, don't grab a 12-color palette; **shrink the category count**:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
const top = ChartFactory.data.topN(rows, 'revenue', 5, { by: 'segment', other: 'Other' });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The residual bucket is handled for you: **a series or slice named "Other" is
|
|
53
|
+
automatically colored neutral gray** (`--chart-neutral`) by the default
|
|
54
|
+
palettes, and it does *not* consume a palette slot — real categories keep
|
|
55
|
+
their colors. This applies to stacked/normalized/streamgraph areas,
|
|
56
|
+
stacked/grouped/vertical bars, multi-line, histogram overlays, donut
|
|
57
|
+
(including its own `minSlice` fold), and the derived shell legend
|
|
58
|
+
(`legend: true`). Passing explicit `colors` or `colorMap` disables it —
|
|
59
|
+
that's the escape hatch when "Other" is a genuine category.
|
|
60
|
+
|
|
61
|
+
Keep "Other" **last** in `keys`/data order (`data.topN` already does this):
|
|
62
|
+
gray reads as "the remainder", and remainders belong at the end.
|
|
63
|
+
|
|
64
|
+
## Reserved meanings — don't spend them on categories
|
|
65
|
+
|
|
66
|
+
Some colors already mean something in this system. Using them as arbitrary
|
|
67
|
+
category colors creates false signals:
|
|
68
|
+
|
|
69
|
+
- **Green/red = direction.** `--chart-trend-up` / `--chart-trend-down` drive
|
|
70
|
+
slope-trend coloring, diverging bars, and up/down markers. A category that
|
|
71
|
+
happens to be green will be read as "good".
|
|
72
|
+
- **Red = anomaly** (`--chart-anomaly`): pulse/forecast anomaly markers.
|
|
73
|
+
- **Gray = de-emphasis**: the residual bucket, muted series in
|
|
74
|
+
highlight modes, context layers. Never use gray for a category you want
|
|
75
|
+
the reader to care about.
|
|
76
|
+
- Avoid red+green as a categorical *pair* entirely — it's the most common
|
|
77
|
+
color-vision confusion. If direction matters and accessibility is critical,
|
|
78
|
+
pair color with another channel the way the builders already do
|
|
79
|
+
(slope direction, diverging sides, anomaly markers are all positional too).
|
|
80
|
+
|
|
81
|
+
For context/reference series (a benchmark line behind the real data, last
|
|
82
|
+
year's shape), use `extraLayers` with a neutral:
|
|
83
|
+
`{ type: 'line', y: 'lastYear', color: 'var(--chart-neutral)', behind: true }`.
|
|
84
|
+
|
|
85
|
+
## Accessibility (CVD)
|
|
86
|
+
|
|
87
|
+
The defaults are already safe: **Set2** (categorical) and **Viridis**-family
|
|
88
|
+
(sequential) are colorblind-safe. If you deviate, check before shipping:
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
ChartFactory.palettes.isColorblindSafe('RdYlGn') // false — avoid
|
|
92
|
+
ChartFactory.palettes.list('categorical')
|
|
93
|
+
.filter(ChartFactory.palettes.isColorblindSafe) // safe alternatives
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`OkabeIto` is the strictest categorical choice (designed for all CVD types) —
|
|
97
|
+
but note its 8th color is pure black, which disappears on dark backgrounds;
|
|
98
|
+
slice it to 7 if you need dark-mode parity. `RdYlGn` (“traffic light”) is the
|
|
99
|
+
most-requested unsafe palette; `RdYlBu` or `Temperature` carry the same
|
|
100
|
+
bad-to-good reading safely.
|
|
101
|
+
|
|
102
|
+
## Dark mode: already handled
|
|
103
|
+
|
|
104
|
+
Sequential/diverging ramps re-anchor their pale end toward the surface under
|
|
105
|
+
`[data-theme="dark"]`; the categorical tokens have dark variants; charts
|
|
106
|
+
re-theme on `ChartFactory.rerenderAll()` (or `setTheme(name)`, which does
|
|
107
|
+
both steps). **Do not compensate manually** — no "dark mode palettes", no
|
|
108
|
+
hand-lightened hexes. If you pass literal hexes, you own their dark-mode
|
|
109
|
+
behavior; prefer `var(--…)` token strings (they re-theme via CSS) or palette
|
|
110
|
+
*names* (re-resolved per render).
|
|
111
|
+
|
|
112
|
+
Dark mode is one instance of the general theming contract — external
|
|
113
|
+
"companion themes" (own token scope, texture fills, mark filters) are
|
|
114
|
+
documented in [theming.md](theming.md).
|
|
115
|
+
|
|
116
|
+
## Scenario → palette
|
|
117
|
+
|
|
118
|
+
| Scenario | Use |
|
|
119
|
+
|---|---|
|
|
120
|
+
| Any single-series chart | nothing — `--chart-primary` |
|
|
121
|
+
| Any multi-series chart, ≤8 categories | nothing — Set2 default |
|
|
122
|
+
| >8 categories | `data.topN(...)` + auto-grayed "Other" |
|
|
123
|
+
| Heatmap / density / calendar intensity | `colorScheme: 'Viridis'` (or `Blues` for corporate-quiet) |
|
|
124
|
+
| Above/below zero, plus/minus, diff vs target | `colorScheme: 'RdBu'` or `'Temperature'`, domain pinned symmetric |
|
|
125
|
+
| Performance bad→good with CVD safety | `RdYlBu` or `Temperature` (not `RdYlGn`) |
|
|
126
|
+
| Strict accessibility requirement | `colors: 'OkabeIto'` (7 colors on dark) |
|
|
127
|
+
| Benchmark/context series | `extraLayers` + `var(--chart-neutral)`, `behind: true` |
|
|
128
|
+
| Status/semantic UI values | `colors: 'Status'` (success/warning/error/info) |
|
|
129
|
+
| Yes/no, on/off | `colors: 'Binary'` |
|
|
130
|
+
|
|
131
|
+
One consistency rule across a dashboard: **same entity, same color,
|
|
132
|
+
everywhere.** When several charts show the same categories, pass the same
|
|
133
|
+
explicit `colors`/`colorMap` (or use `linkGroup`'s shared `colorFor`) rather
|
|
134
|
+
than letting encounter order assign different hues per chart.
|