@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,1150 @@
|
|
|
1
|
+
# XY Charts — Line, Area, Bar, Column, Candlestick, Scatter
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Required imports
|
|
5
|
+
|
|
6
|
+
### ES modules / TypeScript
|
|
7
|
+
```ts
|
|
8
|
+
import * as am5 from "@amcharts/amcharts5";
|
|
9
|
+
import * as am5xy from "@amcharts/amcharts5/xy";
|
|
10
|
+
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### CDN / script tags
|
|
14
|
+
```html
|
|
15
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
16
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
17
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Core setup pattern
|
|
21
|
+
|
|
22
|
+
Every XY chart follows this structure:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// 1. Root
|
|
26
|
+
const root = am5.Root.new("chartdiv");
|
|
27
|
+
|
|
28
|
+
// 2. Theme
|
|
29
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
30
|
+
|
|
31
|
+
// 3. Chart
|
|
32
|
+
const chart = root.container.children.push(
|
|
33
|
+
am5xy.XYChart.new(root, { layout: root.verticalLayout })
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// 4. Axes (X + Y)
|
|
37
|
+
const xAxis = chart.xAxes.push(/* axis */);
|
|
38
|
+
const yAxis = chart.yAxes.push(/* axis */);
|
|
39
|
+
|
|
40
|
+
// 5. Series
|
|
41
|
+
const series = chart.series.push(/* series */);
|
|
42
|
+
|
|
43
|
+
// 6. Optional: cursor, scrollbar, legend
|
|
44
|
+
|
|
45
|
+
// 7. Data — ALWAYS LAST
|
|
46
|
+
series.data.setAll(data);
|
|
47
|
+
|
|
48
|
+
// 8. Animate in
|
|
49
|
+
series.appear(1000);
|
|
50
|
+
chart.appear(1000, 100);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Axis types
|
|
54
|
+
|
|
55
|
+
| Axis class | Use when | Data field prefix | Needs own data? |
|
|
56
|
+
|-----------|----------|-------------------|-----------------|
|
|
57
|
+
| `am5xy.CategoryAxis` | Discrete categories (product names, months) | `category` | **Yes** — `xAxis.data.setAll()` |
|
|
58
|
+
| `am5xy.DateAxis` | Time-based data | `value` (timestamps) | No |
|
|
59
|
+
| `am5xy.ValueAxis` | Numeric values | `value` | No |
|
|
60
|
+
| `am5xy.DurationAxis` | Duration values | `value` | No |
|
|
61
|
+
| `am5xy.GaplessDateAxis` | Time data without gaps | `value` (timestamps) | No |
|
|
62
|
+
|
|
63
|
+
## Series types
|
|
64
|
+
|
|
65
|
+
| Series class | Use for |
|
|
66
|
+
|-------------|---------|
|
|
67
|
+
| `am5xy.LineSeries` | Line and area charts |
|
|
68
|
+
| `am5xy.ColumnSeries` | Vertical columns or horizontal bars |
|
|
69
|
+
| `am5xy.StepLineSeries` | Step/staircase lines |
|
|
70
|
+
| `am5xy.CandlestickSeries` | Financial candlesticks |
|
|
71
|
+
| `am5xy.OHLCSeries` | Financial OHLC |
|
|
72
|
+
| `am5xy.SmoothedXLineSeries` | Smoothed/curved lines (X smooth) |
|
|
73
|
+
| `am5xy.SmoothedXYLineSeries` | Smoothed lines (XY smooth) |
|
|
74
|
+
|
|
75
|
+
## Data field naming convention
|
|
76
|
+
|
|
77
|
+
The field name combines the **value type** + **axis direction**:
|
|
78
|
+
|
|
79
|
+
- Category axis on X → `categoryXField: "category"`
|
|
80
|
+
- Value axis on Y → `valueYField: "value"`
|
|
81
|
+
- Date axis on X → `valueXField: "date"` (dates are numeric timestamps)
|
|
82
|
+
- Open/high/low/close → `openValueYField`, `highValueYField`, `lowValueYField`, `valueYField`
|
|
83
|
+
|
|
84
|
+
## Common additions
|
|
85
|
+
|
|
86
|
+
### Cursor
|
|
87
|
+
```js
|
|
88
|
+
chart.set("cursor", am5xy.XYCursor.new(root, {
|
|
89
|
+
behavior: "none" // "zoomX", "zoomY", "zoomXY", "selectX", "selectXY"
|
|
90
|
+
}));
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Scrollbar
|
|
94
|
+
```js
|
|
95
|
+
chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" }));
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Legend
|
|
99
|
+
```js
|
|
100
|
+
const legend = chart.children.push(am5.Legend.new(root, {
|
|
101
|
+
centerX: am5.percent(50),
|
|
102
|
+
x: am5.percent(50)
|
|
103
|
+
}));
|
|
104
|
+
legend.data.setAll(chart.series.values);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Tooltip on series
|
|
108
|
+
```js
|
|
109
|
+
series.set("tooltip", am5.Tooltip.new(root, {
|
|
110
|
+
labelText: "{name}: {valueY}"
|
|
111
|
+
}));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Stacking
|
|
115
|
+
```js
|
|
116
|
+
// On each series:
|
|
117
|
+
am5xy.ColumnSeries.new(root, {
|
|
118
|
+
stacked: true,
|
|
119
|
+
// ... other settings
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Disposal (SPA frameworks)
|
|
124
|
+
|
|
125
|
+
Always dispose on component unmount:
|
|
126
|
+
```js
|
|
127
|
+
root.dispose();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
# amCharts 5 XY Charts — API Reference
|
|
134
|
+
|
|
135
|
+
Detailed reference for axes, series, and configuration options.
|
|
136
|
+
Full docs: https://www.amcharts.com/docs/v5/charts/xy-chart/
|
|
137
|
+
|
|
138
|
+
## CategoryAxis
|
|
139
|
+
|
|
140
|
+
Used for discrete, non-numeric categories (product names, countries, months as labels).
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
|
|
144
|
+
categoryField: "category",
|
|
145
|
+
renderer: am5xy.AxisRendererX.new(root, {
|
|
146
|
+
minGridDistance: 30,
|
|
147
|
+
cellStartLocation: 0.1, // padding between columns
|
|
148
|
+
cellEndLocation: 0.9
|
|
149
|
+
}),
|
|
150
|
+
tooltip: am5.Tooltip.new(root, {})
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
// CRITICAL: CategoryAxis MUST receive data separately
|
|
154
|
+
xAxis.data.setAll(data);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Key settings:**
|
|
158
|
+
- `categoryField` (required) — field name in data for categories
|
|
159
|
+
- `startLocation` / `endLocation` — 0 to 1, controls where axis starts/ends within first/last category
|
|
160
|
+
- `tooltip` — shows category under cursor
|
|
161
|
+
|
|
162
|
+
**Gotchas:**
|
|
163
|
+
- Category order in axis data and series data must match
|
|
164
|
+
- Forgetting `xAxis.data.setAll()` is the #1 mistake — the chart will render empty
|
|
165
|
+
|
|
166
|
+
## DateAxis
|
|
167
|
+
|
|
168
|
+
Used for time-series data. Values must be **millisecond timestamps** (numbers), not Date objects.
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
const xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
|
|
172
|
+
baseInterval: { timeUnit: "day", count: 1 },
|
|
173
|
+
renderer: am5xy.AxisRendererX.new(root, {
|
|
174
|
+
minGridDistance: 50
|
|
175
|
+
}),
|
|
176
|
+
tooltip: am5.Tooltip.new(root, {})
|
|
177
|
+
}));
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Key settings:**
|
|
181
|
+
- `baseInterval` (required) — smallest data granularity: `{ timeUnit: "minute"|"hour"|"day"|"week"|"month"|"year", count: N }`
|
|
182
|
+
- `groupData: true` — automatically groups data when zoomed out (e.g., daily → monthly)
|
|
183
|
+
- `groupCount: 500` — target number of data items after grouping
|
|
184
|
+
- `groupIntervals` — array of allowed group intervals
|
|
185
|
+
- `markUnitChange: true` — highlights when time unit changes on axis labels (e.g., new month)
|
|
186
|
+
- `tooltipDateFormat` — format string for cursor tooltip
|
|
187
|
+
|
|
188
|
+
**Data format:**
|
|
189
|
+
```js
|
|
190
|
+
series.data.setAll([
|
|
191
|
+
{ date: new Date(2024, 0, 1).getTime(), value: 100 }, // ✅ timestamp
|
|
192
|
+
{ date: 1704067200000, value: 120 }, // ✅ timestamp
|
|
193
|
+
{ date: "2024-01-01", value: 100 }, // ❌ WRONG — string
|
|
194
|
+
{ date: new Date(2024, 0, 1), value: 100 }, // ❌ WRONG — Date object
|
|
195
|
+
]);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## ValueAxis
|
|
199
|
+
|
|
200
|
+
Used for numeric values. Auto-calculates min/max from data.
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
204
|
+
renderer: am5xy.AxisRendererY.new(root, {}),
|
|
205
|
+
// Optional:
|
|
206
|
+
min: 0, // force minimum
|
|
207
|
+
max: 100, // force maximum
|
|
208
|
+
strictMinMax: true, // don't let axis adjust beyond min/max
|
|
209
|
+
logarithmic: false, // log scale
|
|
210
|
+
treatZeroAs: 0.001, // when logarithmic, replace zeros
|
|
211
|
+
numberFormat: "#,###", // custom format
|
|
212
|
+
extraMax: 0.1, // add 10% padding above highest value
|
|
213
|
+
extraMin: 0.1, // add 10% padding below lowest value
|
|
214
|
+
calculateTotals: true, // needed for 100% stacked charts
|
|
215
|
+
maxPrecision: 0 // max decimal places in axis labels
|
|
216
|
+
}));
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## AxisRendererX / AxisRendererY
|
|
220
|
+
|
|
221
|
+
Controls visual rendering of an axis. Every axis MUST have a renderer.
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
am5xy.AxisRendererX.new(root, {
|
|
225
|
+
minGridDistance: 30, // min pixels between grid lines
|
|
226
|
+
opposite: false, // true → show on top/right
|
|
227
|
+
inversed: false, // true → flip direction
|
|
228
|
+
inside: false, // true → labels inside plot area
|
|
229
|
+
cellStartLocation: 0, // 0–1, column start offset
|
|
230
|
+
cellEndLocation: 1, // 0–1, column end offset
|
|
231
|
+
pan: "none", // "zoom" → enable drag-zoom on axis
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Configuring grid lines:**
|
|
236
|
+
```js
|
|
237
|
+
const renderer = yAxis.get("renderer");
|
|
238
|
+
renderer.grid.template.setAll({
|
|
239
|
+
stroke: am5.color(0xcccccc),
|
|
240
|
+
strokeWidth: 1,
|
|
241
|
+
strokeDasharray: [3, 3]
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Configuring axis labels:**
|
|
246
|
+
```js
|
|
247
|
+
renderer.labels.template.setAll({
|
|
248
|
+
fontSize: 12,
|
|
249
|
+
fill: am5.color(0x666666),
|
|
250
|
+
rotation: -45, // rotate labels
|
|
251
|
+
centerY: am5.percent(50),
|
|
252
|
+
centerX: am5.percent(100)
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## LineSeries
|
|
257
|
+
|
|
258
|
+
For line and area charts.
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
const series = chart.series.push(am5xy.LineSeries.new(root, {
|
|
262
|
+
name: "Revenue",
|
|
263
|
+
xAxis: xAxis,
|
|
264
|
+
yAxis: yAxis,
|
|
265
|
+
valueYField: "revenue",
|
|
266
|
+
valueXField: "date", // for DateAxis/ValueAxis on X
|
|
267
|
+
// OR categoryXField: "cat", // for CategoryAxis on X
|
|
268
|
+
tooltip: am5.Tooltip.new(root, { labelText: "{valueY}" }),
|
|
269
|
+
// Visual:
|
|
270
|
+
stroke: am5.color(0x095256),
|
|
271
|
+
fill: am5.color(0x095256),
|
|
272
|
+
// Stacking:
|
|
273
|
+
stacked: false, // true for stacked area
|
|
274
|
+
}));
|
|
275
|
+
|
|
276
|
+
// Make it an area chart:
|
|
277
|
+
series.fills.template.setAll({
|
|
278
|
+
visible: true,
|
|
279
|
+
fillOpacity: 0.3
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Stroke width:
|
|
283
|
+
series.strokes.template.setAll({
|
|
284
|
+
strokeWidth: 2
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Line appearance:**
|
|
289
|
+
- `connect: true` — connect lines over missing data (default: true). Set `false` for line breaks at gaps
|
|
290
|
+
- `minDistance: 10` — min pixel distance between points before simplifying
|
|
291
|
+
|
|
292
|
+
## ColumnSeries
|
|
293
|
+
|
|
294
|
+
For vertical columns or horizontal bars.
|
|
295
|
+
|
|
296
|
+
```js
|
|
297
|
+
const series = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
298
|
+
name: "Sales",
|
|
299
|
+
xAxis: xAxis,
|
|
300
|
+
yAxis: yAxis,
|
|
301
|
+
valueYField: "sales",
|
|
302
|
+
categoryXField: "category", // or valueXField for scatter
|
|
303
|
+
tooltip: am5.Tooltip.new(root, { labelText: "{categoryX}: {valueY}" }),
|
|
304
|
+
stacked: false, // true for stacked columns
|
|
305
|
+
clustered: true, // false to overlap columns
|
|
306
|
+
}));
|
|
307
|
+
|
|
308
|
+
// Column appearance:
|
|
309
|
+
series.columns.template.setAll({
|
|
310
|
+
cornerRadiusTL: 5,
|
|
311
|
+
cornerRadiusTR: 5,
|
|
312
|
+
strokeOpacity: 0,
|
|
313
|
+
width: am5.percent(80), // column width
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Individual column colors from data:
|
|
317
|
+
series.columns.template.adapters.add("fill", (fill, target) => {
|
|
318
|
+
return chart.get("colors").getIndex(series.columns.indexOf(target));
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Horizontal bar chart:** swap axes — put CategoryAxis on Y, ValueAxis on X:
|
|
323
|
+
```js
|
|
324
|
+
const yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, {
|
|
325
|
+
categoryField: "category",
|
|
326
|
+
renderer: am5xy.AxisRendererY.new(root, { inversed: true })
|
|
327
|
+
}));
|
|
328
|
+
const xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
|
|
329
|
+
renderer: am5xy.AxisRendererX.new(root, {})
|
|
330
|
+
}));
|
|
331
|
+
// Series uses categoryYField + valueXField
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## CandlestickSeries
|
|
335
|
+
|
|
336
|
+
For financial OHLC candlestick charts. Requires 4 value fields.
|
|
337
|
+
|
|
338
|
+
```js
|
|
339
|
+
const series = chart.series.push(am5xy.CandlestickSeries.new(root, {
|
|
340
|
+
name: "Price",
|
|
341
|
+
xAxis: xAxis,
|
|
342
|
+
yAxis: yAxis,
|
|
343
|
+
openValueYField: "open",
|
|
344
|
+
highValueYField: "high",
|
|
345
|
+
lowValueYField: "low",
|
|
346
|
+
valueYField: "close",
|
|
347
|
+
valueXField: "date"
|
|
348
|
+
}));
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## XYCursor
|
|
352
|
+
|
|
353
|
+
Adds crosshair and enables tooltips on hover.
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
const cursor = chart.set("cursor", am5xy.XYCursor.new(root, {
|
|
357
|
+
behavior: "none", // "zoomX", "zoomY", "zoomXY", "selectX", "selectXY"
|
|
358
|
+
xAxis: xAxis, // optional: snap to axis
|
|
359
|
+
}));
|
|
360
|
+
|
|
361
|
+
// Customize appearance:
|
|
362
|
+
cursor.lineX.setAll({ stroke: am5.color(0x000000), strokeDasharray: [2, 2] });
|
|
363
|
+
cursor.lineY.setAll({ visible: false });
|
|
364
|
+
|
|
365
|
+
// Snap tooltips to series data points:
|
|
366
|
+
series.set("tooltip", am5.Tooltip.new(root, { labelText: "{valueY}" }));
|
|
367
|
+
chart.set("cursor", am5xy.XYCursor.new(root, { snapToSeries: [series] }));
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Scrollbar
|
|
371
|
+
|
|
372
|
+
Enables zooming/panning via scrollbar. Can optionally include a preview chart.
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
// Simple scrollbar:
|
|
376
|
+
chart.set("scrollbarX", am5.Scrollbar.new(root, {
|
|
377
|
+
orientation: "horizontal"
|
|
378
|
+
}));
|
|
379
|
+
|
|
380
|
+
// Scrollbar with preview chart:
|
|
381
|
+
const scrollbar = am5xy.XYChartScrollbar.new(root, {
|
|
382
|
+
orientation: "horizontal",
|
|
383
|
+
height: 50
|
|
384
|
+
});
|
|
385
|
+
chart.set("scrollbarX", scrollbar);
|
|
386
|
+
|
|
387
|
+
// Push axes into the scrollbar's internal chart
|
|
388
|
+
const sbxAxis = scrollbar.chart.xAxes.push(am5xy.DateAxis.new(root, {
|
|
389
|
+
baseInterval: { timeUnit: "day", count: 1 },
|
|
390
|
+
renderer: am5xy.AxisRendererX.new(root, {})
|
|
391
|
+
}));
|
|
392
|
+
const sbyAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
393
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
394
|
+
}));
|
|
395
|
+
|
|
396
|
+
// Add a series to the scrollbar's chart for the preview
|
|
397
|
+
const sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
|
|
398
|
+
xAxis: sbxAxis,
|
|
399
|
+
yAxis: sbyAxis,
|
|
400
|
+
valueYField: "value",
|
|
401
|
+
valueXField: "date"
|
|
402
|
+
}));
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Legend
|
|
406
|
+
|
|
407
|
+
```js
|
|
408
|
+
const legend = chart.children.push(am5.Legend.new(root, {
|
|
409
|
+
centerX: am5.percent(50),
|
|
410
|
+
x: am5.percent(50),
|
|
411
|
+
layout: root.horizontalLayout // or root.verticalLayout, root.gridLayout
|
|
412
|
+
}));
|
|
413
|
+
legend.data.setAll(chart.series.values);
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Dynamic legend labels (show values under cursor):**
|
|
417
|
+
```js
|
|
418
|
+
const series = chart.series.push(am5xy.LineSeries.new(root, {
|
|
419
|
+
// ...
|
|
420
|
+
legendLabelText: "{name}",
|
|
421
|
+
legendValueText: "{valueY}",
|
|
422
|
+
legendRangeLabelText: "{name}",
|
|
423
|
+
legendRangeValueText: ""
|
|
424
|
+
}));
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Stacking
|
|
428
|
+
|
|
429
|
+
```js
|
|
430
|
+
// Each series in the stack needs stacked: true
|
|
431
|
+
const series1 = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
432
|
+
stacked: true, name: "A", valueYField: "a", /* ... */
|
|
433
|
+
}));
|
|
434
|
+
const series2 = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
435
|
+
stacked: true, name: "B", valueYField: "b", /* ... */
|
|
436
|
+
}));
|
|
437
|
+
|
|
438
|
+
// For 100% stacked:
|
|
439
|
+
// 1. Set calculateTotals on value axis:
|
|
440
|
+
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
441
|
+
calculateTotals: true,
|
|
442
|
+
min: 0, max: 100,
|
|
443
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
444
|
+
}));
|
|
445
|
+
// 2. Use display fields on series:
|
|
446
|
+
am5xy.ColumnSeries.new(root, {
|
|
447
|
+
stacked: true,
|
|
448
|
+
valueYField: "a",
|
|
449
|
+
valueYShow: "valueYTotalPercent", // display as % of total
|
|
450
|
+
/* ... */
|
|
451
|
+
});
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Axis ranges (highlights / reference lines)
|
|
455
|
+
|
|
456
|
+
```js
|
|
457
|
+
// Highlight a value range:
|
|
458
|
+
const rangeDataItem = yAxis.makeDataItem({ value: 50, endValue: 100 });
|
|
459
|
+
const range = yAxis.createAxisRange(rangeDataItem);
|
|
460
|
+
rangeDataItem.get("grid").setAll({ stroke: am5.color(0xff0000), strokeOpacity: 1 });
|
|
461
|
+
rangeDataItem.get("axisFill").setAll({
|
|
462
|
+
fill: am5.color(0xff0000),
|
|
463
|
+
fillOpacity: 0.1,
|
|
464
|
+
visible: true
|
|
465
|
+
});
|
|
466
|
+
rangeDataItem.get("label").setAll({ text: "Target", fill: am5.color(0xff0000) });
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## Scatter / Bubble chart
|
|
470
|
+
|
|
471
|
+
Use `ValueAxis` on both X and Y with `LineSeries` (no connecting line) or `ColumnSeries`.
|
|
472
|
+
|
|
473
|
+
```js
|
|
474
|
+
// Scatter: ValueAxis on both axes
|
|
475
|
+
const xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
|
|
476
|
+
renderer: am5xy.AxisRendererX.new(root, {}),
|
|
477
|
+
tooltip: am5.Tooltip.new(root, {})
|
|
478
|
+
}));
|
|
479
|
+
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
480
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
481
|
+
}));
|
|
482
|
+
|
|
483
|
+
const series = chart.series.push(am5xy.LineSeries.new(root, {
|
|
484
|
+
xAxis: xAxis,
|
|
485
|
+
yAxis: yAxis,
|
|
486
|
+
valueXField: "x",
|
|
487
|
+
valueYField: "y",
|
|
488
|
+
tooltip: am5.Tooltip.new(root, { labelText: "({valueX}, {valueY})" })
|
|
489
|
+
}));
|
|
490
|
+
|
|
491
|
+
// Hide connecting line (scatter, not line chart)
|
|
492
|
+
series.strokes.template.set("visible", false);
|
|
493
|
+
|
|
494
|
+
// Add circle bullets
|
|
495
|
+
series.bullets.push(function(root, series, dataItem) {
|
|
496
|
+
return am5.Bullet.new(root, {
|
|
497
|
+
sprite: am5.Circle.new(root, {
|
|
498
|
+
radius: 5,
|
|
499
|
+
fill: series.get("fill"),
|
|
500
|
+
fillOpacity: 0.7
|
|
501
|
+
})
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Bubble chart: variable-size bullets from data
|
|
506
|
+
series.bullets.push(function(root, series, dataItem) {
|
|
507
|
+
var size = dataItem.dataContext.size || 1;
|
|
508
|
+
return am5.Bullet.new(root, {
|
|
509
|
+
sprite: am5.Circle.new(root, {
|
|
510
|
+
radius: Math.sqrt(size) * 3,
|
|
511
|
+
fill: series.get("fill"),
|
|
512
|
+
fillOpacity: 0.5,
|
|
513
|
+
tooltipText: "{name}: ({valueX}, {valueY}) size: {size}"
|
|
514
|
+
})
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
series.data.setAll([
|
|
519
|
+
{ x: 10, y: 20, size: 50, name: "A" },
|
|
520
|
+
{ x: 30, y: 45, size: 120, name: "B" },
|
|
521
|
+
{ x: 55, y: 15, size: 80, name: "C" }
|
|
522
|
+
]);
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Bullets (data point markers)
|
|
526
|
+
|
|
527
|
+
```js
|
|
528
|
+
// Add circle bullets to a line series
|
|
529
|
+
series.bullets.push(function(root, series, dataItem) {
|
|
530
|
+
return am5.Bullet.new(root, {
|
|
531
|
+
sprite: am5.Circle.new(root, {
|
|
532
|
+
radius: 4,
|
|
533
|
+
fill: series.get("fill"),
|
|
534
|
+
stroke: am5.color(0xffffff),
|
|
535
|
+
strokeWidth: 1
|
|
536
|
+
})
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// Custom bullet (e.g., star, image, label)
|
|
541
|
+
series.bullets.push(function(root, series, dataItem) {
|
|
542
|
+
return am5.Bullet.new(root, {
|
|
543
|
+
sprite: am5.Label.new(root, {
|
|
544
|
+
text: "{valueY}",
|
|
545
|
+
centerX: am5.percent(50),
|
|
546
|
+
centerY: am5.percent(100),
|
|
547
|
+
populateText: true
|
|
548
|
+
})
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// Auto-hide bullets when too close together
|
|
553
|
+
series.set("minBulletDistance", 20);
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## Dual Y-axis (multiple value axes)
|
|
557
|
+
|
|
558
|
+
```js
|
|
559
|
+
// First Y axis (left)
|
|
560
|
+
var yAxis1 = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
561
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
562
|
+
}));
|
|
563
|
+
|
|
564
|
+
// Second Y axis (right)
|
|
565
|
+
var yAxis2 = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
566
|
+
renderer: am5xy.AxisRendererY.new(root, { opposite: true })
|
|
567
|
+
}));
|
|
568
|
+
|
|
569
|
+
// Sync grid lines (optional)
|
|
570
|
+
yAxis2.set("syncWithAxis", yAxis1);
|
|
571
|
+
|
|
572
|
+
// Series on first axis
|
|
573
|
+
var series1 = chart.series.push(am5xy.LineSeries.new(root, {
|
|
574
|
+
name: "Revenue ($)",
|
|
575
|
+
xAxis: xAxis, yAxis: yAxis1,
|
|
576
|
+
valueYField: "revenue", valueXField: "date"
|
|
577
|
+
}));
|
|
578
|
+
|
|
579
|
+
// Series on second axis
|
|
580
|
+
var series2 = chart.series.push(am5xy.LineSeries.new(root, {
|
|
581
|
+
name: "Units Sold",
|
|
582
|
+
xAxis: xAxis, yAxis: yAxis2,
|
|
583
|
+
valueYField: "units", valueXField: "date"
|
|
584
|
+
}));
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
## Axis titles
|
|
588
|
+
|
|
589
|
+
```js
|
|
590
|
+
yAxis.children.unshift(am5.Label.new(root, {
|
|
591
|
+
text: "Revenue ($)",
|
|
592
|
+
rotation: -90,
|
|
593
|
+
y: am5.percent(50),
|
|
594
|
+
centerX: am5.percent(50)
|
|
595
|
+
}));
|
|
596
|
+
|
|
597
|
+
xAxis.children.push(am5.Label.new(root, {
|
|
598
|
+
text: "Month",
|
|
599
|
+
x: am5.percent(50),
|
|
600
|
+
centerX: am5.percent(50)
|
|
601
|
+
}));
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
## Range columns / Waterfall (openValueYField)
|
|
605
|
+
|
|
606
|
+
```js
|
|
607
|
+
// Range columns: each bar spans from openValueY to valueY
|
|
608
|
+
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
609
|
+
xAxis: xAxis, yAxis: yAxis,
|
|
610
|
+
valueYField: "high",
|
|
611
|
+
openValueYField: "low", // bar starts from this value
|
|
612
|
+
categoryXField: "category"
|
|
613
|
+
}));
|
|
614
|
+
|
|
615
|
+
// Waterfall: cumulative bars using calculated open/close values
|
|
616
|
+
// Data should pre-calculate start/end values for each bar
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
## Events on XY elements
|
|
620
|
+
|
|
621
|
+
```js
|
|
622
|
+
// Click on a column
|
|
623
|
+
series.columns.template.events.on("click", function(ev) {
|
|
624
|
+
var data = ev.target.dataItem.dataContext;
|
|
625
|
+
console.log("Clicked:", data);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
// Hover on a data point (line series bullet)
|
|
629
|
+
series.bullets.push(function(root, series, dataItem) {
|
|
630
|
+
var circle = am5.Circle.new(root, { radius: 5, fill: series.get("fill") });
|
|
631
|
+
circle.events.on("pointerover", function() {
|
|
632
|
+
circle.set("scale", 1.5);
|
|
633
|
+
});
|
|
634
|
+
circle.events.on("pointerout", function() {
|
|
635
|
+
circle.set("scale", 1);
|
|
636
|
+
});
|
|
637
|
+
return am5.Bullet.new(root, { sprite: circle });
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// Axis zoom/scroll event
|
|
641
|
+
xAxis.events.on("rangechanged", function() {
|
|
642
|
+
console.log("Axis range changed (zoomed/scrolled)");
|
|
643
|
+
});
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
## Chart settings reference
|
|
647
|
+
|
|
648
|
+
```js
|
|
649
|
+
am5xy.XYChart.new(root, {
|
|
650
|
+
layout: root.verticalLayout, // how children (legend, chart) are laid out
|
|
651
|
+
panX: true, // allow horizontal panning
|
|
652
|
+
panY: false, // allow vertical panning
|
|
653
|
+
wheelX: "panX", // mouse wheel: "panX", "panY", "zoomX", "zoomY", "none"
|
|
654
|
+
wheelY: "zoomX", // mouse wheel vertical
|
|
655
|
+
pinchZoomX: true, // mobile pinch zoom on X
|
|
656
|
+
arrangeFields: false, // auto-arrange overlapping fields
|
|
657
|
+
maxTooltipDistance: 0, // show tooltips for nearby series (-1 = all)
|
|
658
|
+
})
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
# amCharts 5 XY Charts — Working Examples
|
|
664
|
+
|
|
665
|
+
Complete, tested examples ready to use. Each example is self-contained.
|
|
666
|
+
|
|
667
|
+
## Example 1: Column chart with categories
|
|
668
|
+
|
|
669
|
+
A basic vertical bar chart with category axis.
|
|
670
|
+
|
|
671
|
+
```html
|
|
672
|
+
<!DOCTYPE html>
|
|
673
|
+
<html>
|
|
674
|
+
<head>
|
|
675
|
+
<meta charset="UTF-8">
|
|
676
|
+
<title>Column Chart</title>
|
|
677
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
678
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
679
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
680
|
+
<style>
|
|
681
|
+
#chartdiv { width: 100%; height: 500px; }
|
|
682
|
+
</style>
|
|
683
|
+
</head>
|
|
684
|
+
<body>
|
|
685
|
+
<div id="chartdiv"></div>
|
|
686
|
+
<script>
|
|
687
|
+
// Create root
|
|
688
|
+
var root = am5.Root.new("chartdiv");
|
|
689
|
+
|
|
690
|
+
// Set theme
|
|
691
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
692
|
+
|
|
693
|
+
// Create chart
|
|
694
|
+
var chart = root.container.children.push(am5xy.XYChart.new(root, {
|
|
695
|
+
panX: true,
|
|
696
|
+
panY: false,
|
|
697
|
+
wheelX: "panX",
|
|
698
|
+
wheelY: "zoomX",
|
|
699
|
+
layout: root.verticalLayout
|
|
700
|
+
}));
|
|
701
|
+
|
|
702
|
+
// Data
|
|
703
|
+
var data = [
|
|
704
|
+
{ category: "Research", value: 1000 },
|
|
705
|
+
{ category: "Marketing", value: 1200 },
|
|
706
|
+
{ category: "Sales", value: 850 },
|
|
707
|
+
{ category: "Support", value: 600 },
|
|
708
|
+
{ category: "Development", value: 1500 }
|
|
709
|
+
];
|
|
710
|
+
|
|
711
|
+
// Create axes
|
|
712
|
+
var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
|
|
713
|
+
categoryField: "category",
|
|
714
|
+
renderer: am5xy.AxisRendererX.new(root, {
|
|
715
|
+
minGridDistance: 30,
|
|
716
|
+
cellStartLocation: 0.1,
|
|
717
|
+
cellEndLocation: 0.9
|
|
718
|
+
}),
|
|
719
|
+
tooltip: am5.Tooltip.new(root, {})
|
|
720
|
+
}));
|
|
721
|
+
xAxis.data.setAll(data); // CategoryAxis MUST receive data
|
|
722
|
+
|
|
723
|
+
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
724
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
725
|
+
}));
|
|
726
|
+
|
|
727
|
+
// Create series
|
|
728
|
+
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
729
|
+
name: "Revenue",
|
|
730
|
+
xAxis: xAxis,
|
|
731
|
+
yAxis: yAxis,
|
|
732
|
+
valueYField: "value",
|
|
733
|
+
categoryXField: "category",
|
|
734
|
+
tooltip: am5.Tooltip.new(root, {
|
|
735
|
+
labelText: "{categoryX}: ${valueY}"
|
|
736
|
+
})
|
|
737
|
+
}));
|
|
738
|
+
|
|
739
|
+
series.columns.template.setAll({
|
|
740
|
+
cornerRadiusTL: 5,
|
|
741
|
+
cornerRadiusTR: 5,
|
|
742
|
+
strokeOpacity: 0
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
// Assign individual colors from chart's color set
|
|
746
|
+
series.columns.template.adapters.add("fill", function (fill, target) {
|
|
747
|
+
return chart.get("colors").getIndex(series.columns.indexOf(target));
|
|
748
|
+
});
|
|
749
|
+
series.columns.template.adapters.add("stroke", function (stroke, target) {
|
|
750
|
+
return chart.get("colors").getIndex(series.columns.indexOf(target));
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
// Set data LAST
|
|
754
|
+
series.data.setAll(data);
|
|
755
|
+
|
|
756
|
+
// Animate
|
|
757
|
+
series.appear(1000);
|
|
758
|
+
chart.appear(1000, 100);
|
|
759
|
+
</script>
|
|
760
|
+
</body>
|
|
761
|
+
</html>
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
## Example 2: Multi-series line chart with date axis
|
|
765
|
+
|
|
766
|
+
A time-series line chart with two series, cursor, scrollbar, and legend.
|
|
767
|
+
|
|
768
|
+
```html
|
|
769
|
+
<!DOCTYPE html>
|
|
770
|
+
<html>
|
|
771
|
+
<head>
|
|
772
|
+
<meta charset="UTF-8">
|
|
773
|
+
<title>Multi-Series Line Chart</title>
|
|
774
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
775
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
776
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
777
|
+
<style>
|
|
778
|
+
#chartdiv { width: 100%; height: 500px; }
|
|
779
|
+
</style>
|
|
780
|
+
</head>
|
|
781
|
+
<body>
|
|
782
|
+
<div id="chartdiv"></div>
|
|
783
|
+
<script>
|
|
784
|
+
var root = am5.Root.new("chartdiv");
|
|
785
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
786
|
+
|
|
787
|
+
var chart = root.container.children.push(am5xy.XYChart.new(root, {
|
|
788
|
+
panX: true,
|
|
789
|
+
panY: false,
|
|
790
|
+
wheelX: "panX",
|
|
791
|
+
wheelY: "zoomX",
|
|
792
|
+
layout: root.verticalLayout
|
|
793
|
+
}));
|
|
794
|
+
|
|
795
|
+
// Generate sample date-based data
|
|
796
|
+
var data = [];
|
|
797
|
+
var date = new Date(2024, 0, 1);
|
|
798
|
+
var revenue = 100;
|
|
799
|
+
var expenses = 80;
|
|
800
|
+
|
|
801
|
+
for (var i = 0; i < 90; i++) {
|
|
802
|
+
revenue += Math.round((Math.random() - 0.48) * 10);
|
|
803
|
+
expenses += Math.round((Math.random() - 0.5) * 8);
|
|
804
|
+
data.push({
|
|
805
|
+
date: date.getTime(), // Must be timestamp!
|
|
806
|
+
revenue: revenue,
|
|
807
|
+
expenses: expenses
|
|
808
|
+
});
|
|
809
|
+
date.setDate(date.getDate() + 1);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Axes
|
|
813
|
+
var xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
|
|
814
|
+
baseInterval: { timeUnit: "day", count: 1 },
|
|
815
|
+
renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 50 }),
|
|
816
|
+
tooltip: am5.Tooltip.new(root, {})
|
|
817
|
+
}));
|
|
818
|
+
|
|
819
|
+
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
820
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
821
|
+
}));
|
|
822
|
+
|
|
823
|
+
// Helper function to create series
|
|
824
|
+
function createSeries(name, field) {
|
|
825
|
+
var series = chart.series.push(am5xy.LineSeries.new(root, {
|
|
826
|
+
name: name,
|
|
827
|
+
xAxis: xAxis,
|
|
828
|
+
yAxis: yAxis,
|
|
829
|
+
valueYField: field,
|
|
830
|
+
valueXField: "date",
|
|
831
|
+
tooltip: am5.Tooltip.new(root, {
|
|
832
|
+
labelText: "{name}: {valueY}"
|
|
833
|
+
})
|
|
834
|
+
}));
|
|
835
|
+
|
|
836
|
+
series.strokes.template.setAll({ strokeWidth: 2 });
|
|
837
|
+
series.data.setAll(data);
|
|
838
|
+
series.appear(1000);
|
|
839
|
+
return series;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
createSeries("Revenue", "revenue");
|
|
843
|
+
createSeries("Expenses", "expenses");
|
|
844
|
+
|
|
845
|
+
// Cursor
|
|
846
|
+
chart.set("cursor", am5xy.XYCursor.new(root, {
|
|
847
|
+
behavior: "none"
|
|
848
|
+
}));
|
|
849
|
+
|
|
850
|
+
// Scrollbar
|
|
851
|
+
chart.set("scrollbarX", am5.Scrollbar.new(root, {
|
|
852
|
+
orientation: "horizontal"
|
|
853
|
+
}));
|
|
854
|
+
|
|
855
|
+
// Legend
|
|
856
|
+
var legend = chart.children.push(am5.Legend.new(root, {
|
|
857
|
+
centerX: am5.percent(50),
|
|
858
|
+
x: am5.percent(50)
|
|
859
|
+
}));
|
|
860
|
+
legend.data.setAll(chart.series.values);
|
|
861
|
+
|
|
862
|
+
chart.appear(1000, 100);
|
|
863
|
+
</script>
|
|
864
|
+
</body>
|
|
865
|
+
</html>
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
## Example 3: Stacked area chart
|
|
869
|
+
|
|
870
|
+
Area chart with three stacked series.
|
|
871
|
+
|
|
872
|
+
```html
|
|
873
|
+
<!DOCTYPE html>
|
|
874
|
+
<html>
|
|
875
|
+
<head>
|
|
876
|
+
<meta charset="UTF-8">
|
|
877
|
+
<title>Stacked Area Chart</title>
|
|
878
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
879
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
880
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
881
|
+
<style>
|
|
882
|
+
#chartdiv { width: 100%; height: 500px; }
|
|
883
|
+
</style>
|
|
884
|
+
</head>
|
|
885
|
+
<body>
|
|
886
|
+
<div id="chartdiv"></div>
|
|
887
|
+
<script>
|
|
888
|
+
var root = am5.Root.new("chartdiv");
|
|
889
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
890
|
+
|
|
891
|
+
var chart = root.container.children.push(am5xy.XYChart.new(root, {
|
|
892
|
+
panX: true,
|
|
893
|
+
panY: false,
|
|
894
|
+
wheelX: "panX",
|
|
895
|
+
wheelY: "zoomX",
|
|
896
|
+
layout: root.verticalLayout
|
|
897
|
+
}));
|
|
898
|
+
|
|
899
|
+
var data = [
|
|
900
|
+
{ year: "2019", mobile: 250, desktop: 580, tablet: 120 },
|
|
901
|
+
{ year: "2020", mobile: 300, desktop: 550, tablet: 150 },
|
|
902
|
+
{ year: "2021", mobile: 380, desktop: 500, tablet: 170 },
|
|
903
|
+
{ year: "2022", mobile: 450, desktop: 460, tablet: 190 },
|
|
904
|
+
{ year: "2023", mobile: 520, desktop: 420, tablet: 200 },
|
|
905
|
+
{ year: "2024", mobile: 600, desktop: 380, tablet: 210 }
|
|
906
|
+
];
|
|
907
|
+
|
|
908
|
+
var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
|
|
909
|
+
categoryField: "year",
|
|
910
|
+
renderer: am5xy.AxisRendererX.new(root, {}),
|
|
911
|
+
tooltip: am5.Tooltip.new(root, {})
|
|
912
|
+
}));
|
|
913
|
+
xAxis.data.setAll(data);
|
|
914
|
+
|
|
915
|
+
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
|
|
916
|
+
renderer: am5xy.AxisRendererY.new(root, {})
|
|
917
|
+
}));
|
|
918
|
+
|
|
919
|
+
function createSeries(name, field) {
|
|
920
|
+
var series = chart.series.push(am5xy.LineSeries.new(root, {
|
|
921
|
+
name: name,
|
|
922
|
+
xAxis: xAxis,
|
|
923
|
+
yAxis: yAxis,
|
|
924
|
+
stacked: true,
|
|
925
|
+
valueYField: field,
|
|
926
|
+
categoryXField: "year",
|
|
927
|
+
tooltip: am5.Tooltip.new(root, {
|
|
928
|
+
labelText: "{name}: {valueY}"
|
|
929
|
+
})
|
|
930
|
+
}));
|
|
931
|
+
|
|
932
|
+
// Enable area fill
|
|
933
|
+
series.fills.template.setAll({
|
|
934
|
+
visible: true,
|
|
935
|
+
fillOpacity: 0.5
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
series.strokes.template.setAll({ strokeWidth: 2 });
|
|
939
|
+
series.data.setAll(data);
|
|
940
|
+
series.appear(1000);
|
|
941
|
+
return series;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
createSeries("Mobile", "mobile");
|
|
945
|
+
createSeries("Desktop", "desktop");
|
|
946
|
+
createSeries("Tablet", "tablet");
|
|
947
|
+
|
|
948
|
+
// Cursor
|
|
949
|
+
chart.set("cursor", am5xy.XYCursor.new(root, {}));
|
|
950
|
+
|
|
951
|
+
// Legend
|
|
952
|
+
var legend = chart.children.push(am5.Legend.new(root, {
|
|
953
|
+
centerX: am5.percent(50),
|
|
954
|
+
x: am5.percent(50)
|
|
955
|
+
}));
|
|
956
|
+
legend.data.setAll(chart.series.values);
|
|
957
|
+
|
|
958
|
+
chart.appear(1000, 100);
|
|
959
|
+
</script>
|
|
960
|
+
</body>
|
|
961
|
+
</html>
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
## Example 4: Horizontal bar chart
|
|
965
|
+
|
|
966
|
+
Bars extending horizontally — swap category to Y axis.
|
|
967
|
+
|
|
968
|
+
```html
|
|
969
|
+
<!DOCTYPE html>
|
|
970
|
+
<html>
|
|
971
|
+
<head>
|
|
972
|
+
<meta charset="UTF-8">
|
|
973
|
+
<title>Horizontal Bar Chart</title>
|
|
974
|
+
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
975
|
+
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
|
|
976
|
+
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
977
|
+
<style>
|
|
978
|
+
#chartdiv { width: 100%; height: 500px; }
|
|
979
|
+
</style>
|
|
980
|
+
</head>
|
|
981
|
+
<body>
|
|
982
|
+
<div id="chartdiv"></div>
|
|
983
|
+
<script>
|
|
984
|
+
var root = am5.Root.new("chartdiv");
|
|
985
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
986
|
+
|
|
987
|
+
var chart = root.container.children.push(am5xy.XYChart.new(root, {
|
|
988
|
+
panX: false,
|
|
989
|
+
panY: true,
|
|
990
|
+
wheelX: "none",
|
|
991
|
+
wheelY: "panY",
|
|
992
|
+
layout: root.verticalLayout
|
|
993
|
+
}));
|
|
994
|
+
|
|
995
|
+
var data = [
|
|
996
|
+
{ country: "United States", visits: 4025 },
|
|
997
|
+
{ country: "China", visits: 1882 },
|
|
998
|
+
{ country: "Japan", visits: 1809 },
|
|
999
|
+
{ country: "Germany", visits: 1322 },
|
|
1000
|
+
{ country: "United Kingdom", visits: 1122 },
|
|
1001
|
+
{ country: "France", visits: 1114 },
|
|
1002
|
+
{ country: "India", visits: 984 },
|
|
1003
|
+
{ country: "Spain", visits: 711 }
|
|
1004
|
+
];
|
|
1005
|
+
|
|
1006
|
+
// Note: CategoryAxis on Y, ValueAxis on X
|
|
1007
|
+
var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, {
|
|
1008
|
+
categoryField: "country",
|
|
1009
|
+
renderer: am5xy.AxisRendererY.new(root, {
|
|
1010
|
+
inversed: true, // top-to-bottom order
|
|
1011
|
+
cellStartLocation: 0.1,
|
|
1012
|
+
cellEndLocation: 0.9
|
|
1013
|
+
})
|
|
1014
|
+
}));
|
|
1015
|
+
yAxis.data.setAll(data);
|
|
1016
|
+
|
|
1017
|
+
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
|
|
1018
|
+
renderer: am5xy.AxisRendererX.new(root, {}),
|
|
1019
|
+
min: 0
|
|
1020
|
+
}));
|
|
1021
|
+
|
|
1022
|
+
// Note: categoryYField + valueXField (swapped from vertical)
|
|
1023
|
+
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
|
|
1024
|
+
name: "Visits",
|
|
1025
|
+
xAxis: xAxis,
|
|
1026
|
+
yAxis: yAxis,
|
|
1027
|
+
valueXField: "visits",
|
|
1028
|
+
categoryYField: "country",
|
|
1029
|
+
tooltip: am5.Tooltip.new(root, {
|
|
1030
|
+
labelText: "{categoryY}: {valueX}"
|
|
1031
|
+
})
|
|
1032
|
+
}));
|
|
1033
|
+
|
|
1034
|
+
series.columns.template.setAll({
|
|
1035
|
+
cornerRadiusBR: 5,
|
|
1036
|
+
cornerRadiusTR: 5,
|
|
1037
|
+
strokeOpacity: 0
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
series.columns.template.adapters.add("fill", function (fill, target) {
|
|
1041
|
+
return chart.get("colors").getIndex(series.columns.indexOf(target));
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
series.data.setAll(data);
|
|
1045
|
+
series.appear(1000);
|
|
1046
|
+
chart.appear(1000, 100);
|
|
1047
|
+
</script>
|
|
1048
|
+
</body>
|
|
1049
|
+
</html>
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
## Example 5: TypeScript + ES modules (framework-ready)
|
|
1053
|
+
|
|
1054
|
+
Suitable for React, Angular, Vue, or any bundled project.
|
|
1055
|
+
|
|
1056
|
+
```ts
|
|
1057
|
+
import * as am5 from "@amcharts/amcharts5";
|
|
1058
|
+
import * as am5xy from "@amcharts/amcharts5/xy";
|
|
1059
|
+
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
|
|
1060
|
+
|
|
1061
|
+
export function createChart(elementId: string): am5.Root {
|
|
1062
|
+
const root = am5.Root.new(elementId);
|
|
1063
|
+
root.setThemes([am5themes_Animated.new(root)]);
|
|
1064
|
+
|
|
1065
|
+
const chart = root.container.children.push(
|
|
1066
|
+
am5xy.XYChart.new(root, {
|
|
1067
|
+
panX: true,
|
|
1068
|
+
panY: false,
|
|
1069
|
+
wheelX: "panX",
|
|
1070
|
+
wheelY: "zoomX",
|
|
1071
|
+
layout: root.verticalLayout,
|
|
1072
|
+
})
|
|
1073
|
+
);
|
|
1074
|
+
|
|
1075
|
+
const xAxis = chart.xAxes.push(
|
|
1076
|
+
am5xy.DateAxis.new(root, {
|
|
1077
|
+
baseInterval: { timeUnit: "month", count: 1 },
|
|
1078
|
+
renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 50 }),
|
|
1079
|
+
tooltip: am5.Tooltip.new(root, {}),
|
|
1080
|
+
})
|
|
1081
|
+
);
|
|
1082
|
+
|
|
1083
|
+
const yAxis = chart.yAxes.push(
|
|
1084
|
+
am5xy.ValueAxis.new(root, {
|
|
1085
|
+
renderer: am5xy.AxisRendererY.new(root, {}),
|
|
1086
|
+
})
|
|
1087
|
+
);
|
|
1088
|
+
|
|
1089
|
+
const series = chart.series.push(
|
|
1090
|
+
am5xy.LineSeries.new(root, {
|
|
1091
|
+
name: "Series 1",
|
|
1092
|
+
xAxis: xAxis,
|
|
1093
|
+
yAxis: yAxis,
|
|
1094
|
+
valueYField: "value",
|
|
1095
|
+
valueXField: "date",
|
|
1096
|
+
tooltip: am5.Tooltip.new(root, { labelText: "{valueY}" }),
|
|
1097
|
+
})
|
|
1098
|
+
);
|
|
1099
|
+
|
|
1100
|
+
series.fills.template.setAll({ visible: true, fillOpacity: 0.2 });
|
|
1101
|
+
|
|
1102
|
+
chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "none" }));
|
|
1103
|
+
chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" }));
|
|
1104
|
+
|
|
1105
|
+
const legend = chart.children.push(
|
|
1106
|
+
am5.Legend.new(root, {
|
|
1107
|
+
centerX: am5.percent(50),
|
|
1108
|
+
x: am5.percent(50),
|
|
1109
|
+
})
|
|
1110
|
+
);
|
|
1111
|
+
legend.data.setAll(chart.series.values);
|
|
1112
|
+
|
|
1113
|
+
// Set data
|
|
1114
|
+
const data: Array<{ date: number; value: number }> = [];
|
|
1115
|
+
let value = 100;
|
|
1116
|
+
for (let i = 0; i < 24; i++) {
|
|
1117
|
+
value += Math.round((Math.random() - 0.45) * 20);
|
|
1118
|
+
data.push({
|
|
1119
|
+
date: new Date(2023, i, 1).getTime(),
|
|
1120
|
+
value: value,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
series.data.setAll(data);
|
|
1125
|
+
series.appear(1000);
|
|
1126
|
+
chart.appear(1000, 100);
|
|
1127
|
+
|
|
1128
|
+
// Return root so caller can dispose: root.dispose()
|
|
1129
|
+
return root;
|
|
1130
|
+
}
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
**React usage:**
|
|
1134
|
+
```tsx
|
|
1135
|
+
import { useLayoutEffect, useRef } from "react";
|
|
1136
|
+
import { createChart } from "./chart";
|
|
1137
|
+
|
|
1138
|
+
export function ChartComponent() {
|
|
1139
|
+
const chartRef = useRef<am5.Root | null>(null);
|
|
1140
|
+
|
|
1141
|
+
useLayoutEffect(() => {
|
|
1142
|
+
chartRef.current = createChart("chartdiv");
|
|
1143
|
+
return () => {
|
|
1144
|
+
chartRef.current?.dispose();
|
|
1145
|
+
};
|
|
1146
|
+
}, []);
|
|
1147
|
+
|
|
1148
|
+
return <div id="chartdiv" style={{ width: "100%", height: "500px" }} />;
|
|
1149
|
+
}
|
|
1150
|
+
```
|