@amcharts/amcharts5-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitmodules +3 -0
- package/README.md +82 -0
- package/amcharts5-skill/README.md +50 -0
- package/amcharts5-skill/amcharts5-skill/SKILL.md +667 -0
- package/amcharts5-skill/amcharts5-skill/references/flow.md +523 -0
- package/amcharts5-skill/amcharts5-skill/references/gantt.md +410 -0
- package/amcharts5-skill/amcharts5-skill/references/hierarchy.md +568 -0
- package/amcharts5-skill/amcharts5-skill/references/map.md +574 -0
- package/amcharts5-skill/amcharts5-skill/references/pie.md +663 -0
- package/amcharts5-skill/amcharts5-skill/references/radar.md +584 -0
- package/amcharts5-skill/amcharts5-skill/references/stock.md +664 -0
- package/amcharts5-skill/amcharts5-skill/references/timeline.md +449 -0
- package/amcharts5-skill/amcharts5-skill/references/ui-elements.md +393 -0
- package/amcharts5-skill/amcharts5-skill/references/venn.md +368 -0
- package/amcharts5-skill/amcharts5-skill/references/wordcloud.md +339 -0
- package/amcharts5-skill/amcharts5-skill/references/xy.md +1150 -0
- package/amcharts5-skill/cursorrules +820 -0
- package/package.json +27 -0
- package/src/index.js +329 -0
- package/test.js +153 -0
|
@@ -0,0 +1,820 @@
|
|
|
1
|
+
# amCharts 5 – AI coding rules
|
|
2
|
+
# Drop this file in your project root as .cursorrules (Cursor),
|
|
3
|
+
# .windsurfrules (Windsurf), or .github/copilot-instructions.md (VS Code + Copilot)
|
|
4
|
+
# Docs: https://www.amcharts.com/docs/v5/
|
|
5
|
+
|
|
6
|
+
## Version
|
|
7
|
+
|
|
8
|
+
Always use **amCharts 5** (not v3 or v4). The APIs are completely different.
|
|
9
|
+
amCharts 5 uses Canvas rendering (not SVG like v4).
|
|
10
|
+
|
|
11
|
+
## Object creation
|
|
12
|
+
|
|
13
|
+
amCharts 5 does NOT use `new ClassName()`. Always use the static `.new()` factory:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
// ✅ CORRECT
|
|
17
|
+
const root = am5.Root.new("chartdiv");
|
|
18
|
+
const chart = root.container.children.push(am5xy.XYChart.new(root, { ... }));
|
|
19
|
+
|
|
20
|
+
// ❌ WRONG – never use `new` keyword
|
|
21
|
+
const root = new am5.Root("chartdiv");
|
|
22
|
+
const chart = new am5xy.XYChart(root, { ... });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Every `.new()` call takes `root` as the first argument (except Root itself which takes the div ID).
|
|
26
|
+
|
|
27
|
+
## Core setup pattern
|
|
28
|
+
|
|
29
|
+
Every chart follows this structure:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
// 1. Create root
|
|
33
|
+
const root = am5.Root.new("chartdiv");
|
|
34
|
+
|
|
35
|
+
// 2. Apply theme(s)
|
|
36
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
37
|
+
|
|
38
|
+
// 3. Create chart
|
|
39
|
+
const chart = root.container.children.push(
|
|
40
|
+
am5xy.XYChart.new(root, { layout: root.verticalLayout })
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// 4. Create axes, series, etc.
|
|
44
|
+
// 5. Set data LAST (important!)
|
|
45
|
+
series.data.setAll([...]);
|
|
46
|
+
|
|
47
|
+
// 6. Play animations
|
|
48
|
+
series.appear(1000);
|
|
49
|
+
chart.appear(1000, 100);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**CRITICAL:** Always set data as late as possible. Once data is set, related objects are created — configuration applied afterward may not take effect.
|
|
53
|
+
|
|
54
|
+
## Packages and imports
|
|
55
|
+
|
|
56
|
+
### ES modules / TypeScript
|
|
57
|
+
```ts
|
|
58
|
+
import * as am5 from "@amcharts/amcharts5";
|
|
59
|
+
import * as am5xy from "@amcharts/amcharts5/xy";
|
|
60
|
+
import * as am5percent from "@amcharts/amcharts5/percent";
|
|
61
|
+
import * as am5map from "@amcharts/amcharts5/map";
|
|
62
|
+
import * as am5hierarchy from "@amcharts/amcharts5/hierarchy";
|
|
63
|
+
import * as am5flow from "@amcharts/amcharts5/flow";
|
|
64
|
+
import * as am5radar from "@amcharts/amcharts5/radar";
|
|
65
|
+
import * as am5stock from "@amcharts/amcharts5/stock";
|
|
66
|
+
import * as am5wc from "@amcharts/amcharts5/wc";
|
|
67
|
+
import * as am5venn from "@amcharts/amcharts5/venn";
|
|
68
|
+
import * as am5gantt from "@amcharts/amcharts5/gantt";
|
|
69
|
+
import * as am5timeline from "@amcharts/amcharts5/timeline";
|
|
70
|
+
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
|
|
71
|
+
import am5themes_Dark from "@amcharts/amcharts5/themes/Dark";
|
|
72
|
+
|
|
73
|
+
// Map geodata (example)
|
|
74
|
+
import am5geodata_worldLow from "@amcharts/amcharts5-geodata/worldLow";
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### CDN / script tags
|
|
78
|
+
```html
|
|
79
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
80
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
81
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
82
|
+
<!-- Geodata for maps -->
|
|
83
|
+
<script src="https://cdn.amcharts.com/lib/5/geodata/worldLow.js"></script>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
CDN script objects use `am5` (core), `am5xy`, `am5percent`, `am5map`, `am5hierarchy`, `am5flow`, `am5radar`, `am5stock`, `am5timeline`, `am5wc`, `am5venn`, `am5gantt` namespaces.
|
|
87
|
+
Themes: `am5themes_Animated`, `am5themes_Dark`, etc.
|
|
88
|
+
Geodata: `am5geodata_worldLow`, `am5geodata_usaLow`, etc.
|
|
89
|
+
|
|
90
|
+
### Package → chart type mapping
|
|
91
|
+
|
|
92
|
+
| You need | Import package |
|
|
93
|
+
|----------|---------------|
|
|
94
|
+
| XY chart (line, bar, column, area, candlestick) | `@amcharts/amcharts5/xy` |
|
|
95
|
+
| Pie, donut, funnel, pyramid | `@amcharts/amcharts5/percent` |
|
|
96
|
+
| Map / choropleth | `@amcharts/amcharts5/map` + geodata |
|
|
97
|
+
| Radar / gauge | `@amcharts/amcharts5/radar` (also needs xy) |
|
|
98
|
+
| Treemap, sunburst, force-directed, pack | `@amcharts/amcharts5/hierarchy` |
|
|
99
|
+
| Sankey, chord, arc diagram | `@amcharts/amcharts5/flow` |
|
|
100
|
+
| Stock chart | `@amcharts/amcharts5/stock` |
|
|
101
|
+
| Word cloud | `@amcharts/amcharts5/wc` |
|
|
102
|
+
| Venn diagram | `@amcharts/amcharts5/venn` |
|
|
103
|
+
| Timeline (serpentine, spiral, curve) | `@amcharts/amcharts5/timeline` (also needs xy) |
|
|
104
|
+
| Gantt chart | `@amcharts/amcharts5/gantt` (also needs xy) |
|
|
105
|
+
|
|
106
|
+
## Settings pattern
|
|
107
|
+
|
|
108
|
+
amCharts 5 uses `.set()`, `.setAll()`, and `.get()` — not direct property assignment:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
// ✅ CORRECT
|
|
112
|
+
series.set("valueField", "value");
|
|
113
|
+
series.setAll({ valueField: "value", categoryField: "category" });
|
|
114
|
+
const val = series.get("valueField");
|
|
115
|
+
|
|
116
|
+
// ❌ WRONG
|
|
117
|
+
series.valueField = "value";
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Settings are passed in the second argument of `.new()`:
|
|
121
|
+
```js
|
|
122
|
+
am5xy.LineSeries.new(root, {
|
|
123
|
+
xAxis: xAxis,
|
|
124
|
+
yAxis: yAxis,
|
|
125
|
+
valueYField: "value",
|
|
126
|
+
valueXField: "date"
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Dark theme
|
|
131
|
+
|
|
132
|
+
If the page has a dark background, always include the Dark theme. Without it, labels and grid will be invisible:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
root.setThemes([
|
|
136
|
+
am5themes_Animated.new(root),
|
|
137
|
+
am5themes_Dark.new(root) // must come after Animated
|
|
138
|
+
]);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Rule:** Only add Dark theme when background is clearly dark. Default to white/light with no Dark theme unless the user asks.
|
|
142
|
+
|
|
143
|
+
## Colors — use defaults, don't invent palettes
|
|
144
|
+
|
|
145
|
+
amCharts assigns colors automatically. Do NOT create custom color palettes unless the user explicitly requests specific colors.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
// Get default colors programmatically
|
|
149
|
+
var colors = chart.get("colors"); // XY, radar, etc.
|
|
150
|
+
var colors = series.get("colors"); // pie/percent charts
|
|
151
|
+
|
|
152
|
+
colors.getIndex(0); // color by index (no counter advance)
|
|
153
|
+
colors.next(); // next color in sequence (advances counter)
|
|
154
|
+
colors.reset(); // restart counter
|
|
155
|
+
|
|
156
|
+
// Only if user requests custom colors:
|
|
157
|
+
colors.set("colors", [am5.color(0x095256), am5.color(0x087f8c)]);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Common chart recipes
|
|
161
|
+
|
|
162
|
+
### XY chart with category axis (bar/column)
|
|
163
|
+
```js
|
|
164
|
+
const xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
|
|
165
|
+
categoryField: "category",
|
|
166
|
+
renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 30 })
|
|
167
|
+
}));
|
|
168
|
+
|
|
169
|
+
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
170
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
const series = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
174
|
+
xAxis: xAxis,
|
|
175
|
+
yAxis: yAxis,
|
|
176
|
+
valueYField: "value",
|
|
177
|
+
categoryXField: "category"
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
xAxis.data.setAll(data); // CategoryAxis needs data too!
|
|
181
|
+
series.data.setAll(data);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### XY chart with date axis (time series)
|
|
185
|
+
```js
|
|
186
|
+
const xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
|
|
187
|
+
baseInterval: { timeUnit: "day", count: 1 },
|
|
188
|
+
renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 50 })
|
|
189
|
+
}));
|
|
190
|
+
|
|
191
|
+
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
192
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
193
|
+
}));
|
|
194
|
+
|
|
195
|
+
const series = chart.series.push(am5xy.LineSeries.new(root, {
|
|
196
|
+
xAxis: xAxis,
|
|
197
|
+
yAxis: yAxis,
|
|
198
|
+
valueYField: "value",
|
|
199
|
+
valueXField: "date"
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
// Date values must be timestamps (milliseconds)
|
|
203
|
+
series.data.setAll([
|
|
204
|
+
{ date: new Date(2024, 0, 1).getTime(), value: 100 },
|
|
205
|
+
{ date: new Date(2024, 1, 1).getTime(), value: 120 }
|
|
206
|
+
]);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Pie / Donut chart
|
|
210
|
+
```js
|
|
211
|
+
const chart = root.container.children.push(
|
|
212
|
+
am5percent.PieChart.new(root, {
|
|
213
|
+
innerRadius: am5.percent(50), // 0 for pie, >0 for donut
|
|
214
|
+
layout: root.verticalLayout
|
|
215
|
+
})
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const series = chart.series.push(am5percent.PieSeries.new(root, {
|
|
219
|
+
valueField: "value",
|
|
220
|
+
categoryField: "category"
|
|
221
|
+
}));
|
|
222
|
+
|
|
223
|
+
series.data.setAll([
|
|
224
|
+
{ category: "A", value: 10 },
|
|
225
|
+
{ category: "B", value: 7 },
|
|
226
|
+
{ category: "C", value: 3 }
|
|
227
|
+
]);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Map chart (choropleth)
|
|
231
|
+
```js
|
|
232
|
+
const chart = root.container.children.push(
|
|
233
|
+
am5map.MapChart.new(root, {
|
|
234
|
+
panX: "rotateX",
|
|
235
|
+
projection: am5map.geoMercator()
|
|
236
|
+
})
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const polygonSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
|
|
240
|
+
geoJSON: am5geodata_worldLow,
|
|
241
|
+
valueField: "value",
|
|
242
|
+
calculateAggregates: true
|
|
243
|
+
}));
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Funnel chart
|
|
247
|
+
```js
|
|
248
|
+
const chart = root.container.children.push(
|
|
249
|
+
am5percent.SlicedChart.new(root, { layout: root.verticalLayout })
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const series = chart.series.push(am5percent.FunnelSeries.new(root, {
|
|
253
|
+
name: "Funnel",
|
|
254
|
+
valueField: "value",
|
|
255
|
+
categoryField: "stage",
|
|
256
|
+
orientation: "vertical",
|
|
257
|
+
bottomRatio: 0 // 0 = trapezoids (classic funnel), 1 = rectangles
|
|
258
|
+
}));
|
|
259
|
+
|
|
260
|
+
series.data.setAll([
|
|
261
|
+
{ stage: "Visits", value: 10000 },
|
|
262
|
+
{ stage: "Signups", value: 5200 },
|
|
263
|
+
{ stage: "Paid", value: 1400 }
|
|
264
|
+
]);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Stock chart (candlestick with toolbar)
|
|
268
|
+
```js
|
|
269
|
+
// Requires: index.js, xy.js, stock.js
|
|
270
|
+
// HTML: <div id="chartcontrols"></div> <div id="chartdiv"></div>
|
|
271
|
+
const stockChart = root.container.children.push(
|
|
272
|
+
am5stock.StockChart.new(root, {})
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const mainPanel = stockChart.panels.push(
|
|
276
|
+
am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
const dateAxis = mainPanel.xAxes.push(am5xy.DateAxis.new(root, {
|
|
280
|
+
baseInterval: { timeUnit: "day", count: 1 },
|
|
281
|
+
renderer: am5xy.AxisRendererX.new(root, {})
|
|
282
|
+
}));
|
|
283
|
+
|
|
284
|
+
const valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
285
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
286
|
+
}));
|
|
287
|
+
|
|
288
|
+
const valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
|
|
289
|
+
name: "STCK",
|
|
290
|
+
xAxis: dateAxis, yAxis: valueAxis,
|
|
291
|
+
valueXField: "Date", valueYField: "Close",
|
|
292
|
+
highValueYField: "High", lowValueYField: "Low",
|
|
293
|
+
openValueYField: "Open", calculateAggregates: true
|
|
294
|
+
}));
|
|
295
|
+
|
|
296
|
+
stockChart.set("stockSeries", valueSeries); // CRITICAL: register main series
|
|
297
|
+
valueSeries.data.setAll(data);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Serpentine timeline
|
|
301
|
+
```js
|
|
302
|
+
const chart = root.container.children.push(am5timeline.SerpentineChart.new(root, {
|
|
303
|
+
orientation: "vertical", levelCount: 3,
|
|
304
|
+
yAxisRadius: am5.percent(25), yAxisInnerRadius: -25
|
|
305
|
+
}));
|
|
306
|
+
const yRenderer = am5timeline.AxisRendererCurveY.new(root, {}); // create Y renderer FIRST
|
|
307
|
+
const xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
|
|
308
|
+
baseInterval: { timeUnit: "day", count: 1 },
|
|
309
|
+
renderer: am5timeline.AxisRendererCurveX.new(root, { yRenderer: yRenderer }) // NOT AxisRendererX
|
|
310
|
+
}));
|
|
311
|
+
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
312
|
+
renderer: yRenderer // reuse the same renderer
|
|
313
|
+
}));
|
|
314
|
+
const series = chart.series.push(am5timeline.CurveLineSeries.new(root, { // NOT LineSeries
|
|
315
|
+
xAxis, yAxis, valueYField: "value", valueXField: "date"
|
|
316
|
+
}));
|
|
317
|
+
series.data.setAll(data); // timestamps for DateAxis
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Word cloud
|
|
321
|
+
```js
|
|
322
|
+
// Requires: index.js, wc.js
|
|
323
|
+
const series = root.container.children.push(am5wc.WordCloud.new(root, {
|
|
324
|
+
categoryField: "tag",
|
|
325
|
+
valueField: "weight",
|
|
326
|
+
maxFontSize: am5.percent(20),
|
|
327
|
+
minFontSize: am5.percent(3)
|
|
328
|
+
}));
|
|
329
|
+
|
|
330
|
+
series.labels.template.setAll({ tooltipText: "{category}: {value}" });
|
|
331
|
+
|
|
332
|
+
series.data.setAll([
|
|
333
|
+
{ tag: "JavaScript", weight: 64 },
|
|
334
|
+
{ tag: "Python", weight: 48 },
|
|
335
|
+
{ tag: "React", weight: 28 }
|
|
336
|
+
]);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Venn diagram
|
|
340
|
+
```js
|
|
341
|
+
// Requires: index.js, venn.js
|
|
342
|
+
// NOTE: There is NO VennDiagram class — push Venn directly into a Container
|
|
343
|
+
const container = root.container.children.push(am5.Container.new(root, {
|
|
344
|
+
width: am5.percent(100),
|
|
345
|
+
height: am5.percent(100),
|
|
346
|
+
layout: root.verticalLayout
|
|
347
|
+
}));
|
|
348
|
+
|
|
349
|
+
const series = container.children.push(am5venn.Venn.new(root, {
|
|
350
|
+
categoryField: "name",
|
|
351
|
+
valueField: "value",
|
|
352
|
+
intersectionsField: "sets"
|
|
353
|
+
}));
|
|
354
|
+
|
|
355
|
+
series.data.setAll([
|
|
356
|
+
{ name: "A", value: 100 },
|
|
357
|
+
{ name: "B", value: 80 },
|
|
358
|
+
{ name: "A∩B", value: 30, sets: ["A", "B"] }
|
|
359
|
+
]);
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Gantt chart
|
|
363
|
+
```js
|
|
364
|
+
// Requires: index.js, xy.js, plugins/colorPicker.js, gantt.js
|
|
365
|
+
const chart = root.container.children.push(am5gantt.Gantt.new(root, {
|
|
366
|
+
editable: true,
|
|
367
|
+
durationUnit: "day"
|
|
368
|
+
}));
|
|
369
|
+
|
|
370
|
+
// Gantt uses TWO separate data calls — NOT nested children
|
|
371
|
+
chart.yAxis.data.setAll([
|
|
372
|
+
{ id: "phase1", name: "Phase 1", color: am5.color(0x297373) },
|
|
373
|
+
{ id: "taskA", name: "Task A", parentId: "phase1" },
|
|
374
|
+
{ id: "taskB", name: "Task B", parentId: "phase1" }
|
|
375
|
+
]);
|
|
376
|
+
chart.series.data.setAll([
|
|
377
|
+
{ id: "phase1", start: new Date(2024, 0, 1).getTime(), duration: 10, progress: 100 },
|
|
378
|
+
{ id: "taskA", start: new Date(2024, 0, 1).getTime(), duration: 5, progress: 100 },
|
|
379
|
+
{ id: "taskB", start: new Date(2024, 0, 6).getTime(), duration: 5, progress: 80 }
|
|
380
|
+
]);
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Events
|
|
384
|
+
|
|
385
|
+
```js
|
|
386
|
+
// Click on elements
|
|
387
|
+
series.columns.template.events.on("click", function(ev) {
|
|
388
|
+
console.log("Clicked:", ev.target.dataItem.dataContext);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Lifecycle
|
|
392
|
+
series.events.on("datavalidated", function() { /* data ready */ });
|
|
393
|
+
|
|
394
|
+
// One-time listener
|
|
395
|
+
series.events.once("datavalidated", function() { /* runs once */ });
|
|
396
|
+
|
|
397
|
+
// Setting change watch
|
|
398
|
+
sprite.on("width", function(width) { console.log("Width:", width); });
|
|
399
|
+
|
|
400
|
+
// Remove listener
|
|
401
|
+
var disposer = sprite.events.on("click", handler);
|
|
402
|
+
disposer.dispose();
|
|
403
|
+
|
|
404
|
+
// Common events: click, pointerover, pointerout, pointerdown, globalpointermove
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Adapters
|
|
408
|
+
|
|
409
|
+
Dynamically modify a setting value before it's applied:
|
|
410
|
+
|
|
411
|
+
```js
|
|
412
|
+
series.columns.template.adapters.add("fill", function(fill, target) {
|
|
413
|
+
return target.dataItem.get("valueY") > 100
|
|
414
|
+
? am5.color(0x00cc00)
|
|
415
|
+
: am5.color(0xcc0000);
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## States
|
|
420
|
+
|
|
421
|
+
```js
|
|
422
|
+
series.columns.template.states.create("hover", {
|
|
423
|
+
fillOpacity: 0.8,
|
|
424
|
+
scale: 1.05
|
|
425
|
+
});
|
|
426
|
+
// Built-in states: "hover", "active", "disabled", "hidden"
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Heat rules
|
|
430
|
+
|
|
431
|
+
Color or size elements by data value. Requires `calculateAggregates: true` on the series (unless `minValue`/`maxValue` are set).
|
|
432
|
+
|
|
433
|
+
```js
|
|
434
|
+
// Color columns by value
|
|
435
|
+
series.set("heatRules", [{
|
|
436
|
+
target: series.columns.template,
|
|
437
|
+
dataField: "valueY",
|
|
438
|
+
min: am5.color(0xe5dc36),
|
|
439
|
+
max: am5.color(0x5faa46),
|
|
440
|
+
key: "fill"
|
|
441
|
+
}]);
|
|
442
|
+
|
|
443
|
+
// Scale bullet radius by value — bullets need am5.Template
|
|
444
|
+
var circleTemplate = am5.Template.new({});
|
|
445
|
+
series.bullets.push(function() {
|
|
446
|
+
return am5.Bullet.new(root, {
|
|
447
|
+
sprite: am5.Circle.new(root, {
|
|
448
|
+
fill: series.get("fill")
|
|
449
|
+
}, circleTemplate) // template as 3rd arg
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
series.set("heatRules", [{
|
|
453
|
+
target: circleTemplate,
|
|
454
|
+
dataField: "valueY",
|
|
455
|
+
min: 3, max: 25,
|
|
456
|
+
key: "radius"
|
|
457
|
+
}]);
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Heat rule keys:** `"fill"`, `"radius"`, `"opacity"`, `"strokeWidth"`, `"fontSize"`, etc.
|
|
461
|
+
**customFunction:** `(sprite, min, max, value)` for full control.
|
|
462
|
+
|
|
463
|
+
**HeatLegend:**
|
|
464
|
+
```js
|
|
465
|
+
var heatLegend = chart.children.push(am5.HeatLegend.new(root, {
|
|
466
|
+
orientation: "horizontal",
|
|
467
|
+
startColor: am5.color(0xe5dc36),
|
|
468
|
+
endColor: am5.color(0x5faa46),
|
|
469
|
+
startText: "Low",
|
|
470
|
+
endText: "High",
|
|
471
|
+
stepCount: 5
|
|
472
|
+
}));
|
|
473
|
+
series.events.on("datavalidated", function() {
|
|
474
|
+
heatLegend.set("startValue", series.getPrivate("valueLow"));
|
|
475
|
+
heatLegend.set("endValue", series.getPrivate("valueHigh"));
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Accessibility
|
|
480
|
+
|
|
481
|
+
```js
|
|
482
|
+
series.columns.template.setAll({
|
|
483
|
+
focusable: true,
|
|
484
|
+
ariaLabel: "{categoryX}: {valueY}",
|
|
485
|
+
role: "figure"
|
|
486
|
+
});
|
|
487
|
+
// Keyboard: TAB to navigate focusable elements, ENTER to click
|
|
488
|
+
// focusableGroup: "series1" — TAB to first, arrows within group
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Container & Layout
|
|
492
|
+
|
|
493
|
+
```js
|
|
494
|
+
var container = root.container.children.push(am5.Container.new(root, {
|
|
495
|
+
width: am5.percent(100),
|
|
496
|
+
height: am5.percent(100),
|
|
497
|
+
layout: root.verticalLayout // also: horizontalLayout, gridLayout
|
|
498
|
+
}));
|
|
499
|
+
container.setAll({ paddingTop: 10, paddingBottom: 10, marginLeft: 20 });
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**Layout options:**
|
|
503
|
+
|
|
504
|
+
| Layout | Access | Behavior |
|
|
505
|
+
|--------|--------|----------|
|
|
506
|
+
| Vertical | `root.verticalLayout` | Children stacked top-to-bottom |
|
|
507
|
+
| Horizontal | `root.horizontalLayout` | Children in a row left-to-right |
|
|
508
|
+
| Grid | `root.gridLayout` | Multi-column grid |
|
|
509
|
+
| Custom grid | `am5.GridLayout.new(root, { maxColumns: 3 })` | Grid with custom column count |
|
|
510
|
+
| None | omit `layout` | Children placed at x/y coordinates |
|
|
511
|
+
|
|
512
|
+
## UI Elements
|
|
513
|
+
|
|
514
|
+
amCharts 5 provides built-in interactive UI widgets. **Prefer these over HTML elements** when building controls.
|
|
515
|
+
|
|
516
|
+
| Element | Class | Description |
|
|
517
|
+
|---------|-------|-------------|
|
|
518
|
+
| Button | `am5.Button` | Clickable with label, icon, hover/down/active states |
|
|
519
|
+
| Slider | `am5.Slider` | Single-value slider (0-1 range), fires `rangechanged` |
|
|
520
|
+
| Scrollbar | `am5.Scrollbar` | Two-grip range selector |
|
|
521
|
+
| NumericStepper | `am5.NumericStepper` | Number input with up/down arrows |
|
|
522
|
+
| ProgressPie | `am5.ProgressPie` | Circular progress indicator |
|
|
523
|
+
| SpriteResizer | `am5.SpriteResizer` | Drag-to-resize handles on any sprite |
|
|
524
|
+
| EditableLabel | `am5.EditableLabel` | Label editable on click |
|
|
525
|
+
| Modal | `am5.Modal` | HTML overlay dialog with `open()`/`close()` |
|
|
526
|
+
|
|
527
|
+
```js
|
|
528
|
+
// Slider controlling a chart value
|
|
529
|
+
var slider = container.children.push(am5.Slider.new(root, {
|
|
530
|
+
orientation: "horizontal",
|
|
531
|
+
start: 0.5,
|
|
532
|
+
width: am5.percent(80),
|
|
533
|
+
centerX: am5.percent(50),
|
|
534
|
+
x: am5.percent(50)
|
|
535
|
+
}));
|
|
536
|
+
slider.events.on("rangechanged", function(ev) {
|
|
537
|
+
var value = ev.start; // 0-1 range
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// Button
|
|
541
|
+
var button = container.children.push(am5.Button.new(root, {
|
|
542
|
+
label: am5.Label.new(root, { text: "Reset" }),
|
|
543
|
+
centerX: am5.percent(50),
|
|
544
|
+
x: am5.percent(50)
|
|
545
|
+
}));
|
|
546
|
+
button.events.on("click", function() {
|
|
547
|
+
slider.set("start", 0.5);
|
|
548
|
+
});
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
## Dynamic data
|
|
552
|
+
|
|
553
|
+
```js
|
|
554
|
+
series.data.setAll(newData); // replace all (NO animation)
|
|
555
|
+
series.data.push({ cat: "X", val: 1 }); // add
|
|
556
|
+
series.data.setIndex(0, newItem); // update at index (ANIMATES)
|
|
557
|
+
series.data.removeIndex(2); // remove at index
|
|
558
|
+
series.data.insertIndex(1, newItem); // insert at index
|
|
559
|
+
|
|
560
|
+
// To update data WITH animation, use setIndex() per item:
|
|
561
|
+
// newData.forEach(function(item, i) { series.data.setIndex(i, item); });
|
|
562
|
+
|
|
563
|
+
// IMPORTANT: series.dataItems is a plain array, NOT a List
|
|
564
|
+
// ❌ series.dataItems.each(fn) — will throw
|
|
565
|
+
// ✅ series.dataItems.forEach(fn) — standard JS
|
|
566
|
+
// ✅ am5.array.each(series.dataItems, function(dataItem) {})
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Data processor (for external/API data)
|
|
570
|
+
|
|
571
|
+
```js
|
|
572
|
+
series.data.processor = am5.DataProcessor.new(root, {
|
|
573
|
+
dateFields: ["date"],
|
|
574
|
+
dateFormat: "yyyy-MM-dd",
|
|
575
|
+
numericFields: ["value"],
|
|
576
|
+
emptyAs: 0
|
|
577
|
+
});
|
|
578
|
+
// Configure BEFORE setting data
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
## Common components
|
|
582
|
+
|
|
583
|
+
### Legend
|
|
584
|
+
```js
|
|
585
|
+
const legend = chart.children.push(am5.Legend.new(root, {
|
|
586
|
+
centerX: am5.percent(50),
|
|
587
|
+
x: am5.percent(50)
|
|
588
|
+
}));
|
|
589
|
+
legend.data.setAll(chart.series.values);
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Cursor (XY charts)
|
|
593
|
+
```js
|
|
594
|
+
chart.set("cursor", am5xy.XYCursor.new(root, {
|
|
595
|
+
behavior: "none" // "zoomX", "zoomY", "zoomXY", "selectX", "selectXY", "none"
|
|
596
|
+
}));
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Scrollbar (XY charts)
|
|
600
|
+
```js
|
|
601
|
+
chart.set("scrollbarX", am5.Scrollbar.new(root, {
|
|
602
|
+
orientation: "horizontal"
|
|
603
|
+
}));
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Tooltip
|
|
607
|
+
```js
|
|
608
|
+
series.set("tooltip", am5.Tooltip.new(root, {
|
|
609
|
+
labelText: "{categoryX}: {valueY}"
|
|
610
|
+
}));
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Chart title
|
|
614
|
+
Do NOT add titles as HTML — they won't be part of the canvas or exports. Use `am5.Label` in the container BEFORE the chart, with `verticalLayout`:
|
|
615
|
+
```js
|
|
616
|
+
root.container.children.push(am5.Label.new(root, {
|
|
617
|
+
text: "Chart Title",
|
|
618
|
+
fontSize: "1.3em",
|
|
619
|
+
x: am5.p50,
|
|
620
|
+
centerX: am5.p50
|
|
621
|
+
}));
|
|
622
|
+
root.container.set("layout", root.verticalLayout);
|
|
623
|
+
|
|
624
|
+
var chart = root.container.children.push(am5xy.XYChart.new(root, { ... }));
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
## Key differences from amCharts 4 (common AI mistakes)
|
|
628
|
+
|
|
629
|
+
| amCharts 4 (WRONG) | amCharts 5 (CORRECT) |
|
|
630
|
+
|---------------------|----------------------|
|
|
631
|
+
| `am4core.create("div", am4charts.XYChart)` | `am5.Root.new("div")` then `am5xy.XYChart.new(root, {})` |
|
|
632
|
+
| `new am4charts.CategoryAxis()` | `am5xy.CategoryAxis.new(root, { ... })` |
|
|
633
|
+
| `chart.data = [...]` | `series.data.setAll([...])` |
|
|
634
|
+
| `series.dataFields.valueY = "v"` | `valueYField: "v"` in `.new()` settings |
|
|
635
|
+
| `am4core.color("#f00")` | `am5.color(0xff0000)` or `am5.color("#f00")` |
|
|
636
|
+
| `new am4charts.Legend()` | `am5.Legend.new(root, {})` |
|
|
637
|
+
| `chart.cursor = new am4charts.XYCursor()` | `chart.set("cursor", am5xy.XYCursor.new(root, {}))` |
|
|
638
|
+
| SVG-based rendering | Canvas-based rendering |
|
|
639
|
+
| `am4core.useTheme(am4themes_animated)` | `root.setThemes([am5themes_Animated.new(root)])` |
|
|
640
|
+
|
|
641
|
+
## Common pitfalls
|
|
642
|
+
|
|
643
|
+
1. **CategoryAxis needs data too** — Unlike ValueAxis, CategoryAxis must receive data: `xAxis.data.setAll(data)` in addition to `series.data.setAll(data)`.
|
|
644
|
+
|
|
645
|
+
2. **Date values must be timestamps** — DateAxis expects numbers (ms since epoch), not Date objects or strings. Use `new Date(...).getTime()`.
|
|
646
|
+
|
|
647
|
+
3. **Renderer is required for every axis** — Always pass a `renderer` when creating an axis: `am5xy.AxisRendererX.new(root, {})`.
|
|
648
|
+
|
|
649
|
+
4. **Don't forget `root` in `.new()` calls** — Every `.new()` call (except Root itself) takes `root` as the first arg.
|
|
650
|
+
|
|
651
|
+
5. **Dispose via root** — To clean up, call `root.dispose()`, not `chart.dispose()`.
|
|
652
|
+
|
|
653
|
+
6. **Colors** — Use `am5.color(0xFF0000)` or `am5.color("#ff0000")`. For color sets, access `chart.get("colors")`.
|
|
654
|
+
|
|
655
|
+
7. **Percent values** — Use `am5.percent(50)` not plain `50` or `"50%"` when a setting expects a Percent value.
|
|
656
|
+
|
|
657
|
+
8. **children.push()** — Adding elements to containers uses `.children.push()` which returns the element. Always capture the return value.
|
|
658
|
+
|
|
659
|
+
9. **No CSS styling** — amCharts 5 renders to Canvas, not DOM/SVG. You cannot style chart elements with CSS. Use themes or `.set()`/`.setAll()`.
|
|
660
|
+
|
|
661
|
+
10. **Hierarchy charts are chart-less** — Treemap, force-directed, etc. add series directly to `root.container` (or a wrapper Container), not to a chart object.
|
|
662
|
+
|
|
663
|
+
11. **`dataItems` is a plain array** — `series.dataItems` does NOT have `.each()`. Use `series.dataItems.forEach(fn)` or `am5.array.each(series.dataItems, fn)`. Only `series.data` (the ListData object) has `.each()`.
|
|
664
|
+
|
|
665
|
+
12. **CDN script load order matters** — `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`.
|
|
666
|
+
|
|
667
|
+
13. **No `minorGrid` / `minorTicks` / `minorLabels` objects** — These properties don't exist. Enable minor grid via renderer flags:
|
|
668
|
+
```js
|
|
669
|
+
am5xy.AxisRendererX.new(root, {
|
|
670
|
+
minorGridEnabled: true, // shows minor grid lines
|
|
671
|
+
minorLabelsEnabled: true // optional: shows minor labels
|
|
672
|
+
})
|
|
673
|
+
```
|
|
674
|
+
Style minor elements through theme rules targeting the `"minor"` tag — they auto-inherit main grid appearance but slightly lighter.
|
|
675
|
+
|
|
676
|
+
14. **Flow chart animated bullets go on `series.bullets`, NOT `series.links.template.bullets`** — To animate labels/circles flowing along Sankey/Chord links, use `series.bullets.push()`. Animate `bullet.locationX` (Sankey) or `bullet.locationY` (Chord) from 0→1 with `loops: Infinity`. Use an adapter on opacity based on position for fade effect:
|
|
677
|
+
```js
|
|
678
|
+
// Sankey: use locationX. For Chord: replace ALL locationX with locationY.
|
|
679
|
+
series.bullets.push(function(root, series, dataItem) {
|
|
680
|
+
var label = am5.Label.new(root, {
|
|
681
|
+
text: "${value}B", populateText: true,
|
|
682
|
+
centerX: am5.p50, fill: am5.color(0xffffff)
|
|
683
|
+
});
|
|
684
|
+
var bullet = am5.Bullet.new(root, {
|
|
685
|
+
locationX: 0, sprite: label, autoRotate: true
|
|
686
|
+
});
|
|
687
|
+
bullet.animate({
|
|
688
|
+
key: "locationX", from: 0, to: 1,
|
|
689
|
+
duration: Math.random() * 10000 + 2000, loops: Infinity
|
|
690
|
+
});
|
|
691
|
+
label.adapters.add("opacity", function(opacity) {
|
|
692
|
+
return 0.5 - Math.abs(0.5 - bullet.get("locationX"));
|
|
693
|
+
});
|
|
694
|
+
bullet.on("locationX", function() {
|
|
695
|
+
label.set("opacity", label.get("opacity"));
|
|
696
|
+
});
|
|
697
|
+
return bullet;
|
|
698
|
+
});
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
15. **`MapPointSeries` needs `latitudeField`/`longitudeField` when using `data.setAll()`** — Without these settings, points silently won't appear:
|
|
702
|
+
```js
|
|
703
|
+
// WRONG — points won't show
|
|
704
|
+
am5map.MapPointSeries.new(root, {})
|
|
705
|
+
|
|
706
|
+
// CORRECT — tell the series which fields hold coordinates
|
|
707
|
+
am5map.MapPointSeries.new(root, {
|
|
708
|
+
latitudeField: "latitude",
|
|
709
|
+
longitudeField: "longitude"
|
|
710
|
+
})
|
|
711
|
+
```
|
|
712
|
+
This is NOT needed when using `pushDataItem({ latitude: ..., longitude: ... })` which passes coordinates directly to the data item.
|
|
713
|
+
|
|
714
|
+
16. **`data.setAll()` does NOT animate — use `data.setIndex()` for animated updates** — `series.data.setAll(newData)` replaces everything instantly with no transition. To update data with smooth animation, use `series.data.setIndex(i, newItem)` per item:
|
|
715
|
+
```js
|
|
716
|
+
// WRONG — no animation
|
|
717
|
+
series.data.setAll(newData);
|
|
718
|
+
|
|
719
|
+
// CORRECT — animates each value change
|
|
720
|
+
newData.forEach(function(item, i) {
|
|
721
|
+
series.data.setIndex(i, item);
|
|
722
|
+
});
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
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: `am5.Color.brighten()`, `am5.Color.saturate()`.
|
|
726
|
+
|
|
727
|
+
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.
|
|
728
|
+
|
|
729
|
+
19. **Timeline `AxisRendererCurveX` requires `yRenderer`** — Always create the Y renderer first, then pass it:
|
|
730
|
+
```js
|
|
731
|
+
var yRenderer = am5timeline.AxisRendererCurveY.new(root, {});
|
|
732
|
+
var xRenderer = am5timeline.AxisRendererCurveX.new(root, {
|
|
733
|
+
yRenderer: yRenderer
|
|
734
|
+
});
|
|
735
|
+
```
|
|
736
|
+
Without this, crashes with `Cannot read properties of undefined (reading 'axis')`.
|
|
737
|
+
|
|
738
|
+
20. **Gantt data uses TWO separate calls** — Do NOT use `chart.data.setAll()`. Set categories on `chart.yAxis.data.setAll([{id, name, parentId, color}])` and tasks on `chart.series.data.setAll([{id, start, duration, progress, linkTo}])`. Use flat `parentId` for hierarchy, NOT nested `children` arrays. CDN order: `index.js` → `xy.js` → `plugins/colorPicker.js` → `gantt.js` → `themes/Animated.js`:
|
|
739
|
+
```js
|
|
740
|
+
// WRONG — single data call with nested children
|
|
741
|
+
chart.data.setAll([{ name: "Task", children: [...] }]);
|
|
742
|
+
|
|
743
|
+
// CORRECT — two separate calls with flat parentId hierarchy
|
|
744
|
+
chart.yAxis.data.setAll([
|
|
745
|
+
{ id: "phase1", name: "Phase 1", color: am5.color(0x297373) },
|
|
746
|
+
{ id: "task1", name: "Task 1", parentId: "phase1" }
|
|
747
|
+
]);
|
|
748
|
+
chart.series.data.setAll([
|
|
749
|
+
{ id: "phase1", start: timestamp, duration: 10, progress: 50 },
|
|
750
|
+
{ id: "task1", start: timestamp, duration: 5, progress: 100, linkTo: ["phase1"] }
|
|
751
|
+
]);
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
21. **No continent-level geodata at top-level CDN** — `geodata/europeLow.js` does NOT exist. Use `geodata/region/world/europeLow.js` (global: `am5geodata_region_world_europeLow`) or filter `worldLow` with `include: ["FR", "DE", "ES", ...]`.
|
|
755
|
+
|
|
756
|
+
22. **Do not add chart titles as HTML** — HTML titles are outside the canvas and won't appear in exports. Use `am5.Label` pushed into the container BEFORE the chart, with `verticalLayout` on the container. See "Chart title" in Common components above.
|
|
757
|
+
|
|
758
|
+
23. **`XYChartScrollbar` axes — never use `scrollbar.get("xAxis")`** — Axes passed to the scrollbar constructor are NOT stored as gettable settings. Create axes as separate variables, pass them to the scrollbar, and reuse those same variables for the scrollbar's inner series:
|
|
759
|
+
```js
|
|
760
|
+
// WRONG — scrollbar.get("xAxis") returns undefined
|
|
761
|
+
var sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
|
|
762
|
+
xAxis: scrollbar.get("xAxis"), // undefined!
|
|
763
|
+
yAxis: scrollbar.get("yAxis") // undefined!
|
|
764
|
+
}));
|
|
765
|
+
|
|
766
|
+
// CORRECT — reuse the axis variables
|
|
767
|
+
var sbxAxis = am5xy.DateAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}) });
|
|
768
|
+
var sbyAxis = am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) });
|
|
769
|
+
var scrollbar = am5xy.XYChartScrollbar.new(root, { xAxis: sbxAxis, yAxis: sbyAxis });
|
|
770
|
+
var sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
|
|
771
|
+
xAxis: sbxAxis, yAxis: sbyAxis, valueYField: "value", valueXField: "date"
|
|
772
|
+
}));
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
24. **`am5.color()` only accepts hex integers or CSS strings** — `am5.color(0xff0000)`, `am5.color("#ff0000")`, `am5.color("rgb(255,0,0)")` are valid. `am5.color({ r: 255, g: 0, b: 0 })` is NOT — it throws.
|
|
776
|
+
|
|
777
|
+
25. **`MapChart` has NO `"colors"` setting** — `chart.get("colors")` returns `undefined` on `MapChart`. Only XY, Radar, and Percent charts auto-create a ColorSet. For maps, create your own: `am5.ColorSet.new(root, {})`.
|
|
778
|
+
|
|
779
|
+
26. **`VoronoiTreemap` has NO `.rectangles` property** — Unlike `Treemap` (which has `series.rectangles.template`), `VoronoiTreemap` renders organic polygon cells. Style via `series.nodes.template` and its children, not `.rectangles`.
|
|
780
|
+
27. **Labels with data placeholders need `populateText: true`** — When a Label uses data field placeholders like `text: "{name}"`, you MUST also set `populateText: true`. Without it, the placeholder is not resolved and the label appears blank. This applies everywhere Labels display dynamic data — bullet labels, map point labels, etc. Example: `am5.Label.new(root, { text: "{name}", populateText: true, ... })`.
|
|
781
|
+
|
|
782
|
+
## Disposal (SPA / React / Angular / Vue)
|
|
783
|
+
|
|
784
|
+
**Always call `root.dispose()`** — this cleans up all children, series, and event listeners.
|
|
785
|
+
|
|
786
|
+
```js
|
|
787
|
+
// React
|
|
788
|
+
useLayoutEffect(() => {
|
|
789
|
+
const root = am5.Root.new("chartdiv");
|
|
790
|
+
// ... build chart
|
|
791
|
+
return () => { root.dispose(); };
|
|
792
|
+
}, []);
|
|
793
|
+
|
|
794
|
+
// Angular
|
|
795
|
+
ngOnDestroy() { this.root?.dispose(); }
|
|
796
|
+
|
|
797
|
+
// Vue
|
|
798
|
+
onUnmounted(() => { root.dispose(); });
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
## Verify unfamiliar API before using it
|
|
802
|
+
|
|
803
|
+
If unsure whether a method, property, or setting exists, **verify it** before using it:
|
|
804
|
+
|
|
805
|
+
1. **Primary:** `https://www.amcharts.com/docs/v5/reference/{classname}/` (lowercase, e.g. `LineSeries` → `lineseries`)
|
|
806
|
+
2. **Fallback:** TypeScript source on GitHub — `https://raw.githubusercontent.com/amcharts/amcharts5/master/src/.internal/charts/` — settings interfaces are named `I{ClassName}Settings`
|
|
807
|
+
|
|
808
|
+
Common source paths:
|
|
809
|
+
- XY series: `charts/xy/series/{ClassName}.ts`
|
|
810
|
+
- XY axes: `charts/xy/axes/{ClassName}.ts`
|
|
811
|
+
- Pie: `charts/percent/pie/{ClassName}.ts`
|
|
812
|
+
- Radar: `charts/radar/{ClassName}.ts`
|
|
813
|
+
- Map: `charts/map/{ClassName}.ts`
|
|
814
|
+
- Core sprites: `core/render/{ClassName}.ts`
|
|
815
|
+
|
|
816
|
+
## Documentation reference
|
|
817
|
+
|
|
818
|
+
Full docs: https://www.amcharts.com/docs/v5/
|
|
819
|
+
Demos: https://www.amcharts.com/demos/
|
|
820
|
+
Class reference: https://www.amcharts.com/docs/v5/reference/
|