angularchartsamchartsamcharts5

amCharts5 - Cannot read properties of undefined (reading 'root')


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?


Solution

  • 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
          });
        });