@amcharts/amcharts5-mcp 1.3.2 → 1.5.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.
Files changed (42) hide show
  1. package/content/SKILL.md +166 -8
  2. package/content/flow.md +4 -0
  3. package/content/hierarchy.md +21 -0
  4. package/content/map.md +75 -9
  5. package/content/pie.md +16 -0
  6. package/content/radar.md +1 -1
  7. package/content/stock.md +41 -1
  8. package/content/timeline.md +3 -3
  9. package/content/venn.md +4 -0
  10. package/content/wordcloud.md +92 -4
  11. package/content/xy.md +67 -1
  12. package/extended/charts/word-cloud.md +19 -3
  13. package/extended/concepts/colors-gradients-and-patterns/patterns.md +53 -0
  14. package/extended/concepts/events.md +32 -0
  15. package/extended/concepts/serializing/chart-serializer.md +17 -2
  16. package/extended/concepts/serializing.md +14 -0
  17. package/extended/concepts/themes.md +91 -0
  18. package/extended/reference/ibasecolumnseriesdataitem.md +1 -0
  19. package/extended/reference/ibasecolumnseriessettings.md +2 -0
  20. package/extended/reference/ichartserializersettings.md +1 -0
  21. package/extended/reference/imapchartsettings.md +2 -0
  22. package/extended/reference/imaplineseriesdataitem.md +1 -0
  23. package/extended/reference/imaplineseriessettings.md +2 -0
  24. package/extended/reference/iparsesettings.md +9 -3
  25. package/extended/reference/irectanglepatternsettings.md +1 -0
  26. package/extended/reference/irootsettings.md +4 -0
  27. package/extended/reference/iscrollbarsettings.md +1 -0
  28. package/extended/reference/iserialchartcontainersettings.md +16 -0
  29. package/extended/reference/iseriessettings.md +2 -0
  30. package/extended/reference/istarpatternsettings.md +38 -0
  31. package/extended/reference/itrianglepatternsettings.md +37 -0
  32. package/extended/reference/iwordcloudsettings.md +24 -8
  33. package/extended/reference/ixychartsettings.md +2 -0
  34. package/extended/reference/ixycursorsettings.md +1 -0
  35. package/extended/reference/mapchart.md +4 -0
  36. package/extended/reference/serialchart.md +1 -1
  37. package/extended/reference/serialchartcontainer.md +34 -0
  38. package/extended/reference/starpattern.md +51 -0
  39. package/extended/reference/trianglepattern.md +49 -0
  40. package/package.json +2 -1
  41. package/src/content-fs.js +10 -0
  42. package/src/tools.js +73 -21
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
 
@@ -192,6 +201,27 @@ series.set("tooltip", tooltip);
192
201
 
193
202
  `getStrokeFromSprite` (default `false`) copies the sprite's stroke color when `true`.
194
203
 
204
+ ### Shared vs per-sprite tooltip
205
+
206
+ Setting **only** `tooltipText` on a sprite (no `tooltip:` instance anywhere on it) is enough to get a hover tooltip: the sprite lazily resolves the **Root's shared default `Tooltip`** (`sprite.getTooltip()` returns it). You only need your own `am5.Tooltip.new(root, {...})` when that element's tooltip must **look different** from the shared one, or on XY charts, where series/axis tooltips are **cursor-driven** rather than hover-driven and need their own instance.
207
+
208
+ So for non-XY charts do not create a Tooltip per series — set `tooltipText` on the right template and style the look once on the shared tooltip:
209
+
210
+ ```js
211
+ // Where tooltipText goes on non-XY charts
212
+ pieSeries.slices.template.set("tooltipText", "{category}: {value}"); // pie / funnel / venn slices
213
+ hierarchySeries.nodes.template.set("tooltipText", "{category}: {sum}"); // hierarchy nodes
214
+ flowSeries.nodes.nodes.template.set("tooltipText", "{name}"); // flow nodes
215
+ flowSeries.links.template.set("tooltipText", "{sourceId} → {targetId}: {value}"); // flow links
216
+ wordCloud.labels.template.set("tooltipText", "{category}: {value}"); // word cloud words
217
+ polygonSeries.mapPolygons.template.set("tooltipText", "{name}"); // map polygons (map points: the bullet sprite)
218
+
219
+ // Style the shared tooltip once — it lives on root.container (applies everywhere no dedicated Tooltip was set)
220
+ var shared = root.container.get("tooltip");
221
+ shared.set("getFillFromSprite", false);
222
+ shared.get("background").setAll({ fill: am5.color(0x000000), fillOpacity: 0.8 });
223
+ ```
224
+
195
225
  ## Chart title
196
226
 
197
227
  Do NOT add titles as HTML elements — they are outside the canvas and won't appear in exports. Add an `am5.Label` to the container BEFORE the chart, and set `verticalLayout`:
