@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.
@@ -0,0 +1,449 @@
1
+ # Timeline Charts — Curve, Serpentine, Spiral
2
+
3
+ Docs: https://www.amcharts.com/docs/v5/charts/timeline/
4
+
5
+ Timeline charts are "curved XY charts" — they use XY-style axes and series but bend the chart into serpentine, spiral, or custom shapes. Added in amCharts 5.12.0.
6
+
7
+ ## Key differences from XY charts
8
+
9
+ Timeline charts work like XY charts but use **different classes**:
10
+
11
+ | XY class | Timeline equivalent |
12
+ |----------|-------------------|
13
+ | `am5xy.XYChart` | `am5timeline.CurveChart` / `SerpentineChart` / `SpiralChart` |
14
+ | `am5xy.AxisRendererX` | `am5timeline.AxisRendererCurveX` |
15
+ | `am5xy.AxisRendererY` | `am5timeline.AxisRendererCurveY` |
16
+ | `am5xy.LineSeries` | `am5timeline.CurveLineSeries` |
17
+ | `am5xy.ColumnSeries` | `am5timeline.CurveColumnSeries` |
18
+ | `am5xy.XYCursor` | `am5timeline.CurveCursor` |
19
+
20
+ All XY axis types (DateAxis, CategoryAxis, ValueAxis) work — just swap the renderer.
21
+
22
+ ## Imports
23
+
24
+ ### ES modules / TypeScript
25
+ ```ts
26
+ import * as am5 from "@amcharts/amcharts5";
27
+ import * as am5xy from "@amcharts/amcharts5/xy";
28
+ import * as am5timeline from "@amcharts/amcharts5/timeline";
29
+ import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
30
+ ```
31
+
32
+ ### CDN / script tags
33
+ ```html
34
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
35
+ <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
36
+ <script src="https://cdn.amcharts.com/lib/5/timeline.js"></script>
37
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
38
+ ```
39
+
40
+ ## Chart types
41
+
42
+ ### SerpentineChart
43
+
44
+ The easiest starting point. Automatically generates a winding, snake-like path.
45
+
46
+ ```js
47
+ const chart = root.container.children.push(
48
+ am5timeline.SerpentineChart.new(root, {
49
+ orientation: "vertical", // "vertical" | "horizontal"
50
+ levelCount: 3, // number of bends/turns
51
+ yAxisRadius: am5.percent(25), // curve thickness
52
+ yAxisInnerRadius: -25, // inner radius (negative = percentage of radius)
53
+ })
54
+ );
55
+ ```
56
+
57
+ **Serpentine settings:**
58
+
59
+ | Setting | Type | Description |
60
+ |---------|------|-------------|
61
+ | `orientation` | `"vertical"` \| `"horizontal"` | Direction of the snake pattern |
62
+ | `levelCount` | number | Number of turns/bends |
63
+ | `yAxisRadius` | percent/number | Outer radius of the curve |
64
+ | `yAxisInnerRadius` | number | Inner radius (0 = filled, negative = relative) |
65
+
66
+ ### SpiralChart
67
+
68
+ Wraps the chart into a spiral shape.
69
+
70
+ ```js
71
+ const chart = root.container.children.push(
72
+ am5timeline.SpiralChart.new(root, {
73
+ levelCount: 3, // number of spiral rings
74
+ inversed: true, // spiral direction
75
+ endAngle: -135, // end angle in degrees
76
+ yAxisRadius: am5.percent(70),
77
+ yAxisInnerRadius: 0,
78
+ innerRadius: am5.percent(30), // inner hole radius
79
+ })
80
+ );
81
+ ```
82
+
83
+ **Spiral settings:**
84
+
85
+ | Setting | Type | Description |
86
+ |---------|------|-------------|
87
+ | `levelCount` | number | Number of spiral rings |
88
+ | `inversed` | boolean | Spiral direction |
89
+ | `endAngle` | number | Where the spiral ends (degrees) |
90
+ | `innerRadius` | percent/number | Size of the center hole |
91
+
92
+ ### CurveChart
93
+
94
+ The base class — define your own custom shape via control points on the X axis renderer.
95
+
96
+ ```js
97
+ const chart = root.container.children.push(
98
+ am5timeline.CurveChart.new(root, {})
99
+ );
100
+
101
+ // Create Y renderer first, then X renderer with yRenderer + custom points
102
+ const yRenderer = am5timeline.AxisRendererCurveY.new(root, {});
103
+ const xRenderer = am5timeline.AxisRendererCurveX.new(root, {
104
+ yRenderer: yRenderer, // REQUIRED
105
+ // Control points define the curve shape
106
+ points: [
107
+ { x: -400, y: 0 },
108
+ { x: -200, y: -100 },
109
+ { x: 0, y: 0 },
110
+ { x: 200, y: 100 },
111
+ { x: 400, y: 0 }
112
+ ]
113
+ });
114
+ ```
115
+
116
+ ## Axes
117
+
118
+ Same axis types as XY charts, but with Curve renderers.
119
+
120
+ **IMPORTANT:** `AxisRendererCurveX` MUST receive the `yRenderer` reference. Create the Y renderer first, then pass it to the X renderer. Without this, the chart crashes with `Cannot read properties of undefined (reading 'axis')`.
121
+
122
+ ```js
123
+ // Step 1: Create Y renderer FIRST
124
+ const yRenderer = am5timeline.AxisRendererCurveY.new(root, {});
125
+
126
+ // Step 2: Create X renderer and pass yRenderer to it
127
+ const xRenderer = am5timeline.AxisRendererCurveX.new(root, {
128
+ yRenderer: yRenderer // REQUIRED — links the two axes for curve layout
129
+ });
130
+
131
+ // Step 3: Create the axes
132
+ const xAxis = chart.xAxes.push(
133
+ am5xy.DateAxis.new(root, {
134
+ baseInterval: { timeUnit: "day", count: 1 },
135
+ renderer: xRenderer
136
+ })
137
+ );
138
+
139
+ const yAxis = chart.yAxes.push(
140
+ am5xy.ValueAxis.new(root, {
141
+ renderer: yRenderer
142
+ })
143
+ );
144
+ ```
145
+
146
+ **Any XY axis type works:**
147
+ - `am5xy.DateAxis` — most common for timelines
148
+ - `am5xy.CategoryAxis` — discrete items along the curve
149
+ - `am5xy.ValueAxis` — numeric scale
150
+
151
+ **Important:** CategoryAxis still needs its own data: `xAxis.data.setAll(data)`.
152
+
153
+ ## Series
154
+
155
+ Use Curve-prefixed series classes:
156
+
157
+ ```js
158
+ // Line series
159
+ const series = chart.series.push(
160
+ am5timeline.CurveLineSeries.new(root, {
161
+ name: "Events",
162
+ xAxis: xAxis,
163
+ yAxis: yAxis,
164
+ valueYField: "value",
165
+ valueXField: "date", // timestamps for DateAxis
166
+ // or categoryXField // for CategoryAxis
167
+ tooltip: am5.Tooltip.new(root, { labelText: "{valueY}" })
168
+ })
169
+ );
170
+
171
+ // Column series
172
+ const series = chart.series.push(
173
+ am5timeline.CurveColumnSeries.new(root, {
174
+ name: "Events",
175
+ xAxis: xAxis,
176
+ yAxis: yAxis,
177
+ valueYField: "value",
178
+ valueXField: "date",
179
+ tooltip: am5.Tooltip.new(root, { labelText: "{valueY}" })
180
+ })
181
+ );
182
+ ```
183
+
184
+ ## Cursor
185
+
186
+ ```js
187
+ chart.set("cursor", am5timeline.CurveCursor.new(root, {}));
188
+ ```
189
+
190
+ ## Bullets
191
+
192
+ Bullets on timeline charts work the same as XY charts:
193
+
194
+ ```js
195
+ series.bullets.push(function() {
196
+ return am5.Bullet.new(root, {
197
+ sprite: am5.Circle.new(root, {
198
+ radius: 5,
199
+ fill: series.get("fill")
200
+ })
201
+ });
202
+ });
203
+ ```
204
+
205
+ ## Event markers on timeline
206
+
207
+ Use bullets with labels to show discrete events (milestones, releases) along the curve:
208
+
209
+ ```js
210
+ series.bullets.push(function(root, series, dataItem) {
211
+ var dc = dataItem.dataContext;
212
+ if (dc.milestone) {
213
+ return am5.Bullet.new(root, {
214
+ sprite: am5.Container.new(root, {
215
+ children: [
216
+ am5.Circle.new(root, { radius: 8, fill: am5.color(0xff5733) }),
217
+ am5.Label.new(root, {
218
+ text: dc.label || "",
219
+ centerX: am5.percent(50),
220
+ centerY: am5.percent(100),
221
+ dy: -15,
222
+ fontSize: 11,
223
+ populateText: true
224
+ })
225
+ ]
226
+ })
227
+ });
228
+ }
229
+ return am5.Bullet.new(root, {
230
+ sprite: am5.Circle.new(root, { radius: 3, fill: series.get("fill") })
231
+ });
232
+ });
233
+ ```
234
+
235
+ ## Events on timeline elements
236
+
237
+ ```js
238
+ // Click on data points (via bullets)
239
+ series.bullets.push(function() {
240
+ var circle = am5.Circle.new(root, {
241
+ radius: 5,
242
+ fill: series.get("fill"),
243
+ cursorOverStyle: "pointer"
244
+ });
245
+ circle.events.on("click", function(ev) {
246
+ var di = ev.target.dataItem;
247
+ console.log("Clicked:", di.get("valueX"), di.get("valueY"));
248
+ });
249
+ return am5.Bullet.new(root, { sprite: circle });
250
+ });
251
+
252
+ // Click on timeline columns (CurveColumnSeries)
253
+ series.columns.template.events.on("click", function(ev) {
254
+ console.log("Column:", ev.target.dataItem.dataContext);
255
+ });
256
+
257
+ // Cursor position tracking
258
+ chart.get("cursor").events.on("cursormoved", function(ev) {
259
+ var x = xAxis.positionToValue(xAxis.toAxisPosition(ev.target.getPrivate("positionX")));
260
+ console.log("Cursor at:", new Date(x));
261
+ });
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Example: Serpentine timeline with events
267
+
268
+ ```html
269
+ <!DOCTYPE html>
270
+ <html>
271
+ <head>
272
+ <meta charset="UTF-8">
273
+ <title>Serpentine Timeline</title>
274
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
275
+ <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
276
+ <script src="https://cdn.amcharts.com/lib/5/timeline.js"></script>
277
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
278
+ <style>
279
+ #chartdiv { width: 100%; height: 600px; }
280
+ </style>
281
+ </head>
282
+ <body>
283
+ <div id="chartdiv"></div>
284
+ <script>
285
+ var root = am5.Root.new("chartdiv");
286
+ root.setThemes([am5themes_Animated.new(root)]);
287
+
288
+ // Create serpentine chart
289
+ var chart = root.container.children.push(
290
+ am5timeline.SerpentineChart.new(root, {
291
+ orientation: "vertical",
292
+ levelCount: 3,
293
+ yAxisRadius: am5.percent(25),
294
+ yAxisInnerRadius: -25
295
+ })
296
+ );
297
+
298
+ // Create axes — Y renderer first, then pass to X renderer
299
+ var yRenderer = am5timeline.AxisRendererCurveY.new(root, {});
300
+ var xRenderer = am5timeline.AxisRendererCurveX.new(root, {
301
+ yRenderer: yRenderer // REQUIRED
302
+ });
303
+
304
+ var xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
305
+ baseInterval: { timeUnit: "month", count: 1 },
306
+ renderer: xRenderer,
307
+ tooltip: am5.Tooltip.new(root, {})
308
+ }));
309
+
310
+ var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
311
+ renderer: yRenderer
312
+ }));
313
+
314
+ // Create series
315
+ var series = chart.series.push(am5timeline.CurveLineSeries.new(root, {
316
+ name: "Revenue",
317
+ xAxis: xAxis,
318
+ yAxis: yAxis,
319
+ valueYField: "value",
320
+ valueXField: "date",
321
+ tooltip: am5.Tooltip.new(root, { labelText: "{valueY}" })
322
+ }));
323
+
324
+ series.strokes.template.setAll({ strokeWidth: 2 });
325
+ series.fills.template.setAll({ visible: true, fillOpacity: 0.3 });
326
+
327
+ // Add bullets
328
+ series.bullets.push(function() {
329
+ return am5.Bullet.new(root, {
330
+ sprite: am5.Circle.new(root, {
331
+ radius: 4,
332
+ fill: series.get("fill")
333
+ })
334
+ });
335
+ });
336
+
337
+ // Generate data
338
+ var data = [];
339
+ var date = new Date(2024, 0, 1);
340
+ var value = 100;
341
+ for (var i = 0; i < 24; i++) {
342
+ value += Math.round((Math.random() - 0.45) * 20);
343
+ data.push({
344
+ date: new Date(date.getFullYear(), date.getMonth() + i, 1).getTime(),
345
+ value: value
346
+ });
347
+ }
348
+
349
+ series.data.setAll(data);
350
+
351
+ // Cursor
352
+ chart.set("cursor", am5timeline.CurveCursor.new(root, {}));
353
+
354
+ series.appear(1000);
355
+ chart.appear(1000, 100);
356
+ </script>
357
+ </body>
358
+ </html>
359
+ ```
360
+
361
+ ## Example: Spiral chart
362
+
363
+ ```html
364
+ <!DOCTYPE html>
365
+ <html>
366
+ <head>
367
+ <meta charset="UTF-8">
368
+ <title>Spiral Chart</title>
369
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
370
+ <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
371
+ <script src="https://cdn.amcharts.com/lib/5/timeline.js"></script>
372
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
373
+ <style>
374
+ #chartdiv { width: 100%; height: 600px; }
375
+ </style>
376
+ </head>
377
+ <body>
378
+ <div id="chartdiv"></div>
379
+ <script>
380
+ var root = am5.Root.new("chartdiv");
381
+ root.setThemes([am5themes_Animated.new(root)]);
382
+
383
+ var chart = root.container.children.push(
384
+ am5timeline.SpiralChart.new(root, {
385
+ levelCount: 3,
386
+ inversed: true,
387
+ endAngle: -135,
388
+ yAxisRadius: am5.percent(70),
389
+ yAxisInnerRadius: 0,
390
+ innerRadius: am5.percent(30)
391
+ })
392
+ );
393
+
394
+ var yRenderer = am5timeline.AxisRendererCurveY.new(root, {});
395
+ var xRenderer = am5timeline.AxisRendererCurveX.new(root, {
396
+ yRenderer: yRenderer // REQUIRED
397
+ });
398
+
399
+ var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
400
+ categoryField: "category",
401
+ renderer: xRenderer,
402
+ tooltip: am5.Tooltip.new(root, {})
403
+ }));
404
+
405
+ var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
406
+ renderer: yRenderer,
407
+ min: 0
408
+ }));
409
+
410
+ var series = chart.series.push(am5timeline.CurveColumnSeries.new(root, {
411
+ name: "Score",
412
+ xAxis: xAxis,
413
+ yAxis: yAxis,
414
+ valueYField: "value",
415
+ categoryXField: "category",
416
+ tooltip: am5.Tooltip.new(root, { labelText: "{categoryX}: {valueY}" })
417
+ }));
418
+
419
+ series.columns.template.setAll({
420
+ cornerRadiusTL: 5,
421
+ cornerRadiusTR: 5,
422
+ strokeOpacity: 0
423
+ });
424
+
425
+ series.columns.template.adapters.add("fill", function(fill, target) {
426
+ return chart.get("colors").getIndex(series.columns.indexOf(target));
427
+ });
428
+
429
+ var data = [
430
+ { category: "Lithuania", value: 501 },
431
+ { category: "Czechia", value: 301 },
432
+ { category: "Ireland", value: 201 },
433
+ { category: "Germany", value: 165 },
434
+ { category: "Australia", value: 139 },
435
+ { category: "Austria", value: 128 },
436
+ { category: "UK", value: 99 },
437
+ { category: "Belgium", value: 60 },
438
+ { category: "Netherlands", value: 50 }
439
+ ];
440
+
441
+ xAxis.data.setAll(data); // CategoryAxis needs its own data!
442
+ series.data.setAll(data);
443
+
444
+ series.appear(1000);
445
+ chart.appear(1000, 100);
446
+ </script>
447
+ </body>
448
+ </html>
449
+ ```