I'm trying to implement a radar chart using amCharts5 in Angular from this demo (https://www.amcharts.com/demos/radar-chart-visualizing-yearly-activities/#code). But at this area I'm getting the error: ERROR TypeError: Cannot read properties of undefined (reading 'root')
// add bullet
let circleTemplate: am5.Template<am5.Circle> = am5.Template.new({});
bubbleSeries.bullets.push(function () {
console.log("Root: ", this.root);
let graphics = am5.Circle.new(this.root, {
fill: distanceSeries.get("fill"),
tooltipText: "{title}: {value} km"
}, circleTemplate);
return am5.Bullet.new(this.root, {
sprite: graphics
});
});
I also tried to console root
value. Before the bubbleSeries.bullets.push()
the root
value is there, but inside it I'm getting the error. Below is my complete code.
radar-chart.component.html
<div id="radarChart" style="width: 100%; height: 100%;"></div>
radar-chart.component.ts
import { Component, OnInit, AfterViewInit } from '@angular/core';
import * as am5 from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
import * as am5radar from "@amcharts/amcharts5/radar";
import am5themes_Animated from '@amcharts/amcharts5/themes/Animated';
@Component({
selector: 'app-radar-chart',
templateUrl: './radar-chart.component.html',
styleUrls: ['./radar-chart.component.css']
})
export class RadarChartComponent implements OnInit, AfterViewInit {
data = [
{
"Activity Date": "2019-04-07",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 16901.30078125,
"Moving Time": 4731
},
{
"Activity Date": "2019-04-08",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 10051.400390625,
"Moving Time": 2123
},
{
"Activity Date": "2019-04-25",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 31012,
"Moving Time": 7902
},
{
"Activity Date": "2019-04-30",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 8279,
"Moving Time": 2401
},
{
"Activity Date": "2019-05-01",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 65781,
"Moving Time": 11690
},
{
"Activity Date": "2019-05-09",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 18331.599609375,
"Moving Time": 4706
},
{
"Activity Date": "2019-05-05",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 23213,
"Moving Time": 9471
},
{
"Activity Date": "2019-05-10",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 55106,
"Moving Time": 12755
},
{
"Activity Date": "2019-05-11",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 67423,
"Moving Time": 15667
},
{
"Activity Date": "2019-05-12",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 31127,
"Moving Time": 6157
},
{
"Activity Date": "2019-05-12",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 16067,
"Moving Time": 4087
},
{
"Activity Date": "2019-05-14",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 38208,
"Moving Time": 8931
},
{
"Activity Date": "2019-05-15",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 115606,
"Moving Time": 26471
},
{
"Activity Date": "2019-05-16",
"Activity Name": "Palma de Mallorca day 3",
"Activity Type": "Ride",
"Distance": 110470,
"Moving Time": 22967
},
{
"Activity Date": "2019-05-17",
"Activity Name": "Sa Colabra epic ride",
"Activity Type": "Ride",
"Distance": 67143,
"Moving Time": 18009
},
{
"Activity Date": "2019-05-18",
"Activity Name": "Mallorka last day",
"Activity Type": "Ride",
"Distance": 87590,
"Moving Time": 18553
},
{
"Activity Date": "2019-05-24",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 21088,
"Moving Time": 2555
},
{
"Activity Date": "2019-05-25",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 53361,
"Moving Time": 8473
},
{
"Activity Date": "2019-05-26",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 13463.7001953125,
"Moving Time": 3768
},
{
"Activity Date": "2019-05-26",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 14177.2001953125,
"Moving Time": 3642
},
{
"Activity Date": "2019-06-01",
"Activity Name": "3.5 karto Juodkrantė - Klaipėda",
"Activity Type": "Ride",
"Distance": 75997,
"Moving Time": 14452
},
{
"Activity Date": "2019-06-27",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 44062,
"Moving Time": 6016
},
{
"Activity Date": "2019-06-30",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 8756,
"Moving Time": 3242
},
{
"Activity Date": "2019-07-01",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 27867,
"Moving Time": 6479
},
{
"Activity Date": "2019-07-02",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 21775,
"Moving Time": 5256
},
{
"Activity Date": "2019-07-02",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 7343,
"Moving Time": 2064
},
{
"Activity Date": "2019-07-03",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 26956,
"Moving Time": 6879
},
{
"Activity Date": "2019-07-04",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 14175,
"Moving Time": 3617
},
{
"Activity Date": "2019-07-07",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 45489,
"Moving Time": 11656
},
{
"Activity Date": "2019-07-09",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 10049,
"Moving Time": 1767
},
{
"Activity Date": "2019-07-10",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 10000,
"Moving Time": 1805
},
{
"Activity Date": "2019-07-13",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 11603,
"Moving Time": 3127
},
{
"Activity Date": "2019-07-14",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 8701,
"Moving Time": 2369
},
{
"Activity Date": "2019-07-15",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 13021,
"Moving Time": 2728
},
{
"Activity Date": "2019-07-16",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 10094,
"Moving Time": 1823
},
{
"Activity Date": "2019-07-17",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 10075,
"Moving Time": 1783
},
{
"Activity Date": "2019-07-18",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 10170,
"Moving Time": 2006
},
{
"Activity Date": "2019-07-19",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 13796,
"Moving Time": 2487
},
{
"Activity Date": "2019-07-21",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 9837,
"Moving Time": 1761
},
{
"Activity Date": "2019-07-23",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 20292,
"Moving Time": 4581
},
{
"Activity Date": "2019-07-24",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 43681,
"Moving Time": 12542
},
{
"Activity Date": "2019-07-27",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 21879,
"Moving Time": 3556
},
{
"Activity Date": "2019-07-26",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 42881,
"Moving Time": 7302
},
{
"Activity Date": "2019-08-13",
"Activity Name": "Evening Ride",
"Activity Type": "Ride",
"Distance": 11756.5,
"Moving Time": 2433
},
{
"Activity Date": "2019-08-26",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 5596,
"Moving Time": 1505
},
{
"Activity Date": "2019-07-25",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 10639.2001953125,
"Moving Time": 2615
},
{
"Activity Date": "2019-07-26",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 41150.6015625,
"Moving Time": 6795
},
{
"Activity Date": "2019-07-27",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 43459.80078125,
"Moving Time": 6986
},
{
"Activity Date": "2019-08-26",
"Activity Name": "Norvegija su Jurgiu!",
"Activity Type": "Ride",
"Distance": 83720,
"Moving Time": 21811
},
{
"Activity Date": "2019-08-27",
"Activity Name": "Norvegija su Jurgiu! Day 2",
"Activity Type": "Ride",
"Distance": 27739.400390625,
"Moving Time": 8280
},
{
"Activity Date": "2019-08-28",
"Activity Name": "Norvegija su Jurgiu! day 3",
"Activity Type": "Ride",
"Distance": 25866.599609375,
"Moving Time": 6333
},
{
"Activity Date": "2019-09-11",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 4512.2998046875,
"Moving Time": 1250
},
{
"Activity Date": "2019-09-12",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 8641.400390625,
"Moving Time": 3404
},
{
"Activity Date": "2019-09-15",
"Activity Name": "Nuo Pisos iki Florencijos",
"Activity Type": "Ride",
"Distance": 103813.6015625,
"Moving Time": 23376
},
{
"Activity Date": "2019-09-16",
"Activity Name": "Toskana, antra diena",
"Activity Type": "Ride",
"Distance": 55542.6015625,
"Moving Time": 15264
},
{
"Activity Date": "2019-09-17",
"Activity Name": "Toskana, 3 diena",
"Activity Type": "Ride",
"Distance": 70001.3984375,
"Moving Time": 15377
},
{
"Activity Date": "2019-09-18",
"Activity Name": "Toskana, 4 diena",
"Activity Type": "Ride",
"Distance": 82216.703125,
"Moving Time": 18648
},
{
"Activity Date": "2019-09-19",
"Activity Name": "Toskana, 5 diena",
"Activity Type": "Ride",
"Distance": 82086.203125,
"Moving Time": 20213
},
{
"Activity Date": "2019-09-20",
"Activity Name": "Toskana, 6 diena, važiuojam namo.",
"Activity Type": "Ride",
"Distance": 61489.8984375,
"Moving Time": 11320
},
{
"Activity Date": "2019-09-27",
"Activity Name": "Morning Ride",
"Activity Type": "Ride",
"Distance": 4236.2001953125,
"Moving Time": 1030
},
{
"Activity Date": "2019-09-27",
"Activity Name": "Afternoon Ride",
"Activity Type": "Ride",
"Distance": 4303.60009765625,
"Moving Time": 1142
},
{
"Activity Date": "2019-10-13",
"Activity Name": "Lunch Ride",
"Activity Type": "Ride",
"Distance": 14578,
"Moving Time": 3591
}
];
root;
chart: any;
weeklyData = [];
dailyData = [];
firstDay = am5.time.round(new Date(this.data[0]["Activity Date"]), "year", 1);
total: number;
dateFormatter: any;
dateAxis: any;
weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
weekAxisData = [
{ day: "Sun" },
{ day: "Mon" },
{ day: "Tue" },
{ day: "Wed" },
{ day: "Thu" },
{ day: "Fri" },
{ day: "Sat" }
];
colorSet: any;
ngOnInit(): void {
}
ngAfterViewInit(): void {
this.root = am5.Root.new("radarChart");
const myTheme = am5.Theme.new(this.root);
myTheme.rule("Label").set("fontSize", 10);
myTheme.rule("Grid").set("strokeOpacity", 0.06);
this.root.setThemes([am5themes_Animated.new(this.root), myTheme]);
this.root.dateFormatter.setAll({
dateFormat: "w",
dateFields: ["valueX"]
});
this.root.locale.firstDayOfWeek = 0;
const dateFormatter = am5.DateFormatter.new(this.root, {});
this.dateFormatter = dateFormatter;
this.colorSet = am5.ColorSet.new(this.root, {});
// THIS FUNCTION IS WORKING PERFECTLY
this.prepareDistanceData(this.data);
console.log("Weekly Data: ", this.weeklyData);
console.log("Daily Data: ", this.dailyData);
console.log("Total: ", this.total);
this.getChart();
}
prepareDistanceData(data) {
let weeklyData = [];
let dailyData = [];
const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
let total = 0;
for (let i = 0; i < 53; i++) {
weeklyData[i] = {};
weeklyData[i].distance = 0;
let date = new Date(this.firstDay);
date.setDate(i * 7);
am5.time.round(date, "week", 1);
let endDate = am5.time.round(new Date(date), "week", 1);
weeklyData[i].date = date.getTime();
weeklyData[i].endDate = endDate.getTime();
}
am5.array.each(data, function (di) {
let date = new Date(di["Activity Date"]);
let weekDay = date.getDay();
let weekNumber = am5.utils.getWeek(date);
if (weekNumber == 1 && date.getMonth() == 11) {
weekNumber = 53;
}
let distance = am5.math.round(di["Distance"] / 1000, 1);
weeklyData[weekNumber - 1].distance += distance;
weeklyData[weekNumber - 1].distance = am5.math.round(
weeklyData[weekNumber - 1].distance,
1
);
total += distance;
dailyData.push({
date: date.getTime(),
day: weekdays[weekDay],
"Distance": distance,
title: di["Activity Name"]
});
});
this.weeklyData = weeklyData;
this.dailyData = dailyData;
this.total = total;
}
getChart() {
this.chart = this.root.container.children.push(
am5radar.RadarChart.new(this.root, {
panX: false,
panY: false,
wheelX: "panX",
wheelY: "zoomX",
innerRadius: am5.percent(20),
radius: am5.percent(85),
startAngle: 270 - 170,
endAngle: 270 + 170
})
);
// add label in the center
this.chart.radarContainer.children.push(
am5.Label.new(this.root, {
text:
"[fontSize:0.8em]In 2019 I cycled:[/]\n[fontSize:1.5em]" +
Math.round(this.total) +
" km[/]",
textAlign: "center",
centerX: am5.percent(50),
centerY: am5.percent(50)
})
);
let cursor = this.chart.set(
"cursor",
am5radar.RadarCursor.new(this.root, {
behavior: "zoomX"
})
);
cursor.lineY.set("visible", false);
// date axis
let dateAxisRenderer = am5radar.AxisRendererCircular.new(this.root, {
minGridDistance: 20
});
dateAxisRenderer.labels.template.setAll({
radius: 30,
textType: "radial",
centerY: am5.p50
});
this.dateAxis = this.chart.xAxes.push(
am5xy.DateAxis.new(this.root, {
baseInterval: { timeUnit: "week", count: 1 },
renderer: dateAxisRenderer,
min: new Date(2019, 0, 1, 0, 0, 0).getTime(),
max: new Date(2020, 0, 1, 0, 0, 0).getTime()
})
);
// distance axis
let distanceAxisRenderer = am5radar.AxisRendererRadial.new(this.root, {
axisAngle: 90,
radius: am5.percent(60),
innerRadius: am5.percent(20),
inversed: true,
minGridDistance: 20
});
distanceAxisRenderer.labels.template.setAll({
centerX: am5.p50,
minPosition: 0.05,
maxPosition: 0.95
});
let distanceAxis = this.chart.yAxes.push(
am5xy.ValueAxis.new(this.root, {
renderer: distanceAxisRenderer
})
);
distanceAxis.set("numberFormat", "# ' km'");
// week axis
let weekAxisRenderer = am5radar.AxisRendererRadial.new(this.root, {
axisAngle: 90,
innerRadius: am5.percent(60),
radius: am5.percent(100),
minGridDistance: 20
});
weekAxisRenderer.labels.template.setAll({
centerX: am5.p50
});
let weekAxis = this.chart.yAxes.push(
am5xy.CategoryAxis.new(this.root, {
categoryField: "day",
renderer: weekAxisRenderer
})
);
// Create series
let distanceSeries = this.chart.series.push(
am5radar.RadarColumnSeries.new(this.root, {
calculateAggregates: true,
xAxis: this.dateAxis,
yAxis: distanceAxis,
valueYField: "distance",
valueXField: "date",
tooltip: am5.Tooltip.new(this.root, {
labelText: "week {valueX}: {valueY}"
})
})
);
distanceSeries.columns.template.set("strokeOpacity", 0);
// Set up heat rules
distanceSeries.set("heatRules", [{
target: distanceSeries.columns.template,
key: "fill",
min: am5.color(0x673ab7),
max: am5.color(0xf44336),
dataField: "valueY"
}]);
// bubble series is a line series with strokes hidden
let bubbleSeries = this.chart.series.push(
am5radar.RadarLineSeries.new(this.root, {
calculateAggregates: true,
xAxis: this.dateAxis,
yAxis: weekAxis,
baseAxis: this.dateAxis,
categoryYField: "day",
valueXField: "date",
valueField: "Distance",
maskBullets: false
})
);
// only bullets are visible, hide stroke
bubbleSeries.strokes.template.set("forceHidden", true);
// ==================================================
// This is where the error occurs
// ==================================================
// add bullet
let circleTemplate: am5.Template<am5.Circle> = am5.Template.new({});
bubbleSeries.bullets.push(function () {
console.log("Root: ", this.root);
let graphics = am5.Circle.new(this.root, {
fill: distanceSeries.get("fill"),
tooltipText: "{title}: {value} km"
}, circleTemplate);
return am5.Bullet.new(this.root, {
sprite: graphics
});
});
// add heat rule (makes bubbles to be of a various size, depending on a value)
bubbleSeries.set("heatRules", [{
target: circleTemplate,
min: 3,
max: 15,
dataField: "value",
key: "radius"
}]);
// set data
// https://www.amcharts.com/docs/v5/charts/radar-chart/#Setting_data
distanceSeries.data.setAll(this.weeklyData);
weekAxis.data.setAll(this.weekAxisData);
bubbleSeries.data.setAll(this.dailyData);
bubbleSeries.appear(1000);
distanceSeries.appear(1000);
this.chart.appear(1000, 100);
// create axis ranges
let months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
for (let i = 0; i < 12; i++) {
this.createRange(months[i], i);
}
}
createRange(name, index) {
let months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
let axisRange = this.dateAxis.createAxisRange(
this.dateAxis.makeDataItem({ above: true })
);
axisRange.get("label").setAll({ text: name });
let fromTime = new Date(this.firstDay.getFullYear(), index, 1, 0, 0, 0).getTime();
let toTime = am5.time.add(new Date(fromTime), "month", 1).getTime();
axisRange.set("value", fromTime);
axisRange.set("endValue", toTime);
// every 2nd color for a bigger contrast
let fill = axisRange.get("axisFill");
fill.setAll({
toggleKey: "active",
cursorOverStyle: "pointer",
fill: this.colorSet.getIndex(index * 2),
visible: true,
dRadius: 25,
innerRadius: -25
});
axisRange.get("grid").set("visible", false);
let label = axisRange.get("label");
label.setAll({
fill: am5.color(0xffffff),
textType: "circular",
radius: 8,
text: months[index]
});
// clicking on a range zooms in
fill.events.on("click", function (event) {
let dataItem = event.target.dataItem;
if (event.target.get("active")) {
this.dateAxis.zoom(0, 1);
} else {
this.dateAxis.zoomToValues(dataItem.get("value"), dataItem.get("endValue"));
}
});
}
}
Can someone please help, what I'm doing wrong here?
AmCharts provides the root as a parameter in your bullet function (docs), you just need to define it and reference it instead of this.root
:
bubbleSeries.bullets.push(function (root) {
console.log("Root: ", root);
let graphics = am5.Circle.new(root, {
fill: distanceSeries.get("fill"),
tooltipText: "{title}: {value} km"
}, circleTemplate);
return am5.Bullet.new(root, {
sprite: graphics
});
});