@amcharts/amcharts5-mcp 1.2.0 → 1.4.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/README.md CHANGED
@@ -10,6 +10,104 @@ Instead of loading the entire amCharts reference into the AI's context window, t
10
10
 
11
11
  ## Quick Start
12
12
 
13
+ The easiest way is the **hosted server** — no install, just add one URL. Prefer to
14
+ run it yourself? See [Local install](#local-install-npx) below.
15
+
16
+ ### Hosted (no install) — recommended
17
+
18
+ Point your AI client at:
19
+
20
+ ```
21
+ https://mcp.amcharts.com/mcp
22
+ ```
23
+
24
+ **Claude Code**
25
+
26
+ ```bash
27
+ claude mcp add --transport http amcharts5 https://mcp.amcharts.com/mcp
28
+ ```
29
+
30
+ **Claude Desktop / claude.ai** — Settings → Connectors → **Add custom connector**, then paste `https://mcp.amcharts.com/mcp`.
31
+
32
+ **Cursor** — `.cursor/mcp.json`:
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "amcharts5": {
38
+ "url": "https://mcp.amcharts.com/mcp"
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ **VS Code + GitHub Copilot** — `.vscode/mcp.json`:
45
+
46
+ ```json
47
+ {
48
+ "servers": {
49
+ "amcharts5": {
50
+ "type": "http",
51
+ "url": "https://mcp.amcharts.com/mcp"
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ **Windsurf** — `~/.codeium/windsurf/mcp_config.json`:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "amcharts5": {
63
+ "serverUrl": "https://mcp.amcharts.com/mcp"
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ **ChatGPT** (Plus/Pro/Enterprise with connectors/developer mode enabled) — Settings → **Connectors** → **Add custom connector**, then paste `https://mcp.amcharts.com/mcp`.
70
+
71
+ **Cline** (VS Code extension) — open the **MCP Servers** panel → **Remote Servers**, paste `https://mcp.amcharts.com/mcp`, or add to its MCP settings JSON:
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "amcharts5": {
77
+ "type": "streamableHttp",
78
+ "url": "https://mcp.amcharts.com/mcp"
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ **Clients that only support local (stdio) servers** (e.g. Zed, Continue, Amazon Q Developer) — bridge to the hosted URL with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote). Use this as the server's run command in the client's config:
85
+
86
+ ```bash
87
+ npx mcp-remote https://mcp.amcharts.com/mcp
88
+ ```
89
+
90
+ For example, in a `command`/`args` style config:
91
+
92
+ ```json
93
+ {
94
+ "mcpServers": {
95
+ "amcharts5": {
96
+ "command": "npx",
97
+ "args": ["-y", "mcp-remote", "https://mcp.amcharts.com/mcp"]
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ Any other MCP client that accepts a remote server URL works too — use the `/mcp`
104
+ endpoint (Streamable HTTP) or `/sse` (legacy SSE). For URL-only clients that still
105
+ expect a command, use the `mcp-remote` bridge shown above.
106
+
107
+ ## Local install (npx)
108
+
109
+ Prefer running it yourself? The server is also published to npm and runs over stdio.
110
+
13
111
  ### Claude Code
14
112
 
15
113
  For **all projects** (global, recommended):
package/content/SKILL.md CHANGED
@@ -105,7 +105,16 @@ root.dateFormatter.setAll({ dateFormat: "yyyy-MM-dd" });
105
105
  root.numberFormatter.setAll({ numberFormat: "#,###.##" });
106
106
  ```
107
107
 
108
- **Available themes:** `Animated`, `Dark`, `Frozen`, `Dataviz`, `Material`, `Moonrise`, `Spirited`, `Kelly`, `Micro`, `Responsive`.
108
+ **Available themes** (as of 5.20.0):
109
+
110
+ | Kind | Themes |
111
+ |------|--------|
112
+ | Behavioral | `Animated` (animations), `Micro` (stripped-down micro charts), `Responsive` (size-based rules) |
113
+ | Light palettes | `Dataviz`, `Frozen`, `Kelly`, `Material`, `Moonrise`, `Spirited`, `Ember`, `Nord`, `Pastel`, `Petroleum`, `Savanna`, `Colorblind` (Okabe-Ito, color-blindness safe), `Patterns` (pattern fills instead of flat colors) |
114
+ | Dark | `Dark`, `Midnight`, plus a dark variant of most palettes: `DatavizDark`, `FrozenDark`, `KellyDark`, `MaterialDark`, `MoonriseDark`, `SpiritedDark`, `NordDark`, `PastelDark`, `ColorblindDark`, `PatternsDark` |
115
+ | Parameterized (5.20.0) | `Monochrome`, `Adaptive` — see below |
116
+
117
+ Palette themes are additive: combine with `Animated`, e.g. `root.setThemes([am5themes_Animated.new(root), am5themes_Nord.new(root)])`. The `*Dark` variants already carry dark interface colors, so do NOT also add `Dark`.
109
118
 
110
119
  ## Colors
111
120
 
@@ -458,6 +467,39 @@ series.columns.template.states.create("active", {
458
467
  // State animation: stateAnimationDuration, stateAnimationEasing
459
468
  ```
460
469
 
470
+ ## Parameterized themes — Monochrome & Adaptive (5.20.0)
471
+
472
+ Two themes generate their palette from colors you pass in (OKLCH-based, so the result stays perceptually balanced). Because a theme cannot take constructor parameters, these ship as **factory functions** — call them with `(root, settings)`; `.new(root, settings)` also works.
473
+
474
+ ```js
475
+ import am5themes_Monochrome from "@amcharts/amcharts5/themes/Monochrome";
476
+ import am5themes_Adaptive from "@amcharts/amcharts5/themes/Adaptive";
477
+
478
+ // Monochrome — single-hue lightness ramp
479
+ root.setThemes([
480
+ am5themes_Animated.new(root),
481
+ am5themes_Monochrome(root, {
482
+ color: 0x2c6e91, // base hue (default: blue #2e7c9e)
483
+ accent: 0xff7f0e, // optional — applied to the FIRST series only, so it pops
484
+ count: 7, // steps in the ramp (default 7)
485
+ dark: false // true = dark background + light-to-mid ramp
486
+ })
487
+ ]);
488
+
489
+ // Adaptive — full palette generated from one or two base colors
490
+ root.setThemes([
491
+ am5themes_Animated.new(root),
492
+ am5themes_Adaptive(root, {
493
+ baseColor: 0x2c6e91, // first generated color IS this color (good for brand colors)
494
+ baseColor2: 0xffdd00, // optional — palette spans the two colors
495
+ count: 10, // number of series colors (default 10)
496
+ dark: false
497
+ })
498
+ ]);
499
+ ```
500
+
501
+ Both are additive (they do not modify built-in themes) and both handle dark mode themselves via `dark: true` — do not also add the `Dark` theme.
502
+
461
503
  ## Custom themes
462
504
 
463
505
  ```js
@@ -660,7 +702,7 @@ onUnmounted(() => { root.dispose(); });
660
702
  12. **CDN script load order** — `index.js` must load first, then `xy.js`, then any package that depends on it (`radar.js`, `timeline.js`, `gantt.js`). Wrong order causes runtime errors. Correct order: `index.js` → `xy.js` → `radar.js` / `timeline.js` / `gantt.js` → `themes/*.js`.
661
703
  13. **No `minorGrid` / `minorTicks` / `minorLabels` objects** — These do not exist on axes. Minor grid is enabled via boolean flags on the **renderer**: `minorGridEnabled: true` and optionally `minorLabelsEnabled: true`. Styling is done through theme rules targeting the `"minor"` tag, not through separate object properties.
662
704
  14. **Flow chart animated bullets go on `series.bullets`, NOT `series.links.template.bullets`** — To animate labels/circles flowing along Sankey or Chord links, use `series.bullets.push(function(...) { ... })`. Animate `bullet.locationX` (Sankey) or `bullet.locationY` (Chord) from 0→1 with `loops: Infinity`. Use an adapter on opacity for fade effect. See `references/flow.md` → "Animated bullets along links".
663
- 15. **`MapPointSeries` needs `latitudeField`/`longitudeField` when using `data.setAll()`** — If point data has `latitude`/`longitude` fields, the series must declare them: `am5map.MapPointSeries.new(root, { latitudeField: "latitude", longitudeField: "longitude" })`. Without these, points silently won't appear. This is NOT needed when using `pushDataItem({ latitude: ..., longitude: ... })` which passes coordinates directly.
705
+ 15. **`MapPointSeries` needs `latitudeField`/`longitudeField` when your data fields are named anything other than `latitude`/`longitude`** — Since 5.16.1 the series defaults to `latitudeField: "latitude"`, `longitudeField: "longitude"`, so data using exactly those names works with no declaration. Any other naming (`lat`/`lng`, `y`/`x`, …) must be declared or the points silently won't appear: `am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "lng" })`. Neither is needed with `pushDataItem({ latitude: ..., longitude: ... })`, which passes coordinates directly. On amCharts **older than 5.16.1** there were no defaults, so declare the fields explicitly if you must support those versions.
664
706
  16. **`data.setAll()` does NOT animate — use `data.setIndex()` for animated updates** — When the user asks to update/refresh data with animation, do NOT use `series.data.setAll(newData)` — it replaces everything instantly with no transition. Instead, update each item with `series.data.setIndex(i, newItem)` which triggers smooth value animation. For full replacement with animation, loop: `newData.forEach(function(item, i) { series.data.setIndex(i, item); })`.
665
707
  17. **`color.lighten()` / `color.darken()` are NOT instance methods** — `am5.color(0xff0000).lighten(0.3)` does NOT work. Use static methods: `am5.Color.lighten(color, 0.3)` to lighten, `am5.Color.lighten(color, -0.3)` to darken. There is NO `darken()` method — use negative lighten. Also available: `am5.Color.brighten()`, `am5.Color.saturate()`.
666
708
  18. **Venn diagram has no `VennDiagram` class** — `am5venn.Venn` is pushed directly into a `Container`, NOT into a chart's `series`. See `references/venn.md`.
@@ -716,7 +758,7 @@ Skip this step entirely if you cannot execute code (e.g., chat-only context with
716
758
 
717
759
  ## Recent API changes (newer than the bundled class reference)
718
760
 
719
- The bundled per-class API reference was snapshotted on **2026-03-15**, so it predates the changes below. Prefer these names/settings; for anything newer, verify against the live docs (see next section).
761
+ The bundled per-class API reference was snapshotted on **2026-03-15**, so it predates the changes below. Latest release covered here: **5.20.1** (2026-08-03). Prefer these names/settings; for anything newer, verify against the live docs (see next section).
720
762
 
721
763
  **Renamed settings (old name still works but is deprecated — use the new one):**
722
764
 
@@ -731,14 +773,50 @@ am5stock.MovingAverage.new(root, { maType: "exponential", period: 20 });
731
773
  am5hierarchy.VoronoiTreemap.new(root, { shapeType: "rectangle" }); // was: type
732
774
  ```
733
775
 
776
+ **Breaking change — WordCloud internals (5.20.1):** the layout is now computed synchronously in one pass (much faster). The per-data-item `ghostLabel` is gone and labels live in an internal container, so `dataItem.get("ghostLabel")` and any code walking `series.children` to find labels must be updated — use `series.labels` / `dataItem.get("label")` instead.
777
+
734
778
  **New settings / methods worth knowing:**
779
+
780
+ *Themes & styling*
781
+ - 20+ new themes (5.20.0): `Midnight`, `Ember`, `Nord`, `Pastel`, `Colorblind`, `Patterns`, `Petroleum`, `Savanna`, plus `*Dark` variants of most palettes. Two parameterized factory themes, `Monochrome` and `Adaptive` — see "Parameterized themes" above.
782
+ - New fill patterns (5.20.0): `am5.StarPattern` (`radius`, `innerRadius`, `spikes`, `gap`, `checkered`) and `am5.TrianglePattern` (`maxWidth`, `maxHeight`, `gap`, `checkered`).
783
+ - `rotateShapes` (5.20.0) on `RectanglePattern`/`StarPattern`/`TrianglePattern`: `rotation` then spins each shape around its own center instead of the whole grid — tiles seamlessly and is much faster. Prefer it over a whole-pattern `rotation` on large tiles.
784
+ - `Series`: `fillGradient` / `strokeGradient` settings. A bullet `Graphics` with no paint of its own (`fill`, `fillGradient`, `fillPattern`, `stroke`, `strokeGradient`) now inherits all of them from its series — and on pie, funnel, flow and hierarchy charts, from its own slice/node (5.20.0–5.20.1).
785
+
786
+ *XY charts*
787
+ - `XYChart`: `strokeWidths` (array of pixel widths) and `strokeDasharrays` (array of dash arrays) — cycled across line series as they are added, exactly like `colors`. Lets series be told apart without relying on color, e.g. with the `Patterns` theme.
788
+ - `XYCursor`: `clickTolerance` (default `0`) — how many pixels outside the plot area a press may start and still begin a zoom/selection. The selection itself still starts at the plot edge.
789
+ - `XYSeries`: a value field (`valueYField`, `openValueYField`, …) can now be changed after creation — re-set the series data afterwards for it to take effect. A series can also be reassigned to a different `xAxis`/`yAxis` after creation.
790
+
791
+ *WordCloud (5.20.1)*
792
+ - `svgPath` arranges words into a shape (experimental), with `maskByShape` to clip them to the outline and `shapeTolerance` to control spill (negative = padding inside). See `references/wordcloud.md`.
793
+ - `randomizeAngles: false` cycles `angles` in order for a reproducible layout; `allowNesting: false` packs words as non-overlapping bounding boxes (use it when labels have opaque backgrounds).
794
+ - `angles` now accepts **any** angle (e.g. `[0, -30, -45]`). Before 5.20.1 only `0`/`±90` were handled, and the old docs said so explicitly — that restriction is gone.
795
+
796
+ *Core / events*
797
+ - New `globalpointerdown` event on all elements — fires on a press anywhere on the chart surface, mirroring `globalpointermove`/`globalpointerup`.
798
+ - `Root`: `sanitizeHTML` (5.19.0, default `true`) — dynamically-set HTML (`html`/`labelHTML`, HTML tooltips, modal content) is sanitized; set `false` to opt out. Exports gained `escapeFormulas` (default `true`) to guard CSV/XLSX against formula injection.
799
+ - `Root`: `ariaLabel` is now applied to the `<div>` holding the chart's focusable elements (5.20.0).
800
+ - `Label`: `oversizedBehavior: "truncate"` now ignores `maxHeight` (there is no way to truncate text vertically).
801
+ - A `Container`'s `Rectangle`/`RoundedRectangle` background now defaults `crisp` to `true` unless set explicitly (5.20.0).
802
+
803
+ *Maps*
804
+ - `MapChart`: `projectionName` (5.19.0) — string alternative to `projection`, e.g. `"geoOrthographic"`, mainly for JSON config. Register extra ones with `am5map.registerProjection()`. Bundled projections are no longer eagerly imported, so unused ones tree-shake away.
805
+ - `MapSankeySeries` (5.17.0) — Sankey overlaid on a map; auto-resolves `sourceId`/`targetId` once `polygonSeries` geoJSON loads (5.17.1), so no `datavalidated` wrapper needed. See `references/map.md`.
806
+ - `MapPointSeries` defaults changed to `longitudeField: "longitude"`, `latitudeField: "latitude"` (5.16.1).
807
+
808
+ *Hierarchy & axes*
735
809
  - `Tree`: `fitNodes` (5.18.0, exclude hidden nodes from layout), `nodeSeparation` (5.16.2, custom node-spacing fn), `clustered` (5.16.2, dendrogram layout — leaves at same depth).
736
810
  - `ValueAxis`: `syncZeros` (5.16.2, align zero across synced axes — needs `syncWithAxis`).
737
811
  - `Hierarchy`: `parentIdField` setting + `setFlatData(data)` method (5.16.2) — feed flat `{id, parentId}` data instead of nested `children`.
738
- - All entities: `onDebounced(key, cb, delay)` / `offDebounced(key, cb?)` and `onPrivateDebounced` / `offDebouncedPrivate` (5.17.3) — fire once after rapid changes settle.
812
+
813
+ *Stock*
814
+ - Indicator numeric settings now enforce min/max limits, so extreme values can no longer freeze the page. `IIndicatorEditableSetting` gained `scale`, `maxValue` and `step` (5.20.0).
815
+ - Volume Profile now spreads each bar's volume across its full high/low range instead of placing it all at the close. Several indicator math fixes (Williams %R, Momentum, RSI, Moving Average Cross defaults, Commodity Channel Index) landed in 5.19.0–5.20.0 — see `references/stock.md`.
816
+
817
+ *All entities*
818
+ - `onDebounced(key, cb, delay)` / `offDebounced(key, cb?)` and `onPrivateDebounced` / `offDebouncedPrivate` (5.17.3) — fire once after rapid changes settle.
739
819
  - `Label`: `fontFamily: "inherit"` (5.17.3) uses the chart container's computed font.
740
- - `MapSankeySeries` (5.17.0) — Sankey overlaid on a map; auto-resolves `sourceId`/`targetId` once `polygonSeries` geoJSON loads (5.17.1), so no `datavalidated` wrapper needed. See `references/map.md`.
741
- - `MapPointSeries` defaults changed to `longitudeField: "longitude"`, `latitudeField: "latitude"` (5.16.1).
742
820
 
743
821
  ## Verify unfamiliar API before using it
744
822
 
package/content/gantt.md CHANGED
@@ -47,10 +47,10 @@ var chart = root.container.children.push(
47
47
  | `editable` | boolean | `true` | Allow user to add, edit, remove, drag tasks |
48
48
  | `durationUnit` | string | `"day"` | `"year"`, `"month"`, `"week"`, `"day"`, `"hour"`, `"minute"`, `"second"` |
49
49
  | `weekends` | number[] | `[0, 6]` | Non-working days (0=Sun, 1=Mon, ... 6=Sat) |
50
- | `excludeWeekends` | boolean | `true` | Whether to exclude weekends from task durations |
50
+ | `excludeWeekends` | boolean | `false` | Whether to exclude weekends from task durations |
51
51
  | `holidays` | Date[] | `[]` | Specific non-working dates |
52
52
  | `snapThreshold` | number | `0.5` | Drag snap position within a period (0–1) |
53
- | `sidebarWidth` | number | — | Sidebar width in pixels or Percent |
53
+ | `sidebarWidth` | number \| Percent | `30%` | Sidebar width in pixels or Percent |
54
54
 
55
55
  ## Data structure
56
56
 
@@ -134,7 +134,7 @@ Set `duration: 0` to create milestone markers.
134
134
  ```js
135
135
  chart.yAxis.setAll({
136
136
  minCellHeight: 80, // row height in pixels (default: 70)
137
- childCellSize: 1, // child row size relative to parent (default: 0.7, 1 = same)
137
+ childCellSize: 1, // child row size relative to parent (default: 0.8, 1 = same)
138
138
  childShift: 0 // child label indent in pixels (default: 25)
139
139
  });
140
140
  ```
package/content/map.md CHANGED
@@ -166,7 +166,9 @@ pointSeries.bullets.push(function() {
166
166
  });
167
167
  });
168
168
 
169
- // Add points via data — requires latitudeField/longitudeField on the series
169
+ // Add points via data. Fields named "latitude"/"longitude" are the series
170
+ // defaults since 5.16.1; any other naming must be declared via
171
+ // latitudeField/longitudeField or the points silently won't render.
170
172
  pointSeries.data.setAll([
171
173
  { latitude: 48.8566, longitude: 2.3522, name: "Paris" },
172
174
  { latitude: 40.7128, longitude: -74.0060, name: "New York" },
package/content/stock.md CHANGED
@@ -185,7 +185,10 @@ stockChart.indicators.push(am5stock.MovingAverage.new(root, {
185
185
  stockSeries: valueSeries,
186
186
  legend: legend,
187
187
  period: 20,
188
- type: "simple" // "simple", "weighted", "exponential", "dema", "tema"
188
+ maType: "simple" // "simple", "weighted", "exponential", "dema", "tema"
189
+ // NOTE: `type` was renamed to `maType` in 5.18.0 — `type` still
190
+ // works but is deprecated. Same for MovingAverageDeviation,
191
+ // MovingAverageEnvelope and BollingerBands.
189
192
  }));
190
193
 
191
194
  // RSI (creates its own panel)
@@ -216,7 +219,7 @@ stockChart.indicators.push(am5stock.Volume.new(root, {
216
219
  | Indicator | Class | Needs volumeSeries |
217
220
  |-----------|-------|--------------------|
218
221
  | Moving Average | `MovingAverage` | No |
219
- | Moving Average Cross | `MovingAverageCross` | No |
222
+ | Moving Average Cross | `MACross` | No |
220
223
  | Moving Average Envelope | `MovingAverageEnvelope` | No |
221
224
  | Moving Average Deviation | `MovingAverageDeviation` | No |
222
225
  | Bollinger Bands | `BollingerBands` | No |
@@ -244,6 +247,43 @@ stockChart.indicators.push(am5stock.Volume.new(root, {
244
247
 
245
248
  All classes are under `am5stock.*` (e.g., `am5stock.BollingerBands`).
246
249
 
250
+ ### Indicator changes in 5.19.0–5.20.0
251
+
252
+ Several indicators changed behavior. If you have hardcoded expectations or saved settings, re-check them:
253
+
254
+ | Indicator | Change | Version |
255
+ |-----------|--------|---------|
256
+ | `VolumeProfile` | Each bar's volume is now distributed across the full high/low range it traded, instead of being placed entirely at the closing price. Also no longer errors in `ticks` count mode when the visible price range is flat. | 5.20.0 |
257
+ | `MACross` | Default fast/slow periods were inverted; defaults are now `fastPeriod: 9`, `period: 21`. | 5.20.0 |
258
+ | `WilliamsR` | Used a `period + 1` lookback and treated a missing high/low as `0`; now uses exactly `period` bars. | 5.20.0 |
259
+ | `Momentum` | Skipped its first computable value; now plots from `period` bars onward. | 5.20.0 |
260
+ | `RelativeStrengthIndex` | Returned `0` (max "oversold") for a perfectly flat market; now returns a neutral `50`. | 5.20.0 |
261
+ | `AccelerationBands` | `factor` now displays as the conventional `1` instead of `0.001` in both the settings modal and the legend; upper/lower bands were swapped so `upperColor`/`lowerColor` apply correctly. | 5.20.0–5.20.1 |
262
+ | `CommodityChannelIndex` | Typical price was computed as `(high + low + close) / 2` instead of `/ 3`, inflating values. | 5.19.0 |
263
+
264
+ All indicators now enforce min/max limits on their numeric settings, so extreme values entered in the settings modal can no longer freeze the page (e.g. a Volume Profile row count of 24,000).
265
+
266
+ ### Custom indicator editable settings (5.20.0)
267
+
268
+ `IIndicatorEditableSetting` gained three properties for the settings modal:
269
+
270
+ ```js
271
+ _editableSettings: [{
272
+ key: "period",
273
+ name: "Period",
274
+ type: "number",
275
+ minValue: 1,
276
+ maxValue: 200, // 5.20.0 — upper bound enforced by the input
277
+ step: 1 // 5.20.0 — step; a step of 1 also marks the value as an integer
278
+ }, {
279
+ key: "factor",
280
+ name: "Factor",
281
+ type: "number",
282
+ scale: 1000 // 5.20.0 — display multiplier for the modal ONLY:
283
+ // shown value = stored × scale, divided back on save
284
+ }]
285
+ ```
286
+
247
287
  ## Data format
248
288
 
249
289
  ```js
@@ -281,8 +321,9 @@ var data = [
281
321
  ## Events
282
322
 
283
323
  ```js
284
- // Period changed
285
- stockChart.events.on("periodselected", (ev) => {
324
+ // Period changed — the `periodselected` event fires on the PeriodSelector
325
+ // instance, NOT on stockChart. Attach the handler to the selector you created.
326
+ periodSelector.events.on("periodselected", (ev) => {
286
327
  console.log("Period:", ev.period);
287
328
  });
288
329
 
@@ -48,20 +48,24 @@ const chart = root.container.children.push(
48
48
  am5timeline.SerpentineChart.new(root, {
49
49
  orientation: "vertical", // "vertical" | "horizontal"
50
50
  levelCount: 3, // number of bends/turns
51
- yAxisRadius: am5.percent(25), // curve thickness
52
- yAxisInnerRadius: -25, // inner radius (negative = percentage of radius)
51
+ startLocation: 0, // relative start of the "road" (0-1)
52
+ endLocation: 1, // relative end of the "road" (0-1)
53
+ yAxisRadius: am5.percent(50), // band thickness (Percent); applied to the Y axes' radius
53
54
  })
54
55
  );
55
56
  ```
56
57
 
57
- **Serpentine settings:**
58
+ **Serpentine settings** (`ISerpentineChartSettings`):
58
59
 
59
- | Setting | Type | Description |
60
- |---------|------|-------------|
61
- | `orientation` | `"vertical"` \| `"horizontal"` | Direction of the snake pattern |
62
- | `levelCount` | number | Number of turns/bends |
63
- | `yAxisRadius` | percent/number | Outer radius of the curve |
64
- | `yAxisInnerRadius` | number | Inner radius (0 = filled, negative = relative) |
60
+ | Setting | Type | Default | Description |
61
+ |---------|------|---------|-------------|
62
+ | `orientation` | `"vertical"` \| `"horizontal"` | `"vertical"` | Direction of the snake pattern |
63
+ | `levelCount` | number | `3` | Number of turns/bends |
64
+ | `startLocation` | number | `0` | Relative location (0-1) of the start |
65
+ | `endLocation` | number | `1` | Relative location (0-1) of the end |
66
+ | `yAxisRadius` | `Percent` | `50%` | Band thickness — applied to every Y axis renderer's radius |
67
+
68
+ > There is no `yAxisInnerRadius` setting on the chart. Band thickness is controlled by `yAxisRadius` (a `Percent`). For a plain `CurveChart` (no Serpentine/Spiral wrapper) the Y-axis band length is set via `AxisRendererCurveY`'s `axisLength` instead.
65
69
 
66
70
  ### SpiralChart
67
71
 
@@ -71,23 +75,25 @@ Wraps the chart into a spiral shape.
71
75
  const chart = root.container.children.push(
72
76
  am5timeline.SpiralChart.new(root, {
73
77
  levelCount: 3, // number of spiral rings
74
- inversed: true, // spiral direction
78
+ startAngle: -90, // start angle in degrees
75
79
  endAngle: -135, // end angle in degrees
76
- yAxisRadius: am5.percent(70),
77
- yAxisInnerRadius: 0,
78
- innerRadius: am5.percent(30), // inner hole radius
80
+ yAxisRadius: am5.percent(60), // band thickness (Percent)
81
+ innerRadius: am5.percent(30), // inner hole radius (Percent)
79
82
  })
80
83
  );
81
84
  ```
82
85
 
83
- **Spiral settings:**
86
+ **Spiral settings** (`ISpiralChartSettings`):
87
+
88
+ | Setting | Type | Default | Description |
89
+ |---------|------|---------|-------------|
90
+ | `levelCount` | number | `3` | Number of spiral rings |
91
+ | `startAngle` | number | `-90` | Where the spiral starts (degrees) |
92
+ | `endAngle` | number | `0` | Where the spiral ends (degrees) |
93
+ | `innerRadius` | `Percent` | `60%` | Size of the center hole |
94
+ | `yAxisRadius` | `Percent` | `50%` | Band thickness — applied to every Y axis renderer's radius |
84
95
 
85
- | Setting | Type | Description |
86
- |---------|------|-------------|
87
- | `levelCount` | number | Number of spiral rings |
88
- | `inversed` | boolean | Spiral direction |
89
- | `endAngle` | number | Where the spiral ends (degrees) |
90
- | `innerRadius` | percent/number | Size of the center hole |
96
+ > There is no `inversed` or `yAxisInnerRadius` setting on `SpiralChart`. To reverse direction use the `startAngle`/`endAngle` pair. (`inversed` is a valid axis-renderer setting, but not a chart setting.)
91
97
 
92
98
  ### CurveChart
93
99
 
@@ -306,8 +312,7 @@ chart.get("cursor").events.on("cursormoved", function(ev) {
306
312
  am5timeline.SerpentineChart.new(root, {
307
313
  orientation: "vertical",
308
314
  levelCount: 3,
309
- yAxisRadius: am5.percent(25),
310
- yAxisInnerRadius: -25
315
+ yAxisRadius: am5.percent(50)
311
316
  })
312
317
  );
313
318
 
@@ -399,10 +404,9 @@ chart.get("cursor").events.on("cursormoved", function(ev) {
399
404
  var chart = root.container.children.push(
400
405
  am5timeline.SpiralChart.new(root, {
401
406
  levelCount: 3,
402
- inversed: true,
407
+ startAngle: -90,
403
408
  endAngle: -135,
404
- yAxisRadius: am5.percent(70),
405
- yAxisInnerRadius: 0,
409
+ yAxisRadius: am5.percent(60),
406
410
  innerRadius: am5.percent(30)
407
411
  })
408
412
  );
@@ -81,14 +81,16 @@ button.get("background").states.create("down", {
81
81
  ### Togglable button
82
82
 
83
83
  ```js
84
+ // There is no `togglable` setting on Button. Make it a toggle by setting
85
+ // `toggleKey: "active"` (a Sprite setting) — clicks then flip the `active` boolean.
84
86
  var button = container.children.push(am5.Button.new(root, {
85
- togglable: true,
87
+ toggleKey: "active",
86
88
  label: am5.Label.new(root, { text: "Toggle" })
87
89
  }));
88
90
 
89
- // Check active state
91
+ // Check active state via the `active` setting (there is no isActive() method)
90
92
  button.events.on("click", function(ev) {
91
- var isActive = ev.target.isActive();
93
+ var isActive = ev.target.get("active");
92
94
  console.log("Active:", isActive);
93
95
  });
94
96
  ```
@@ -57,15 +57,27 @@ series.appear(1000);
57
57
  |---------|------|---------|-------------|
58
58
  | `categoryField` | string | — | Data field for word text (required) |
59
59
  | `valueField` | string | — | Data field for word weight/size (required) |
60
- | `maxFontSize` | percent/number | `am5.percent(20)` | Maximum font size |
61
- | `minFontSize` | percent/number | `am5.percent(2)` | Minimum font size |
62
- | `angles` | number[] | `[0, -90]` | Allowed rotation angles for words |
63
- | `randomness` | number (0–1) | `0.2` | Layout randomness (0 = ordered by value, 1 = fully random) |
60
+ | `maxFontSize` | number \| Percent | `am5.percent(15)` | Maximum font size (a `Percent` is relative to the smaller chart dimension) |
61
+ | `minFontSize` | number \| Percent | `am5.percent(2)` | Minimum font size (a `Percent` is relative to the smaller chart dimension) |
62
+ | `angles` | number[] | `[0, -90]` | Allowed rotation angles for words. **Any angle works** as of 5.20.1 (e.g. `[0, -30, -45]`), not just `0`/`±90` as in earlier versions |
63
+ | `randomizeAngles` | boolean | `true` | `true` = each word picks a random angle from `angles`. `false` = words cycle through `angles` in order (word 0 → `angles[0]`, …) which, with `randomness: 0`, makes the layout reproducible. *(5.20.1)* |
64
+ | `randomness` | number (0–1) | `0` | Layout randomness (0 = ordered by value, 1 = fully random) |
65
+ | `allowNesting` | boolean | `true` | `true` = small words tuck into the concavities of bigger ones (tight packing, bounding boxes may overlap). `false` = whole bounding boxes are packed so they never overlap — use this when labels have an opaque `background`. *(5.20.1)* |
64
66
  | `minWordLength` | number | `1` | Skip words shorter than this |
67
+ | `minValue` | number | — | Skip words occurring fewer times than this |
65
68
  | `maxCount` | number | — | Maximum number of words to display |
66
69
  | `excludeWords` | string[] | `[]` | Words to exclude |
67
70
  | `text` | string | — | Raw text to parse — words are extracted and weighted by frequency automatically |
68
71
  | `colors` | ColorSet | — | Color set for words |
72
+ | `fillField` | string | — | Data field holding a per-word label fill color |
73
+ | `autoFit` | boolean | `true` | Scale font sizes down so all words fit the available area |
74
+ | `step` | number | `15` | Step size used when searching for the next word placement |
75
+ | `svgPath` | string | — | Arrange words to fill this SVG path shape (experimental) *(5.20.1)* |
76
+ | `maskByShape` | boolean | `false` | Clip words to the `svgPath` outline for a crisp silhouette. Requires `svgPath`. *(5.20.1)* |
77
+ | `shapeTolerance` | number | `0` | Extra pixels a word may spill past the `svgPath` outline; negative pulls words inside, creating padding. Requires `svgPath`. *(5.20.1)* |
78
+ | `animationDuration` | number | — | Duration of word animation on chart resize |
79
+ | `sequencedInterpolation` | boolean | `true` | Stagger the word reveal instead of showing all at once |
80
+ | `sequencedDelay` | number | `15` | Milliseconds between words when `sequencedInterpolation` is on |
69
81
 
70
82
  ### excludeWords example
71
83
 
@@ -77,7 +89,81 @@ am5wc.WordCloud.new(root, {
77
89
  });
78
90
  ```
79
91
 
80
- **Note:** amCharts WordCloud does not support mask/shape rendering (words constrained to a custom shape). Words are arranged in a rectangular area.
92
+ ## Shaped word clouds — `svgPath` (5.20.1)
93
+
94
+ Words can be arranged to fill an arbitrary shape. The path is scaled proportionally to fit the plot area.
95
+
96
+ ```js
97
+ var series = root.container.children.push(
98
+ am5wc.WordCloud.new(root, {
99
+ categoryField: "tag",
100
+ valueField: "weight",
101
+ svgPath: "M10,30 A20,20 0,0,1 50,30 A20,20 0,0,1 90,30 Q90,60 50,90 Q10,60 10,30 z", // heart
102
+ maskByShape: true, // clip letters that overhang the outline
103
+ shapeTolerance: -4, // negative = padding inside the shape
104
+ angles: [0], // simple shapes fill better with fewer angles
105
+ minFontSize: am5.percent(2),
106
+ maxFontSize: am5.percent(12)
107
+ })
108
+ );
109
+ ```
110
+
111
+ The shape outline itself is drawn behind the words as `series.shape` (a `Graphics`), by default a faint 10%-opacity silhouette. Style or hide it:
112
+
113
+ ```js
114
+ series.shape.setAll({ fill: am5.color(0xff3366), fillOpacity: 0.08 });
115
+ series.shape.set("fillOpacity", 0); // no visible silhouette, words only
116
+ ```
117
+
118
+ Style `fill`/`stroke` only — the series manages the shape's geometry (`svgPath`, `scale`, `x`, `y`) and its `forceHidden` flag, so setting those is pointless. To hide the silhouette use `fillOpacity: 0`.
119
+
120
+ **Caveats:** this is an experimental feature and the fit is approximate. Favor simple, bold shapes over thin or highly concave ones, and tune `shapeTolerance`, `maskByShape`, `angles`, `minFontSize`/`maxFontSize` per shape. `shapeTolerance` affects placement only — the drawn outline never moves.
121
+
122
+ ## Diagonal angles (5.20.1)
123
+
124
+ Before 5.20.1 only `0`, `90` and `-90` were handled. The layout rewrite rasterizes each word and its collision mask at the word's actual angle, so arbitrary angles now work — and neighbors pack into the corners of a rotated word's footprint instead of reserving its full axis-aligned bounding box.
125
+
126
+ ```js
127
+ am5wc.WordCloud.new(root, {
128
+ categoryField: "tag",
129
+ valueField: "weight",
130
+ angles: [0, -30, -45, -60, -90]
131
+ });
132
+ ```
133
+
134
+ One caveat: if a word comes out very wide relative to the available area, the layout flips it to `0` or `±90` for a better fit — but only when that value is present in your `angles` array. Leave them out and your angles are used as given.
135
+
136
+ ## Reproducible layouts
137
+
138
+ By default word placement is randomized, so the cloud looks different on every render. For a stable layout:
139
+
140
+ ```js
141
+ am5wc.WordCloud.new(root, {
142
+ categoryField: "tag",
143
+ valueField: "weight",
144
+ randomness: 0, // order strictly by value
145
+ randomizeAngles: false // cycle `angles` in order instead of picking randomly
146
+ });
147
+ ```
148
+
149
+ ## Labels with opaque backgrounds
150
+
151
+ Nesting lets small words sit inside the gaps of larger ones, which looks wrong once labels have a solid background — the background rectangles slide over neighbors. Turn nesting off so whole bounding boxes are packed:
152
+
153
+ ```js
154
+ series.set("allowNesting", false);
155
+ series.labels.template.setAll({
156
+ background: am5.RoundedRectangle.new(root, { fill: am5.color(0x1f2933), fillOpacity: 1 })
157
+ });
158
+ ```
159
+
160
+ ## Breaking change in 5.20.1
161
+
162
+ The layout is now computed synchronously in a single pass instead of one word per animation frame — much faster for large clouds. Consequences for existing code:
163
+
164
+ - The per-data-item `ghostLabel` no longer exists — `dataItem.get("ghostLabel")` returns `undefined`.
165
+ - Labels are held in an internal container, so code walking `series.children` to find labels breaks. Use `series.labels` (the `ListTemplate`) or `dataItem.get("label")`.
166
+ - The reveal is staggered via `sequencedInterpolation`/`sequencedDelay` (defaults `true` / `15`ms) rather than by the layout itself.
81
167
 
82
168
  ## Customizing labels
83
169
 
package/content/xy.md CHANGED
@@ -382,6 +382,17 @@ chart.set("cursor", am5xy.XYCursor.new(root, { snapToSeries: [series] }));
382
382
 
383
383
  **Do NOT** pass `lineX`/`lineY` as constructor options to `XYCursor.new()`. Always access `cursor.lineX` / `cursor.lineY` after creation.
384
384
 
385
+ **Easier edge selections (`clickTolerance`, 5.20.0)** — by default a zoom/select drag can only begin inside the plot area, which makes selecting right up to an edge fiddly. `clickTolerance` widens the area where a press may *start*:
386
+
387
+ ```js
388
+ chart.set("cursor", am5xy.XYCursor.new(root, {
389
+ behavior: "selectX",
390
+ clickTolerance: 20 // px outside the plot area where a drag may start (default 0)
391
+ }));
392
+ ```
393
+
394
+ The selection itself still starts at the plot edge — the press point is clamped into the plot area.
395
+
385
396
  For timeline charts, use `am5timeline.CurveCursor` instead — see `references/timeline.md`.
386
397
 
387
398
  ## Scrollbar
@@ -670,11 +681,50 @@ am5xy.XYChart.new(root, {
670
681
  wheelX: "panX", // mouse wheel: "panX", "panY", "zoomX", "zoomY", "none"
671
682
  wheelY: "zoomX", // mouse wheel vertical
672
683
  pinchZoomX: true, // mobile pinch zoom on X
673
- arrangeFields: false, // auto-arrange overlapping fields
684
+ arrangeTooltips: true, // de-overlap stacked series tooltips (NOTE: there is no `arrangeFields` setting)
674
685
  maxTooltipDistance: 0, // show tooltips for nearby series (-1 = all)
675
686
  })
676
687
  ```
677
688
 
689
+ ## Distinguishing line series without color (5.20.0)
690
+
691
+ `XYChart` can cycle stroke widths and dash patterns across line series as they are added, exactly the way `colors` cycles series colors. Useful for print, for color-blind-safe output, or with the `Patterns` theme.
692
+
693
+ ```js
694
+ const chart = root.container.children.push(am5xy.XYChart.new(root, {
695
+ strokeWidths: [3, 2, 2], // px, cycled per line series
696
+ strokeDasharrays: [0, [6, 3], [2, 2]] // 0 or [] = solid line
697
+ }));
698
+ ```
699
+
700
+ Each added line series takes the next entry by position, wrapping around when the array runs out.
701
+
702
+ ## Series gradients (5.20.0)
703
+
704
+ `Series` accepts `fillGradient` and `strokeGradient`:
705
+
706
+ ```js
707
+ series.set("fillGradient", am5.LinearGradient.new(root, {
708
+ stops: [{ opacity: 0.6 }, { opacity: 0 }],
709
+ rotation: 90
710
+ }));
711
+ ```
712
+
713
+ A bullet `Graphics` that sets none of `fill`, `fillGradient`, `fillPattern`, `stroke`, `strokeGradient` now inherits all of them from its series, so bullets pick up series gradients and patterns automatically.
714
+
715
+ ## Changing fields and axes after creation (5.20.0)
716
+
717
+ ```js
718
+ // Swap which data field a series plots — then re-set the data
719
+ series.set("valueYField", "profit");
720
+ series.data.setAll(data);
721
+
722
+ // Move a series to a different axis
723
+ series.set("yAxis", secondaryYAxis);
724
+ ```
725
+
726
+ Both were previously fixed at creation time. Re-setting the series data is required for a value-field change to take effect.
727
+
678
728
  ---
679
729
 
680
730
  # amCharts 5 XY Charts — Working Examples