apexcharts-skill 1.2.1 → 2.0.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/.cursorrules +272 -0
- package/README.md +9 -5
- package/SKILL.md +102 -22
- package/index.js +1 -0
- package/install/claude-code.md +25 -0
- package/install/copilot.md +23 -0
- package/install/cursor.md +27 -0
- package/package.json +4 -2
- package/references/bar-charts.md +44 -0
- package/references/circular-charts.md +51 -1
- package/references/financial-charts.md +58 -1
- package/references/ssr.md +52 -37
- package/references/tree-shaking.md +19 -3
- package/references/v6-features.md +432 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# v6 Feature Platform: ApexCharts
|
|
2
|
+
|
|
3
|
+
ApexCharts v6 adds an opt-in, tree-shakeable feature platform on top of the v5 core. **Every v5 config keeps working unchanged.** Each feature below is off by default and ships as its own `apexcharts/features/*` entry, so it only enters your bundle when you import it. When using the full `apexcharts` bundle, all features are already present.
|
|
4
|
+
|
|
5
|
+
Two behaviors changed *on by default* (both respect `prefers-reduced-motion`):
|
|
6
|
+
|
|
7
|
+
1. **Coherent variable-length data transitions**: updates that add/remove data points animate as one coordinated motion instead of popping. Appended bars grow from the baseline, removed bars shrink and fade, line/area fills reshape over the union of old and new points, and markers/bubbles/axis labels ride along. Scatter and bubble now animate on dynamic updates for the first time. Disable per chart with `chart.animations.dynamicAnimation.enabled: false`; auto-skipped above `chart.animations.largeDatasetThreshold` (default 1000) and under `prefers-reduced-motion`.
|
|
8
|
+
2. **Native-feeling mobile gestures**: two-finger pinch-zoom, two-finger pan, and kinetic inertia after a flick, with axis rails so a vertical swipe still scrolls the page. Configure via `chart.zoom.pinch` (default `true`) and `chart.pan.inertia` (default `true`, `friction` default `0.92`).
|
|
9
|
+
|
|
10
|
+
Also new by default: **`render()` is idempotent**: a repeated `render()` (e.g. a framework double-invoking an effect) returns the same promise instead of building a duplicate chart. `destroy()` clears it so an instance can render fresh.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Weave: public plugin platform
|
|
15
|
+
|
|
16
|
+
`import 'apexcharts/features/weave'`
|
|
17
|
+
|
|
18
|
+
Publish reusable chart plugins to npm against a stable, versioned API. A plugin draws into its own sandboxed layer and subscribes to lifecycle hooks; it never touches raw internal state.
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
import ApexCharts from 'apexcharts'
|
|
22
|
+
import 'apexcharts/features/weave'
|
|
23
|
+
|
|
24
|
+
ApexCharts.registerPlugin({
|
|
25
|
+
name: 'watermark',
|
|
26
|
+
apiVersion: 1,
|
|
27
|
+
setup(api) {
|
|
28
|
+
api.on('draw', () => {
|
|
29
|
+
const layer = api.layer({ z: 'front', className: 'wm' }) // z: 'front' | 'behind'
|
|
30
|
+
layer.text({ x: 10, y: 20, text: 'ACME', size: '12px', color: '#999' })
|
|
31
|
+
})
|
|
32
|
+
},
|
|
33
|
+
destroy(api) {},
|
|
34
|
+
})
|
|
35
|
+
// ApexCharts.unregisterPlugin('watermark') // for tests / hot reload
|
|
36
|
+
|
|
37
|
+
// Activate per chart:
|
|
38
|
+
const options = { plugins: [{ name: 'watermark', options: { /* frozen, live */ }, order: 0 }] }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The `setup(api)` facade:
|
|
42
|
+
|
|
43
|
+
- `api.on(hook, fn)` / `api.off(hook, fn)`: hooks: `'afterParse' | 'afterScales' | 'draw' | 'afterUpdate' | 'destroy'`.
|
|
44
|
+
- `api.layer(opts?)`: a plugin-owned drawing surface (`path`, `line`, `rect`, `circle`, `text`, `clear`); call it inside draw handlers only, layers are wiped each pass.
|
|
45
|
+
- `api.scales` (readonly): `x(v)`, `y(v, axis?)`, `domainX`, `domainY(axis?)`, `gridWidth`, `gridHeight`, `ratios`.
|
|
46
|
+
- `api.data` (readonly): `[{ name?, hidden, color?, points: [{ x, y }] }]`.
|
|
47
|
+
- `api.theme`: `{ mode, foreColor, seriesColor(i), token(name) }`.
|
|
48
|
+
- `api.store`: per-instance mutable state bag.
|
|
49
|
+
- `api.emit(name, detail?)`: dispatches `plugin:<name>:<event>` on the chart; `api.chart`, `api.el`, `api.name`, `api.version`, `api.options` round out the facade.
|
|
50
|
+
|
|
51
|
+
`apiVersion` gates the contract so raw internals can keep changing safely.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Strata: hybrid SVG + canvas renderer
|
|
56
|
+
|
|
57
|
+
`import 'apexcharts/features/renderer-canvas'`
|
|
58
|
+
|
|
59
|
+
Break the SVG node ceiling without leaving SVG behind. Below a threshold the output is identical SVG; above it, only the series layer becomes a `<canvas>` while axes, grid, tooltips, annotations, and exports stay SVG.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import ApexCharts from 'apexcharts'
|
|
63
|
+
import 'apexcharts/features/renderer-canvas'
|
|
64
|
+
|
|
65
|
+
const options = {
|
|
66
|
+
chart: {
|
|
67
|
+
renderer: 'auto', // 'svg' | 'canvas' | 'auto'
|
|
68
|
+
rendererThreshold: 5000, // point count above which 'auto' picks canvas
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
// chart.getActiveRenderer() // => 'svg' | 'canvas'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Canvas is live for line, area, bar, column, scatter, and candlestick, with shared tooltip, crosshair, zoom, pan, hover/legend dimming, and PNG/SVG export all working. It falls back to SVG automatically for canvas-unsupported features (pattern/image fills, color-matrix filters). Per-point selection visuals and keyboard traversal on canvas remain SVG-only for now.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Marks: composable custom series types
|
|
79
|
+
|
|
80
|
+
`import 'apexcharts/features/marks'`
|
|
81
|
+
|
|
82
|
+
Register a `renderItem(ctx)` function and get a first-class series: events, shared tooltip, legend, and keyboard navigation all work with no extra wiring. Dumbbell, lollipop, and bullet ship as samples.
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
import ApexCharts from 'apexcharts'
|
|
86
|
+
import 'apexcharts/features/marks'
|
|
87
|
+
|
|
88
|
+
ApexCharts.registerSeriesType('lollipop', {
|
|
89
|
+
// dataType?: 'xy' (default) | 'rangeXY' | 'custom'
|
|
90
|
+
// yExtent?: (datum, i) => number | number[] // folds extra values into the y-scale
|
|
91
|
+
// tooltip?: (datum) => number | number[] | string
|
|
92
|
+
renderItem(ctx) {
|
|
93
|
+
const baseline = ctx.scales.y(0) // IMPORTANT: baseline is scales.y(0), NOT api.zeroY
|
|
94
|
+
ctx.api.line({ x1: ctx.x, y1: baseline, x2: ctx.x, y2: ctx.y, stroke: ctx.color, width: 2 })
|
|
95
|
+
ctx.api.circle({ cx: ctx.x, cy: ctx.y, r: 6, fill: ctx.color })
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const options = {
|
|
100
|
+
chart: { type: 'lollipop' },
|
|
101
|
+
series: [{ name: 'Signups', data: [{ x: 'Jan', y: 41 }, { x: 'Feb', y: 58 }] }],
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**`renderItem` context** (`ctx`): `{ datum, x, y, scales, api, seriesIndex, dataPointIndex, color }`: `x`/`y` are resolved pixels for the datum, `color` is the series palette color.
|
|
106
|
+
|
|
107
|
+
**`ctx.api` primitives**: `api.path({ d, stroke, width, fill, opacity, dash, lineCap })`, `api.line({ x1, y1, x2, y2, stroke, width, dash })`, `api.rect({ x, y, w, h, r, fill, stroke, strokeWidth, opacity })`, `api.circle({ cx, cy, r, fill, stroke, strokeWidth })`, `api.text({ x, y, text, anchor, size, color, weight })`.
|
|
108
|
+
|
|
109
|
+
**`ctx.scales`**: `scales.x(value)`, `scales.xAt(index, value)`, `scales.y(value, axis?)`, `scales.gridWidth`, `scales.gridHeight`, `scales.band` (pixel width of one x step / band). There is **no `api.zeroY`**: use `scales.y(0)` for the baseline.
|
|
110
|
+
|
|
111
|
+
Dumbbell uses `dataType: 'rangeXY'` (datum `y` is `[start, end]`, both bounds folded into the axis); bullet uses `yExtent` to fold `target`/top-band into the y-scale. Built-in type names are guarded against shadowing.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Rewind: history and undo/redo
|
|
116
|
+
|
|
117
|
+
`import 'apexcharts/features/history'`
|
|
118
|
+
|
|
119
|
+
Generic Ctrl-Z over a command journal. Zooms, series toggles, option changes, and annotation edits are recorded; high-frequency gestures coalesce into a single step.
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
const options = {
|
|
123
|
+
chart: { history: { enabled: true, maxDepth: 50, coalesceMs: 300, keyboard: true } },
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
chart.history.undo(animate?) // and .redo(animate?)
|
|
127
|
+
chart.history.canUndo() // and .canRedo() -> boolean
|
|
128
|
+
chart.history.jump(id, animate?)
|
|
129
|
+
chart.history.clear()
|
|
130
|
+
await chart.history.transaction(() => { /* batched edits */ }, { label: 'batch' })
|
|
131
|
+
chart.history.entries() // [{ id, label, at }]
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Perspectives: shareable view state
|
|
137
|
+
|
|
138
|
+
`import 'apexcharts/features/perspectives'`
|
|
139
|
+
|
|
140
|
+
Serialize the exact view (zoom window, hidden series, selection, annotations, theme) into a compact token you can put in a URL and restore anywhere.
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const token = chart.perspectives.capture() // { v, view, options? }
|
|
144
|
+
const str = chart.perspectives.encode(token)
|
|
145
|
+
const url = chart.perspectives.toURL() // href with #apex=<token>
|
|
146
|
+
chart.perspectives.apply(token, { animate: true, mergeOptions: {} })
|
|
147
|
+
const id = chart.perspectives.save('Q3 zoom') // -> id
|
|
148
|
+
chart.perspectives.list() // [{ id, name, token }]
|
|
149
|
+
chart.perspectives.delete(id)
|
|
150
|
+
|
|
151
|
+
// static:
|
|
152
|
+
ApexCharts.perspectives.fromURL(location.href) // -> token | null
|
|
153
|
+
ApexCharts.perspectives.decode(str)
|
|
154
|
+
|
|
155
|
+
// config: control which options travel with the token
|
|
156
|
+
const options = { chart: { perspectives: { serializeOptions: ['colors', 'title'] } } }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Facet: design tokens and OS-aware themes
|
|
162
|
+
|
|
163
|
+
`import 'apexcharts/features/facet'`
|
|
164
|
+
|
|
165
|
+
Charts read `--apx-*` CSS custom properties from the cascade, follow the OS light/dark and contrast preferences with no JS, and can reference named brand themes.
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
import ApexCharts from 'apexcharts'
|
|
169
|
+
import 'apexcharts/features/facet'
|
|
170
|
+
|
|
171
|
+
ApexCharts.registerTheme('brand', {
|
|
172
|
+
mode: 'dark', // 'light' | 'dark'
|
|
173
|
+
palette: ['#4f46e5', '#0ea5e9'],
|
|
174
|
+
tokens: { accent: '#4f46e5', grid: '#333', surface: '#111' },
|
|
175
|
+
})
|
|
176
|
+
// ApexCharts.unregisterTheme('brand')
|
|
177
|
+
|
|
178
|
+
const options = {
|
|
179
|
+
theme: {
|
|
180
|
+
follow: 'os', // 'os' | false: tracks prefers-color-scheme + prefers-contrast
|
|
181
|
+
name: 'brand', // a registered theme
|
|
182
|
+
tokens: true, // read --apx-* CSS vars (default true)
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```css
|
|
188
|
+
:root { --apx-accent: #4f46e5; --apx-grid: #e5e7eb; --apx-surface: #fff; --apx-series-1: #4f46e5; }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`await chart.refreshTokens()` re-reads the cascade after a runtime token change that does not itself trigger a render.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Cadence: pluggable easing
|
|
196
|
+
|
|
197
|
+
Core (no feature import).
|
|
198
|
+
|
|
199
|
+
`chart.animations.easing` accepts a named curve, a cubic-bezier array, or a function. The default (`easeInOutSine`) is unchanged, so existing charts animate exactly as before.
|
|
200
|
+
|
|
201
|
+
```js
|
|
202
|
+
const options = {
|
|
203
|
+
chart: {
|
|
204
|
+
animations: {
|
|
205
|
+
easing: 'easeOutBack', // or [0.34, 1.56, 0.64, 1], or (t) => t * t
|
|
206
|
+
dynamicAnimation: { enabled: true, speed: 350, easing: 'linear' },
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
ApexCharts.registerEasing('myBounce', (t) => 1 - Math.pow(1 - t, 3))
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Built-in curve names: `linear`, `easeInSine`, `easeOutSine`, `easeInOutSine`, `easeInQuad`, `easeOutQuad`, `easeInOutQuad`, `easeInCubic`, `easeOutCubic`, `easeInOutCubic`, `easeOutBack`, `easeInOutBack`. Anything else (elastic, bounce, ...) must be registered via `registerEasing`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Link: crossfilter and cross-chart coordination
|
|
219
|
+
|
|
220
|
+
`import 'apexcharts/features/link'`
|
|
221
|
+
|
|
222
|
+
Coordinate a group of charts without wiring.
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
// Highlight mode: brushing one chart dims non-matching marks in the others (no redraw):
|
|
226
|
+
const a = {
|
|
227
|
+
chart: {
|
|
228
|
+
group: 'sales',
|
|
229
|
+
link: { enabled: true, mode: 'highlight', dimOpacity: 0.2 }, // mode: 'highlight' | 'filter'
|
|
230
|
+
selection: { enabled: true }, // required for brushing
|
|
231
|
+
},
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Crossfilter engine: categorical click-filters, range brushes, shared data table, 2D matrix target:
|
|
235
|
+
const cf = ApexCharts.crossfilter({ id: 'sales', records: rows })
|
|
236
|
+
// ApexCharts.getCrossfilter('sales'); chart.clearCrossfilter()
|
|
237
|
+
|
|
238
|
+
// Per-chart filter binding (presence of `dimension` selects filter mode):
|
|
239
|
+
const b = {
|
|
240
|
+
chart: {
|
|
241
|
+
link: {
|
|
242
|
+
enabled: true,
|
|
243
|
+
id: 'sales',
|
|
244
|
+
dimension: (row) => row.region, // key extractor; [xKey, yKey] for a matrix
|
|
245
|
+
reduce: 'count', // 'count' | { sum, avg, min, max } | (rows) => number
|
|
246
|
+
type: 'category', // 'category' | 'range' | 'matrix'
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Ink: direct-manipulation annotation authoring
|
|
255
|
+
|
|
256
|
+
`import 'apexcharts/features/ink'`
|
|
257
|
+
|
|
258
|
+
Annotations become draggable and resizable, with click-to-create, snap to gridlines, and a floating editor card (rename, recolor, bold, font size, marker size/shape, delete). Every edit is undoable when Rewind is enabled.
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
const options = {
|
|
262
|
+
chart: {
|
|
263
|
+
ink: {
|
|
264
|
+
enabled: true,
|
|
265
|
+
palette: true, // show the "add note" tool palette
|
|
266
|
+
snap: true, // snap to gridlines
|
|
267
|
+
noteColors: ['#e91e63', '#3f51b5'], // optional palette override
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
// Fires: annotationDragged, annotationEdited, annotationStyled, annotationDeleted
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Measure: delta ruler
|
|
277
|
+
|
|
278
|
+
`import 'apexcharts/features/measure'`
|
|
279
|
+
|
|
280
|
+
Hold a key and drag to read the change, percent, range, and slope between two points; on release the ruler pins as a data-anchored overlay that re-projects on zoom and resize.
|
|
281
|
+
|
|
282
|
+
```js
|
|
283
|
+
const options = {
|
|
284
|
+
chart: {
|
|
285
|
+
measure: {
|
|
286
|
+
enabled: true,
|
|
287
|
+
mode: 'span', // 'span' = finance-style vertical band; 'free' = diagonal ruler
|
|
288
|
+
key: 'm',
|
|
289
|
+
pinOnRelease: true,
|
|
290
|
+
},
|
|
291
|
+
events: {
|
|
292
|
+
measured: (chart, { from, to, dx, dy, percentChange, slope }) => {},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
}
|
|
296
|
+
// Or drive from code: chart.startMeasure(), chart.stopMeasure(), chart.clearMeasures()
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Styling resolves through `--apx-measure-*` tokens.
|
|
300
|
+
|
|
301
|
+
### Toolbar tool (v6.1)
|
|
302
|
+
|
|
303
|
+
Since 6.1 the ruler is also a built-in toolbar tool, so it can be armed with a click instead of holding the measure key. The button appears automatically whenever `chart.measure.enabled` is true and the `measure` feature is bundled.
|
|
304
|
+
|
|
305
|
+
```js
|
|
306
|
+
const options = {
|
|
307
|
+
chart: {
|
|
308
|
+
measure: { enabled: true },
|
|
309
|
+
toolbar: {
|
|
310
|
+
autoSelected: 'measure', // pre-select the ruler on load (also accepts 'zoom' | 'pan' | 'selection')
|
|
311
|
+
tools: { measure: true }, // default; false keeps it key-only; a string supplies a custom SVG icon
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
- `toolbar.tools.measure` is `boolean | string` (like the other tools). `toolbar.autoSelected` now also accepts `'measure'` so the plot loads armed with no key held and no click. The `m` key still works.
|
|
318
|
+
- Selecting the ruler is mutually exclusive with zoom / pan / selection. The `locale.toolbar.measure` string labels the button.
|
|
319
|
+
- **Behavior change (v6.1, on by default):** clicking an already-selected zoom / pan / selection / measure toolbar icon now toggles it *off*, leaving the chart with no active tool (previously those buttons were one-way).
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Context menu: Radial Actions
|
|
324
|
+
|
|
325
|
+
`import 'apexcharts/features/context-menu'`
|
|
326
|
+
|
|
327
|
+
Right-click or long-press a data point for actions that operate at that exact point.
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
const options = {
|
|
331
|
+
chart: {
|
|
332
|
+
contextMenu: {
|
|
333
|
+
enabled: true,
|
|
334
|
+
// built-in ids (default) + custom items:
|
|
335
|
+
items: ['annotate', 'xline', 'yline', 'measure', {
|
|
336
|
+
id: 'copy',
|
|
337
|
+
label: 'Copy value',
|
|
338
|
+
onClick: (chart, { x, y, seriesIndex, dataPointIndex, clientX, clientY }) => {},
|
|
339
|
+
}],
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Built-in `annotate` / `xline` / `yline` items are ink-managed when the ink feature is bundled (they open the floating editor and undo via Rewind).
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Storyboard: scroll-driven choreography (scrollytelling)
|
|
350
|
+
|
|
351
|
+
`import 'apexcharts/features/storyboard'` (includes Perspectives)
|
|
352
|
+
|
|
353
|
+
Pair prose sections with saved views. Scrolling a beat past the viewport trigger applies its view; scrolling back reverses it. A beat can also merge an `options` payload to restyle or morph `chart.type` inside one animated transition.
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
chart.storyboard.bind({
|
|
357
|
+
beats: [
|
|
358
|
+
{ selector: '[data-apex-beat="1"]', view: { window: { xaxis: { min: 0, max: 10 } } } },
|
|
359
|
+
{ selector: '[data-apex-beat="2"]', view: { collapsed: [1] }, options: { chart: { type: 'area' } } },
|
|
360
|
+
],
|
|
361
|
+
scroller: window, // Element | selector; default viewport
|
|
362
|
+
offset: 0.5, // 0..1 trigger line
|
|
363
|
+
})
|
|
364
|
+
chart.storyboard.goTo('intro', { animate: true }) // beat index or key
|
|
365
|
+
chart.storyboard.current() // { index, key } | null
|
|
366
|
+
chart.storyboard.unbind()
|
|
367
|
+
// Fires: beatChange
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Real-time streaming: constant-velocity scroll
|
|
373
|
+
|
|
374
|
+
Core (the scroll animation needs no opt-in; `chart.streaming` bounds memory).
|
|
375
|
+
|
|
376
|
+
Rolling-window updates scroll at constant velocity instead of warping in place. Any update that continues the previous window (`appendData`, or a shifted fixed-length `updateSeries`) translates smoothly.
|
|
377
|
+
|
|
378
|
+
```js
|
|
379
|
+
const options = { chart: { streaming: { enabled: true, maxPoints: 100000 } } }
|
|
380
|
+
// appendData() trims each series to maxPoints (or the visible xaxis.range window)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Drilldown: hierarchical drill-down
|
|
386
|
+
|
|
387
|
+
`import 'apexcharts/features/drilldown'` (add `import 'apexcharts/features/morph'` for animated cross-type transitions)
|
|
388
|
+
|
|
389
|
+
Data points reference a child level via a `drilldown` id; clicking drills in, with an optional breadcrumb.
|
|
390
|
+
|
|
391
|
+
```js
|
|
392
|
+
import 'apexcharts/features/drilldown'
|
|
393
|
+
import 'apexcharts/features/morph' // optional, animated type morphs
|
|
394
|
+
|
|
395
|
+
const options = {
|
|
396
|
+
series: [{ data: [
|
|
397
|
+
{ x: '2021', y: 480, drilldown: '2021' },
|
|
398
|
+
{ x: '2022', y: 530, drilldown: '2022' },
|
|
399
|
+
] }],
|
|
400
|
+
drilldown: {
|
|
401
|
+
enabled: true,
|
|
402
|
+
breadcrumb: { show: true, position: 'top-right', rootLabel: 'All Years' },
|
|
403
|
+
animation: { enabled: true, zoomFromPoint: false, speed: 260 },
|
|
404
|
+
series: [
|
|
405
|
+
{ id: '2021', name: '2021 by Channel', data: [/* ... */], chart: { type: 'bar' } },
|
|
406
|
+
],
|
|
407
|
+
// or resolve lazily:
|
|
408
|
+
onDrillDown: (ctx) => ({ id: ctx.point.drilldown, name: '...', data: [] }),
|
|
409
|
+
},
|
|
410
|
+
chart: {
|
|
411
|
+
events: {
|
|
412
|
+
drillDownStart: (info, chart, options) => {},
|
|
413
|
+
drillDownEnd: (info, chart, options) => {},
|
|
414
|
+
drillUp: (info, chart, options) => {},
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
chart.drillDown(id) // Promise
|
|
420
|
+
chart.drillUp()
|
|
421
|
+
chart.drillToRoot()
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Common Pitfalls
|
|
427
|
+
|
|
428
|
+
1. **Forgetting the feature import**: every v6 feature is off until you `import 'apexcharts/features/<name>'` (or use the full `apexcharts` bundle). Enabling the config alone does nothing if the feature isn't in the bundle.
|
|
429
|
+
2. **Using `api.zeroY` in a custom mark**: it does not exist. Use `ctx.scales.y(0)` for the baseline.
|
|
430
|
+
3. **Expecting `mode: 'filter'` on `chart.link` without records**: highlight mode needs `chart.selection.enabled: true`; the crossfilter engine needs `ApexCharts.crossfilter({ id, records })` or a `dimension` extractor.
|
|
431
|
+
4. **`largeDatasetThreshold` is under `chart.animations`**, not `chart` directly.
|
|
432
|
+
5. **Assuming the canvas renderer supports everything**: pattern/image fills and per-point selection visuals fall back to (or stay) SVG.
|