@@ -291,12 +321,12 @@ series.set("heatRules", [{
291
321
  | `maxValue` | number | Override auto-calculated max (skips `calculateAggregates`) |
292
322
  | `customFunction` | function | `(sprite, min, max, value)` — full control over the rule |
293
323
 
294
- **Using heat rules on bullets** — bullets need an explicit `am5.Template`:
324
+ **Using heat rules on bullets** — bullets need an explicit `am5.Template`, and the series must track the field the rule reads:
295
325
 
296
326
  ```js
297
327
  var circleTemplate = am5.Template.new({});
298
328
 
299
- series.bullets.push(function() {
329
+ series.bullets.push(function(root, series, dataItem) {
300
330
  return am5.Bullet.new(root, {
301
331
  sprite: am5.Circle.new(root, {
302
332
  fill: series.get("fill"),
@@ -314,6 +344,13 @@ series.set("heatRules", [{
314
344
  }]);
315
345
  ```
316
346
 
347
+ Rules that make bullet heat rules work (each failure is **silent** — every bullet just comes out the same size):
348
+ - `target` must be the **`Template`** the bullet sprites are built from (3rd argument of `am5.Circle.new(...)`), not the sprite and not `series.bullets`.
349
+ - `dataField` is the data item **property key** (`"valueY"`, `"valueX"`, `"value"`, …), **not** the raw column name. To size XY bullets by a column that is not already an axis value, register it as the base value field: `series.set("valueField", "population")` and use `dataField: "value"`.
350
+ - `calculateAggregates: true` is required (unless `minValue`/`maxValue` are given) — without it `valueLow`/`valueHigh` are never computed and every bullet gets the midpoint size.
351
+ - Setting `valueField` (or any `*Field`) **after** the series has processed data does not re-read the data — re-set it: `series.data.setAll(series.data.values.slice())`.
352
+ - `ChartSerializer` calls the bullet factory with a sample data item to introspect the sprite. That throwaway sprite joins the template but has no `dataItem`, and (as of 5.20.5) the heat-rule loop then throws on `target.dataItem` — on a `LineSeries` the stroke silently disappears. If you serialize charts that have bullet heat rules, have the factory call `sprite._setDataItem(dataItem)` itself, or serialize before adding the rule.
353
+
317
354
  **HeatLegend:**
318
355
 
319
356
  ```js
@@ -395,6 +432,23 @@ const cursor = chart.set("cursor", am5xy.XYCursor.new(root, {}));
395
432
 
396
433
  **Reading animated settings is unreliable mid-animation.** Right after `series.appear()` / `chart.appear()`, animated settings like `opacity` are still transitioning — `get("opacity")` can return `0` (the start value). Read such settings after the animation completes, or don't persist values read during appear (a common way to accidentally bake `opacity:0` into generated code).
397
434
 
435
+ ## Settings that already equal the default — omit them
436
+
437
+ Generated code routinely spells out settings that equal the amCharts default (verified against the default themes of 5.20.5). They add noise and mislead readers into thinking they matter. Do not emit these unless changing them:
438
+
439
+ | Class | Setting(s) that are already the default |
440
+ |-------|------------------------------------------|
441
+ | All hierarchy series | `childDataField: "children"`, `downDepth: 1`, `initialDepth: 5` |
442
+ | `Sunburst`, `Partition`, `Treemap`, `VoronoiTreemap` | `singleBranchOnly: true` (`Partition`/`Treemap` also `upDepth: 0`; `VoronoiTreemap` also `shapeType: "polygon"`) |
443
+ | `Tree`, `ForceDirected` | `singleBranchOnly: false`, `upDepth: Infinity`, `topDepth: 0` (`Tree` also `orientation: "vertical"`) |
444
+ | `PieSeries`, `FunnelSeries` | `alignLabels: true` (`FunnelSeries` also `orientation: "vertical"`, `startLocation: 0`, `endLocation: 1`, `bottomRatio: 0`) |
445
+ | `XYSeries` (all XY series) | `maskBullets: true` — note the default is **true**, so `maskBullets: false` is a real change |
446
+ | `LineSeries` (incl. smoothed/step) | `connect: true`; `StepLineSeries` `noRisers: false` |
447
+ | `XYChart` | `maxTooltipDistance` — leave **unset** (unset shows tooltips for all items in the category; `0` is *not* the same) |
448
+ | `HeatLegend` | `stepCount: 1` |
449
+
450
+ Runtime-mutated settings (`visible`, `x`/`y`, `opacity`, `scale`, cursor line `visible`, physics/random layouts, computed `AxisRendererCurve.points`) cannot be checked by "remove and re-`get()`" — amCharts rewrites them after render. User-set values live in `entity._userProperties` (what `ChartSerializer` reads), separate from the full `_settings` bag that includes theme and internal values.
451
+
398
452
  ## Dynamic data
399
453
 
400
454
  ```js
@@ -458,6 +512,39 @@ series.columns.template.states.create("active", {
458
512
  // State animation: stateAnimationDuration, stateAnimationEasing
459
513
  ```
460
514
 
515
+ ## Parameterized themes — Monochrome & Adaptive (5.20.0)
516
+
517
+ 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.
518
+
519
+ ```js
520
+ import am5themes_Monochrome from "@amcharts/amcharts5/themes/Monochrome";
521
+ import am5themes_Adaptive from "@amcharts/amcharts5/themes/Adaptive";
522
+
523
+ // Monochrome — single-hue lightness ramp
524
+ root.setThemes([
525
+ am5themes_Animated.new(root),
526
+ am5themes_Monochrome(root, {
527
+ color: 0x2c6e91, // base hue (default: blue #2e7c9e)
528
+ accent: 0xff7f0e, // optional — applied to the FIRST series only, so it pops
529
+ count: 7, // steps in the ramp (default 7)
530
+ dark: false // true = dark background + light-to-mid ramp
531
+ })
532
+ ]);
533
+
534
+ // Adaptive — full palette generated from one or two base colors
535
+ root.setThemes([
536
+ am5themes_Animated.new(root),
537
+ am5themes_Adaptive(root, {
538
+ baseColor: 0x2c6e91, // first generated color IS this color (good for brand colors)
539
+ baseColor2: 0xffdd00, // optional — palette spans the two colors
540
+ count: 10, // number of series colors (default 10)
541
+ dark: false
542
+ })
543
+ ]);
544
+ ```
545
+
546
+ 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.
547
+
461
548
  ## Custom themes
462
549
 
463
550
  ```js
@@ -513,6 +600,8 @@ colors.set("colors", [
513
600
  ]);
514
601
  ```
515
602
 
603
+ **A `ColorSet` must always hold at least one color.** `colorSet.set("colors", [])` crashes the next `next()`/`getIndex()` call (`Cannot read properties of undefined (reading 'toHSL')` inside `generateColors`) as soon as a series iterates the palette — as of 5.20.5 the empty list is not guarded. To "reset" a palette, swap in a fresh `am5.ColorSet.new(root, {})` instead of emptying the list. The theme's `baseColor` also resolves lazily, so a **synchronous** re-color right after swapping a `ColorSet` can read a transient value (sprites momentarily black); re-set the series data and let amCharts' own data pass recolor the sprites.
604
+
516
605
  ## Data processor
517
606
 
518
607
  ```js
@@ -527,6 +616,17 @@ series.data.processor = am5.DataProcessor.new(root, {
527
616
  // Configure processor BEFORE setting data
528
617
  ```
529
618
 
619
+ ## Serializing to JSON (ChartSerializer / JsonParser)
620
+
621
+ `am5plugins_json.ChartSerializer` turns a live chart into a JSON config and `am5plugins_json.JsonParser` rebuilds it (`await parser.parse(config, { parent: root.container })`). Rules that keep round-trips working:
622
+
623
+ - **Serialize the chart's top-level container child, never a bare series.** `serializer.serializeAll(root.container.children.getIndex(0))`. Serializing an unwrapped series whose settings point back at itself (`selectedDataItem` holds a `DataItem` whose `component` is the series) produces a cycle: `_pruneEmptyObjects` overflows the stack (`removeEmptyObjects: true`, the default) or `JSON.stringify` throws "Converting circular structure". With the container as root the series becomes a `#series-0` reference and the cycle disappears.
624
+ - **Adapters do not round-trip.** `includeAdapters: true` writes each adapter as `{ key, callback: "function (…) {…}" }`; the parser does not turn that string back into a function (and the closure's `chart`/`series`/`root` would not exist anyway). Before 5.20.4 the string was registered as a callback and crashed the chart (`i[s] is not a function` in `Entity.fold`); since 5.20.4 such adapters are skipped. Either way the effect is lost — replace palette-coloring adapters with declarative equivalents: `colorByDataItem: true` on column series (5.20.4), a per-item `fill` data field + `templateField`, or `heatRules`.
625
+ - **Only user-set settings are serialized (5.20.3)** — theme and library defaults are left out, so a serialized config is much smaller than before and a value you never set will not appear in it. Add `includeRoot: true` (5.20.2) to also write a top-level `root` section (Root settings/properties, `interfaceColors`, formatters).
626
+ - **Re-parsing into an existing chart:** `parser.parse(config, { updateTargets: "soft" })` (5.20.3) applies settings onto an existing object of the same `type` instead of replacing it. The default `"strict"` replaces.
627
+ - **Not captured by `ChartSerializer` (as of 5.20.5)** — re-apply these in code after `parse()`: a `ZoomableContainer`'s `contents.children` and its `ZoomTools` (the serialized container comes back empty — track "chart is zoomable" out-of-band, or use `am5.SerialChartContainer` which builds the zoomable wrapper itself); Venn `hoverGraphics` and Venn slice-template `states` (a custom Venn hover cannot be expressed in JSON); custom elements without `themeTags: ["serialize"]`.
628
+ - **Bullets** are captured by calling the factory with a sample data item — write factories as `function(root, series, dataItem)` (pitfall #36) and see the heat-rule caveat under "Heat rules".
629
+
530
630
  ## Accessibility
531
631
 
532
632
  ```js
@@ -660,7 +760,7 @@ onUnmounted(() => { root.dispose(); });
660
760
  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
761
  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
762
  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.
763
+ 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
764
  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
765
  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
766
  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`.
@@ -679,6 +779,10 @@ onUnmounted(() => { root.dispose(); });
679
779
  31. **Globe rotation uses negative coordinates** — To center the globe (`geoOrthographic`) on a geographic point, set `rotationX` to **-longitude** and `rotationY` to **-latitude**. E.g., to center on Paris (48.86°N, 2.35°E): `chart.animate({ key: "rotationX", to: -2.35 }); chart.animate({ key: "rotationY", to: -48.86 });`. Using positive values rotates the globe the wrong way.
680
780
  32. **`positionOnLine` with multi-segment lines limits per-segment control** — `MapPointSeries` data items can animate along a line via `positionOnLine` (0→1). If the line has 3+ points (multi-segment), position 0.5 is the midpoint of the *entire* path, making per-segment effects (scaling at each segment midpoint, pausing between segments, etc.) difficult. For advanced per-segment animations, use **single-segment lines** (2 points each) and animate the bullet across them sequentially. E.g., instead of one line [A,B,C,D], create [A,B], [B,C], [C,D].
681
781
  33. **Do NOT exclude Antarctica (`exclude: ["AQ"]`) by default** — Many amCharts demos exclude Antarctica because they use Mercator projection where it appears disproportionately large. This is a demo-specific choice, not a best practice. Unless the user explicitly asks to exclude Antarctica, or references a demo that does so, keep Antarctica in the map. With non-Mercator projections (`geoNaturalEarth1`, `geoEqualEarth`, `geoOrthographic`, `geoEquirectangular`), Antarctica renders at a reasonable size.
782
+ 34. **Custom GeoJSON for `MapPolygonSeries` needs CLOCKWISE exterior rings** — amCharts projects on a sphere (d3-geo), where ring winding decides which side is "inside". The RFC 7946 default is counter-clockwise, which d3-geo reads as *the whole globe minus the polygon*, so every polygon floods the entire map and the real shape shows only as a sliver. Programmatically generated GeoJSON (grids, cells, buffers) is usually CCW. amCharts does **not** auto-rewind — reverse each ring yourself: `feature.geometry.coordinates = feature.geometry.coordinates.map(ring => ring.slice().reverse())` (for `MultiPolygon`, one level deeper). See `references/map.md`.
783
+ 35. **`axis.dispose()` does NOT remove the axis from `chart.xAxes`/`chart.yAxes`** — unlike `series.dispose()`, which self-removes from `chart.series`. A disposed axis stays in the list, keeps showing up in anything built from `chart.yAxes`, and makes `ChartSerializer` throw `Template is disposed`. Remove axes with `chart.yAxes.removeValue(axis)` (or `removeIndex(i)`) — the list auto-disposes the removed axis, no separate `dispose()` needed.
784
+ 36. **Declare bullet callbacks as `function(root, series, dataItem)`** — amCharts passes all three; closing over an outer `root` works at runtime but breaks JSON round-trips (`ChartSerializer` captures the function source, and the outer `root` dangles on re-bind). Every `series.bullets.push(...)` in these references uses the parameter form — copy it.
785
+ 37. **A `ColorSet` must contain at least one color** — `colors.set("colors", [])` crashes the next `next()`/`getIndex()`. Swap in a fresh `am5.ColorSet.new(root, {})` instead. See "ColorSet" above.
682
786
 
683
787
  ## Easing functions
684
788
 
@@ -716,7 +820,7 @@ Skip this step entirely if you cannot execute code (e.g., chat-only context with
716
820
 
717
821
  ## Recent API changes (newer than the bundled class reference)
718
822
 
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).
823
+ The bundled per-class API reference was snapshotted on **2026-03-15**, so it predates the changes below. Latest release covered here: **5.20.5** (2026-09-03). Prefer these names/settings; for anything newer, verify against the live docs (see next section).
720
824
 
721
825
  **Renamed settings (old name still works but is deprecated — use the new one):**
722
826
 
@@ -731,14 +835,68 @@ am5stock.MovingAverage.new(root, { maType: "exponential", period: 20 });
731
835
  am5hierarchy.VoronoiTreemap.new(root, { shapeType: "rectangle" }); // was: type
732
836
  ```
733
837
 
838
+ **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.
839
+
734
840
  **New settings / methods worth knowing:**
841
+
842
+ *Themes & styling*
843
+ - 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.
844
+ - New fill patterns (5.20.0): `am5.StarPattern` (`radius`, `innerRadius`, `spikes`, `gap`, `checkered`) and `am5.TrianglePattern` (`maxWidth`, `maxHeight`, `gap`, `checkered`).
845
+ - `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.
846
+ - `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).
847
+
848
+ *XY charts*
849
+ - `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.
850
+ - `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.
851
+ - `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.
852
+ - Column series (`ColumnSeries`, `CandlestickSeries`, `OHLCSeries`, …) (5.20.4): `colorByDataItem: true` (default `false`) gives each column its own color from the series' new `colors` (`ColorSet`) setting — the series makes its own `ColorSet` if none is given. The color lands on the data item's `fill` field. Prefer this over the old "adapter on `columns.template` `fill`" recipe: it is declarative and survives JSON serialization.
853
+ - `Scrollbar` (5.20.2): `opposite: true` (default `false`) puts a chart's `scrollbarX` **below** the plot and `scrollbarY` to the **left**, instead of above / right. Only affects scrollbars set via `chart.set("scrollbarX"/"scrollbarY", …)`. This is a **different** setting from the long-standing `opposite` on `AxisRendererX`/`AxisRendererY`.
854
+
855
+ *WordCloud (5.20.1)*
856
+ - `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`.
857
+ - `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).
858
+ - `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.
859
+
860
+ *Core / events*
861
+ - New `globalpointerdown` event on all elements — fires on a press anywhere on the chart surface, mirroring `globalpointermove`/`globalpointerup`.
862
+ - `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.
863
+ - `Root`: `ariaLabel` is now applied to the `<div>` holding the chart's focusable elements (5.20.0).
864
+ - `Label`: `oversizedBehavior: "truncate"` now ignores `maxHeight` (there is no way to truncate text vertically).
865
+ - A `Container`'s `Rectangle`/`RoundedRectangle` background now defaults `crisp` to `true` unless set explicitly (5.20.0).
866
+ - `Root` (5.20.2): `fontFamily`, `fontSize` (number or string) and `fontWeight` (`"normal" | "bold" | "bolder" | "lighter" | "100"…`"900"`) settings — defaults for **all** text elements unless overridden on an element. Set them in `am5.Root.new("chartdiv", { fontFamily: "Inter" })` or `root.setAll({...})` instead of a custom theme rule on `Label`.
867
+ - `am5.SerialChartContainer` (5.20.2) — a directly usable `SerialChart` whose `seriesContainer` sits inside a `ZoomableContainer` (exposed as `chart.zoomableContainer`), so series such as `ForceDirected` can be zoomed and panned. Exported from the **`am5` root module**, not a chart package. Optional `zoomTools` setting takes a `ZoomTools` instance whose `target` is pointed at the series container automatically. Bullets added to its series are drawn (5.20.4) and flow-chart bullets are placed correctly inside it (5.20.5). See `references/hierarchy.md`.
868
+
869
+ *JSON config / serialization (5.20.2 – 5.20.4)*
870
+ - `ChartSerializer` now emits **only user-set settings** (5.20.3) — theme and library defaults are left out. Anything diffing or post-processing serializer output must expect much smaller configs.
871
+ - A JSON config may carry a top-level **`root`** section (5.20.2) that applies settings and properties to the `Root` object before the chart is parsed; `ChartSerializer` writes it when `includeRoot: true` (default `false`). A `Root`'s `interfaceColors`, `utc`, `fps`, formatters and `tabindex` round-trip through it (5.20.3).
872
+ - `JsonParser.parse(config, { updateTargets: "soft" })` (5.20.3) — an option on the **second argument of `parse()`**, not a parser setting. `"soft"` applies settings onto an existing object of the same `type` instead of replacing it; default `"strict"` replaces. `parse()` is async and returns a Promise.
873
+ - Gantt charts are now serializable/parsable (5.20.3). Cross-references are written as references (`"@series.get('fill')"`) instead of copies; large values (a map's `geoJSON`, a `Root`'s locale) are written as the name of the pack they came from and rebuilt on parse.
874
+ - An adapter whose callback did not survive the JSON round-trip is now **skipped** on parse instead of breaking the chart (5.20.4) — adapters still do not round-trip, see "Serializing to JSON" above.
875
+
876
+ *Bullets on non-XY charts (5.20.2)*
877
+ - `ArcDiagram`: bullets on nodes are now placed on the node circle, `locationX`/`locationY` being fractions of it (before 5.20.2 they were created but never positioned). Flow charts (`Sankey`/`Chord`): node bullets are children of the node, drawn above its shape and below its label, positioned relative to the node. `FunnelSeries`/`PyramidSeries`: bullet `locationX`/`locationY` follow the slice's sloping edges instead of its bounding box.
878
+ - A bullet `Graphics` with no paint of its own takes the color of **its own slice or node** on pie, funnel, flow and hierarchy charts — so it is the same color as what it sits on and **invisible** unless offset, stroked, or given a contrasting `fill` deliberately. Setting `fill` on the bullet sprite turns the inheritance off.
879
+
880
+ *Maps*
881
+ - `MapChart` (5.20.2): `doubleClickZoom` (default **`true`** — a behavior change: a double click/tap zooms in, shift + double click zooms out; set `false` to opt out). On maps panned by rotating (`panX: "rotateX"` / `panY: "rotateY"`) the clicked point rotates to the center, otherwise it stays under the pointer. `boxZoom: "none" | "drag" | "shift" | "ctrl" | "alt"` (default `"none"`) is **not a boolean** — it names the key held while dragging a rectangle to zoom into; `"drag"` needs no key, so pair it with `panX`/`panY: "none"`. The rectangle is the readonly `chart.boxZoomSelection` element (a `Rectangle`). There are no keyboard-navigation settings on `MapChart`.
882
+ - `MapLineSeries` (5.20.3): `pointIds` data field (`{ pointIds: ["JFK", "LAX"] }`) names the `MapPointSeries` points a line connects, looked up in the series given by the new `pointSeries` setting; `pointIdsField` (default `"pointIds"`) renames the field. `pointsToConnect` wins if both are set. See `references/map.md`.
883
+ - `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.
884
+ - `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`.
885
+ - `MapPointSeries` defaults changed to `longitudeField: "longitude"`, `latitudeField: "latitude"` (5.16.1).
886
+
887
+ *Hierarchy & axes*
735
888
  - `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
889
  - `ValueAxis`: `syncZeros` (5.16.2, align zero across synced axes — needs `syncWithAxis`).
737
890
  - `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.
891
+
892
+ *Stock*
893
+ - 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).
894
+ - 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`.
895
+
896
+ *All entities*
897
+ - `onDebounced(key, cb, delay)` / `offDebounced(key, cb?)` and `onPrivateDebounced` / `offDebouncedPrivate` (5.17.3) — fire once after rapid changes settle.
898
+ - `once(key, cb)` and `onceDebounced(key, cb, delay)` (5.20.4) — like `on()`/`onDebounced()` for a **settings** key, but the callback fires only the first time that setting changes, then removes itself. Both return an `IDisposer`. (Distinct from `events.once("eventName", …)`, which has existed for events all along.)
739
899
  - `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
900
 
743
901
  ## Verify unfamiliar API before using it
744
902
 
package/content/flow.md CHANGED
@@ -254,6 +254,10 @@ series.links.template.events.on("click", function(ev) {
254
254
  });
255
255
  ```
256
256
 
257
+ ## Bullets on nodes (5.20.2)
258
+
259
+ Bullets pushed to `series.nodes.bullets` are children of the node since 5.20.2: drawn above the node shape and below its label, positioned relative to the node (`locationX`/`locationY` as fractions of it). On `ArcDiagram` they sit on the node circle — before 5.20.2 they were created but never placed. A bullet `Graphics` with no `fill`/`stroke` of its own takes the **node's** color, i.e. the same color as what it sits on — give it a contrasting `fill`, a `stroke`, or an offset or it is invisible. Node/link tooltips need no `am5.Tooltip` instance: set `tooltipText` on `series.nodes.nodes.template` / `series.links.template` and the root's shared tooltip is used.
260
+
257
261
  ## Animated bullets along links
258
262
 
259
263
  Animated labels/circles that flow along Sankey or Chord links use `series.bullets.push()` — **NOT** `series.links.template.bullets.push()`. The bullet position (0 = source, 1 = target) is animated in a loop, and an adapter fades opacity based on position.
@@ -319,6 +319,27 @@ series.events.on("datavalidated", function() {
319
319
  });
320
320
  ```
321
321
 
322
+ ## Zoomable / pannable hierarchy — `SerialChartContainer` (5.20.2)
323
+
324
+ `am5.SerialChartContainer` (exported from the **`am5` root module**, not `am5hierarchy`) is a directly usable `SerialChart` whose `seriesContainer` sits inside a `ZoomableContainer`, so a large `ForceDirected`, `Tree` or `Pack` can be wheel-zoomed and dragged. Prefer it over hand-wrapping the chart in `am5.ZoomableContainer` — it also survives `ChartSerializer` round-trips, which a manual `ZoomableContainer` does not (its `contents` are not serialized).
325
+
326
+ ```js
327
+ const chart = root.container.children.push(am5.SerialChartContainer.new(root, {
328
+ zoomTools: am5.ZoomTools.new(root, {}) // optional +/−/home buttons, target is wired automatically
329
+ }));
330
+
331
+ const series = chart.series.push(am5hierarchy.ForceDirected.new(root, {
332
+ valueField: "value",
333
+ categoryField: "name",
334
+ childDataField: "children"
335
+ }));
336
+ series.data.setAll(data);
337
+
338
+ chart.zoomableContainer.setAll({ maxZoomLevel: 8 }); // the ZoomableContainer holding the series
339
+ ```
340
+
341
+ Bullets on series inside a `SerialChartContainer` are drawn as of 5.20.4, and flow-chart (`Sankey`/`Chord`/`ArcDiagram`) bullets are placed correctly inside one as of 5.20.5.
342
+
322
343
  ## Disposal
323
344
 
324
345
  ```js
package/content/map.md CHANGED
@@ -123,6 +123,28 @@ polygonSeries.data.setAll([
123
123
  ]);
124
124
  ```
125
125
 
126
+ **Custom GeoJSON: exterior rings must be CLOCKWISE.** amCharts projects on a sphere (d3-geo), where a ring's winding order decides which side is "inside". The GeoJSON spec (RFC 7946) winds exterior rings counter-clockwise, and d3-geo reads a CCW ring as *the whole globe minus the polygon* — so every polygon fills the entire viewport and the real shape shows only as a sliver (looks like a zoom/fit bug, is not). GIS exports are usually already clockwise; programmatically generated GeoJSON (grids, cells, buffers) usually is not. amCharts does **not** auto-rewind, so reverse the rings yourself:
127
+
128
+ ```js
129
+ // Fix winding before handing custom GeoJSON to MapPolygonSeries
130
+ geojson.features.forEach(function(feature) {
131
+ var g = feature.geometry;
132
+ if (g.type === "Polygon") {
133
+ g.coordinates = g.coordinates.map(function(ring) { return ring.slice().reverse(); });
134
+ } else if (g.type === "MultiPolygon") {
135
+ g.coordinates = g.coordinates.map(function(poly) {
136
+ return poly.map(function(ring) { return ring.slice().reverse(); });
137
+ });
138
+ }
139
+ });
140
+ polygonSeries.set("geoJSON", geojson);
141
+
142
+ // Fit the map to a custom region (no country geodata needed): left/right = longitude, top/bottom = latitude
143
+ chart.zoomToGeoBounds({ left: -8.6, right: 1.8, top: 60.9, bottom: 49.9 }, 500);
144
+ ```
145
+
146
+ `zoomToGeoBounds(bounds, duration?)` is more reliable than `homeGeoPoint` + `homeZoomLevel` + `goHome()` when the only series is custom polygons.
147
+
126
148
  ### Choropleth (heat map) via heat rules
127
149
 
128
150
  ```js
@@ -145,6 +167,17 @@ const heatLegend = chart.children.push(am5.HeatLegend.new(root, {
145
167
  }));
146
168
  ```
147
169
 
170
+ **Styling heat-legend segments.** With `stepCount: N` the legend draws N discrete `RoundedRectangle` markers inside `heatLegend.markerContainer`, all styled through `heatLegend.markers.template` (it accepts the usual Graphics settings — `stroke`, `strokeWidth`, `strokeOpacity`, `fillOpacity`, `cornerRadius*`, `tooltipText` for a per-block hover tooltip). Segment **thickness** is the marker's cross-axis size: a **vertical** legend uses the marker `width` (default `15`) with `height: 100%`; a **horizontal** legend uses `height` (default `15`) with `width: 100%`. Style via the template — `heatLegend.markers.values` can read empty even while `markerContainer.children` holds the rectangles.
171
+
172
+ ```js
173
+ heatLegend.markers.template.setAll({
174
+ width: 30, // thicker bar on a vertical legend (use height on a horizontal one)
175
+ stroke: am5.color(0xffffff),
176
+ strokeWidth: 1,
177
+ tooltipText: "{value}"
178
+ });
179
+ ```
180
+
148
181
  ### MapPointSeries (markers, bubbles, labels)
149
182
 
150
183
  ```js
@@ -156,7 +189,7 @@ const pointSeries = chart.series.push(
156
189
  );
157
190
 
158
191
  // Define bullet appearance
159
- pointSeries.bullets.push(function() {
192
+ pointSeries.bullets.push(function(root, series, dataItem) {
160
193
  return am5.Bullet.new(root, {
161
194
  sprite: am5.Circle.new(root, {
162
195
  radius: 5,
@@ -166,7 +199,9 @@ pointSeries.bullets.push(function() {
166
199
  });
167
200
  });
168
201
 
169
- // Add points via data — requires latitudeField/longitudeField on the series
202
+ // Add points via data. Fields named "latitude"/"longitude" are the series
203
+ // defaults since 5.16.1; any other naming must be declared via
204
+ // latitudeField/longitudeField or the points silently won't render.
170
205
  pointSeries.data.setAll([
171
206
  { latitude: 48.8566, longitude: 2.3522, name: "Paris" },
172
207
  { latitude: 40.7128, longitude: -74.0060, name: "New York" },
@@ -212,8 +247,24 @@ lineSeries.pushDataItem({
212
247
  coordinates: [[-74.01, 40.71], [-0.45, 51.47]] // [lng, lat] pairs
213
248
  }
214
249
  });
250
+
251
+ // OR (5.20.3) name the points by id — data-driven, JSON-friendly, no data-item references needed
252
+ const pointSeries2 = chart.series.push(am5map.MapPointSeries.new(root, {})); // ids come from the "id" data field
253
+ pointSeries2.data.setAll([
254
+ { id: "JFK", latitude: 40.64, longitude: -73.78 },
255
+ { id: "LAX", latitude: 33.94, longitude: -118.41 }
256
+ ]);
257
+ const lineSeries2 = chart.series.push(am5map.MapLineSeries.new(root, {
258
+ pointSeries: pointSeries2 // where pointIds are looked up
259
+ // pointIdsField: "pointIds" // default field name
260
+ }));
261
+ lineSeries2.data.setAll([
262
+ { pointIds: ["JFK", "LAX"] } // the line waits until every id has a point, then draws
263
+ ]);
215
264
  ```
216
265
 
266
+ `pointsToConnect` wins if a data item has both. Fixed points (`fixed: true`) cannot be used with either.
267
+
217
268
  ### MapSankeySeries (geographic flow bands)
218
269
 
219
270
  Draws variable-width curved bands between geographic points on a map. Band thickness represents a numeric value — like a Sankey diagram projected onto a map. Extends `MapPolygonSeries` and generates actual GeoJSON polygon geometries, so bands follow the map projection during pan, zoom, and rotation.
@@ -363,7 +414,7 @@ var sankeySeries = chart.series.push(
363
414
  #### Animated bullets along bands
364
415
 
365
416
  ```js
366
- sankeySeries.bullets.push(function() {
417
+ sankeySeries.bullets.push(function(root, series, dataItem) {
367
418
  return am5.Bullet.new(root, {
368
419
  locationX: 0,
369
420
  autoRotate: true,
@@ -418,7 +469,7 @@ sankeySeries.data.setAll([
418
469
  ```js
419
470
  // Create a point that follows a line
420
471
  var planeSeries = chart.series.push(am5map.MapPointSeries.new(root, {}));
421
- planeSeries.bullets.push(function() {
472
+ planeSeries.bullets.push(function(root, series, dataItem) {
422
473
  return am5.Bullet.new(root, {
423
474
  sprite: am5.Graphics.new(root, {
424
475
  svgPath: "m2,106h28l24,30h72l-44,-133h35l80,132h98c21,0 21,34 0,34l-98,0 -80,134h-35l43,-133h-71l-24,30h-28l15,-47",
@@ -469,6 +520,19 @@ chart.chartContainer.children.push(am5.Button.new(root, {
469
520
  })).events.on("click", function() {
470
521
  chart.goHome();
471
522
  });
523
+
524
+ // Fit to a lat/long box (left/right = longitude, top/bottom = latitude)
525
+ chart.zoomToGeoBounds({ left: -10, right: 40, top: 70, bottom: 35 }, 800);
526
+ ```
527
+
528
+ **Pointer zoom behaviors (5.20.2):** a double click/tap zooms in and shift + double click zooms out **by default** (`doubleClickZoom: true`; set `false` to turn it off). `boxZoom` lets the user drag a rectangle to zoom into — its value is the key that must be held: `"shift"`, `"ctrl"`, `"alt"`, or `"drag"` for no key (then set `panX`/`panY: "none"`, since a plain drag otherwise pans); default `"none"`. The rectangle being drawn is `chart.boxZoomSelection` (a `Rectangle`, style its `fill`/`stroke`).
529
+
530
+ ```js
531
+ am5map.MapChart.new(root, {
532
+ boxZoom: "shift", // hold shift and drag to zoom into the box
533
+ doubleClickZoom: false // opt out of the default double-click zoom
534
+ });
535
+ chart.boxZoomSelection.setAll({ fill: am5.color(0x1e88e5), fillOpacity: 0.15 });
472
536
  ```
473
537
 
474
538
  ## Globe (orthographic projection)
@@ -550,6 +614,8 @@ am5map.MapChart.new(root, {
550
614
  rotationZ: 0, // tilt
551
615
  wheelY: "zoom", // "zoom", "none"
552
616
  wheelSensitivity: 1, // zoom speed multiplier
617
+ doubleClickZoom: true, // (5.20.2) double click zooms in, shift+double click out — default true
618
+ boxZoom: "none", // (5.20.2) "none" | "drag" | "shift" | "ctrl" | "alt" — key held to drag a zoom box
553
619
  })
554
620
  ```
555
621
 
@@ -781,7 +847,7 @@ root.dispose();
781
847
 
782
848
  // Point series for airports
783
849
  var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, {}));
784
- pointSeries.bullets.push(function() {
850
+ pointSeries.bullets.push(function(root, series, dataItem) {
785
851
  return am5.Bullet.new(root, {
786
852
  sprite: am5.Circle.new(root, {
787
853
  radius: 4,
@@ -893,7 +959,7 @@ Demonstrates: orthographic projection, single-segment lines for per-segment anim
893
959
 
894
960
  // City points with pulse + label
895
961
  var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, {}));
896
- pointSeries.bullets.push(function () {
962
+ pointSeries.bullets.push(function(root, series, dataItem) {
897
963
  var container = am5.Container.new(root, {});
898
964
  container.children.push(am5.Circle.new(root, {
899
965
  radius: 3.5, fill: cityColor, fillOpacity: 0.9,
@@ -930,7 +996,7 @@ Demonstrates: orthographic projection, single-segment lines for per-segment anim
930
996
 
931
997
  // Plane series — one per segment, all hidden initially
932
998
  var planeSeries = chart.series.push(am5map.MapPointSeries.new(root, {}));
933
- planeSeries.bullets.push(function () {
999
+ planeSeries.bullets.push(function(root, series, dataItem) {
934
1000
  return am5.Bullet.new(root, {
935
1001
  sprite: am5.Graphics.new(root, {
936
1002
  svgPath: "m2,106h28l24,30h72l-44,-133h35l80,132h98c21,0 21,34 0,34l-98,0 -80,134h-35l43,-133h-71l-24,30h-28l15,-47",
@@ -1199,7 +1265,7 @@ Demonstrates: `MapSankeySeries` with `sourceId`/`targetId` data (country codes),
1199
1265
  });
1200
1266
 
1201
1267
  // Animated coffee bean bullets
1202
- sankeySeries.bullets.push(function() {
1268
+ sankeySeries.bullets.push(function(root, series, dataItem) {
1203
1269
  return am5.Bullet.new(root, {
1204
1270
  locationX: 0,
1205
1271
  autoRotate: true,
@@ -1490,7 +1556,7 @@ Demonstrates: `MapSankeySeries` with explicit `sourceLongitude`/`sourceLatitude`
1490
1556
  });
1491
1557
 
1492
1558
  // Animated oil drop bullets
1493
- sankeySeries.bullets.push(function() {
1559
+ sankeySeries.bullets.push(function(root, series, dataItem) {
1494
1560
  return am5.Bullet.new(root, {
1495
1561
  locationX: 0,
1496
1562
  autoRotate: true,
package/content/pie.md CHANGED
@@ -260,6 +260,22 @@ am5percent.PictorialStackedSeries.new(root, {
260
260
  })
261
261
  ```
262
262
 
263
+ ## Bullets on slices
264
+
265
+ ```js
266
+ series.bullets.push(function(root, series, dataItem) {
267
+ return am5.Bullet.new(root, {
268
+ locationX: 0.5, locationY: 0.5, // fractions of the slice (funnel/pyramid: along the sloping edges since 5.20.2)
269
+ sprite: am5.Circle.new(root, {
270
+ radius: 6,
271
+ fill: am5.color(0xffffff) // set a paint — an unpainted bullet takes its own slice's color and is invisible
272
+ })
273
+ });
274
+ });
275
+ ```
276
+
277
+ Percent series have **no series-level `fill`**: a bullet `Graphics` with no `fill`/`stroke` is auto-colored per data item from its own slice (5.20.0+), so it blends in unless stroked, offset, or given a contrasting fill. Slice tooltips need no `am5.Tooltip` instance — `series.slices.template.set("tooltipText", "{category}: {value}")` uses the root's shared tooltip.
278
+
263
279
  ## Legend (for all percent charts)
264
280
 
265
281
  ```js
package/content/radar.md CHANGED
@@ -286,7 +286,7 @@ columnSeries.columns.template.events.on("click", function(ev) {
286
286
  });
287
287
 
288
288
  // Pointer over/out on radar line data points (via bullets)
289
- series.bullets.push(function() {
289
+ series.bullets.push(function(root, series, dataItem) {
290
290
  var circle = am5.Circle.new(root, {
291
291
  radius: 5,
292
292
  fill: series.get("fill"),
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)
@@ -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
@@ -214,7 +214,7 @@ series.set("snapTooltip", true);
214
214
  Bullets on timeline charts work the same as XY charts:
215
215
 
216
216
  ```js
217
- series.bullets.push(function() {
217
+ series.bullets.push(function(root, series, dataItem) {
218
218
  return am5.Bullet.new(root, {
219
219
  sprite: am5.Circle.new(root, {
220
220
  radius: 5,
@@ -258,7 +258,7 @@ series.bullets.push(function(root, series, dataItem) {
258
258
 
259
259
  ```js
260
260
  // Click on data points (via bullets)
261
- series.bullets.push(function() {
261
+ series.bullets.push(function(root, series, dataItem) {
262
262
  var circle = am5.Circle.new(root, {
263
263
  radius: 5,
264
264
  fill: series.get("fill"),
@@ -346,7 +346,7 @@ chart.get("cursor").events.on("cursormoved", function(ev) {
346
346
  series.fills.template.setAll({ visible: true, fillOpacity: 0.3 });
347
347
 
348
348
  // Add bullets
349
- series.bullets.push(function() {
349
+ series.bullets.push(function(root, series, dataItem) {
350
350
  return am5.Bullet.new(root, {
351
351
  sprite: am5.Circle.new(root, {
352
352
  radius: 4,
package/content/venn.md CHANGED
@@ -147,6 +147,10 @@ series.labels.template.adapters.add("text", function(text, target) {
147
147
  });
148
148
  ```
149
149
 
150
+ ## Serialization gotcha: custom hover is not captured
151
+
152
+ `series.hoverGraphics` (the dashed set outline used in the amCharts venn demo) and `slices.template.states.create("hover", …)` are **not** written by `am5plugins_json.ChartSerializer` as of 5.20.5 — a venn rebuilt from JSON loses any custom hover look (`slices.template.tooltipText` does round-trip). Re-apply `hoverGraphics.setAll({...})` in code after `JsonParser.parse()`.
153
+
150
154
  ## Click events
151
155
 
152
156
  ```js