1

Path hovering under SVG works when using plain JS + HTML. However when importing the same function over to Angular it stops working.

circularHeatChart.js

function loadCircularHeatMap (dataset, dom_element_to_append_to,radial_labels,segment_labels) {

  var margin = {top: 50, right: 50, bottom: 50, left: 50};
  var width = 600 - margin.left - margin.right;

  var height = width;
  var innerRadius = width/14;
  var segmentHeight = (width - margin.top - margin.bottom - 2*innerRadius )/(2*radial_labels.length)

  var chart = circularHeatChart()
  .innerRadius(innerRadius)
  .segmentHeight(segmentHeight)
  .range(["white", "#01579b"])
  .radialLabels(radial_labels)
  .segmentLabels(segment_labels);

  chart.accessor(function(d) {return d.value;})

  var svg = d3.select(dom_element_to_append_to)
  .selectAll('svg')
  .data([dataset])
  .enter()
  .append('svg')
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append('g')
  .attr("transform",
      "translate(" + ( (width )/2 - (radial_labels.length*segmentHeight + innerRadius)  ) + "," + margin.top + ")")
  .call(chart);

  var tooltip = d3.select(dom_element_to_append_to)
  .append('div')
  .attr('class', 'tooltip');

  tooltip.append('div')
  .attr('class', 'month');
  tooltip.append('div')
  .attr('class', 'value');
  tooltip.append('div')
  .attr('class', 'type');

  svg.selectAll("path")
  .on('mouseover', function(d) {
      tooltip.select('.month').html("<b> Month: " + d.month + "</b>");
      tooltip.select('.type').html("<b> Type: " + d.type + "</b>");
      tooltip.select('.value').html("<b> Value: " + d.value + "</b>");

      tooltip.style('display', 'block');
      tooltip.style('opacity',2);
  })
  .on('mousemove', function(d) {

      tooltip.style('top', (d3.event.layerY + 10) + 'px')
      .style('left', (d3.event.layerX - 25) + 'px');
  })
  .on('mouseout', function(d) {
      tooltip.style('display', 'none');
      tooltip.style('opacity',0);
  });
}

function circularHeatChart() {
  var margin = {top: 20, right: 20, bottom: 20, left: 20},
  innerRadius = 20,
  numSegments = 12,
  segmentHeight = 20,
  domain = null,
  range = ["white", "red"],
  accessor = function(d) {return d;},
  radialLabels = segmentLabels = [];

  function chart(selection) {
      selection.each(function(data) {
          var svg = d3.select(this);

          var offset = innerRadius + Math.ceil(data.length / numSegments) * segmentHeight;
          g = svg.append("g")
              .classed("circular-heat", true)
              .attr("transform", "translate(" + parseInt(margin.left + offset) + "," + parseInt(margin.top + offset) + ")");

          var autoDomain = false;
          if (domain === null) {
              domain = d3.extent(data, accessor);
              autoDomain = true;
          }
          var color = d3.scale.linear().domain(domain).range(range);
          if(autoDomain)
              domain = null;

          g.selectAll("path").data(data)
              .enter().append("path")
              .attr("d", d3.svg.arc().innerRadius(ir).outerRadius(or).startAngle(sa).endAngle(ea))
              .attr("stroke", function(d) {return "#4f5b69";})
              .attr("fill", function(d) {return color(accessor(d));});

          // Unique id so that the text path defs are unique - is there a better way to do this?
          var id = d3.selectAll(".circular-heat")[0].length;

          //Radial labels
          var lsa = 0.01; //Label start angle
          var labels = svg.append("g")
              .classed("labels", true)
              .classed("radial", true)
              .attr("transform", "translate(" + parseInt(margin.left + offset) + "," + parseInt(margin.top + offset) + ")");

          labels.selectAll("def")
              .data(radialLabels).enter()
              .append("def")
              .append("path")
              .attr("id", function(d, i) {return "radial-label-path-"+id+"-"+i;})
              .attr("d", function(d, i) {
                  var r = innerRadius + ((i + 0.2) * segmentHeight);
                  return "m" + r * Math.sin(lsa) + " -" + r * Math.cos(lsa) +
                          " a" + r + " " + r + " 0 1 1 -1 0";
              });

          labels.selectAll("text")
              .data(radialLabels).enter()
              .append("text")
              .append("textPath")
              .attr("xlink:href", function(d, i) {return "#radial-label-path-"+id+"-"+i;})
              .style("font-size", "16px")
              .text(function(d) {return d;});

          //Segment labels
          var segmentLabelOffset = 2;
          var r = innerRadius + Math.ceil(data.length / numSegments) * segmentHeight + segmentLabelOffset;
          labels = svg.append("g")
              .classed("labels", true)
              .classed("segment", true)
              .attr("transform", "translate(" + parseInt(margin.left + offset) + "," + parseInt(margin.top + offset) + ")");

          labels.append("def")
              .append("path")
              .attr("id", "segment-label-path-"+id)
              .attr("d", "m0 -" + r + " a" + r + " " + r + " 0 1 1 -1 0");

          labels.selectAll("text")
              .data(segmentLabels).enter()
              .append("text")
              .append("textPath")
              .attr("xlink:href", "#segment-label-path-"+id)
              .style("font-size", "16px")
              .attr("startOffset", function(d, i) {return i * 100 / numSegments + "%";})
              .text(function(d) {return d;});
      });

  }

  /* Arc functions */
  ir = function(d, i) {
      return innerRadius + Math.floor(i/numSegments) * segmentHeight;
  }
  or = function(d, i) {
      return innerRadius + segmentHeight + Math.floor(i/numSegments) * segmentHeight;
  }
  sa = function(d, i) {
      return (i * 2 * Math.PI) / numSegments;
  }
  ea = function(d, i) {
      return ((i + 1) * 2 * Math.PI) / numSegments;
  }

  /* Configuration getters/setters */
  chart.margin = function(_) {
      if (!arguments.length) return margin;
      margin = _;
      return chart;
  };

  chart.innerRadius = function(_) {
      if (!arguments.length) return innerRadius;
      innerRadius = _;
      return chart;
  };

  chart.numSegments = function(_) {
      if (!arguments.length) return numSegments;
      numSegments = _;
      return chart;
  };

  chart.segmentHeight = function(_) {
      if (!arguments.length) return segmentHeight;
      segmentHeight = _;
      return chart;
  };

  chart.domain = function(_) {
      if (!arguments.length) return domain;
      domain = _;
      return chart;
  };

  chart.range = function(_) {
      if (!arguments.length) return range;
      range = _;
      return chart;
  };

  chart.radialLabels = function(_) {
      if (!arguments.length) return radialLabels;
      if (_ == null) _ = [];
      radialLabels = _;
      return chart;
  };

  chart.segmentLabels = function(_) {
      if (!arguments.length) return segmentLabels;
      if (_ == null) _ = [];
      segmentLabels = _;
      return chart;
  };

  chart.accessor = function(_) {
      if (!arguments.length) return accessor;
      accessor = _;
      return chart;
  };

  return chart;
}

circular-heatmap.component.ts

import { Component, OnInit } from '@angular/core';


declare function loadCircularHeatMap(dataset:any, dom_element_to_append_to:any, radial_labels:any, segment_labels:any):any;

@Component({
  selector: 'app-circular-heatmap',
  templateUrl: './circular-heatmap.component.html',
  styleUrls: ['./circular-heatmap.component.css']
})
export class CircularHeatmapComponent implements OnInit {

  constructor() { }

  ngOnInit(){
    var inputData =
    [{month:1,type:"Category 1",value:25},
    {month:2,type:"Category 1",value:15},
    {month:3,type:"Category 1",value:27},
    {month:4,type:"Category 1",value:10},
    {month:5,type:"Category 1",value:54},
    {month:6,type:"Category 1",value:23},
    {month:7,type:"Category 1",value:31},
    {month:8,type:"Category 1",value:17},
    {month:9,type:"Category 1",value:8},
    {month:10,type:"Category 1",value:12},
    {month:11,type:"Category 1",value:32},
    {month:12,type:"Category 1",value:35},
    {month:1,type:"Category 2",value:19},
    {month:2,type:"Category 2",value:24},
    {month:3,type:"Category 2",value:27},
    {month:4,type:"Category 2",value:12},
    {month:5,type:"Category 2",value:19},
    {month:6,type:"Category 2",value:30},
    {month:7,type:"Category 2",value:31},
    {month:8,type:"Category 2",value:25},
    {month:9,type:"Category 2",value:20},
    {month:10,type:"Category 2",value:5},
    {month:11,type:"Category 2",value:21},
    {month:12,type:"Category 2",value:10},
    {month:1,type:"Category 3",value:19},
    {month:2,type:"Category 3",value:3},
    {month:3,type:"Category 3",value:32},
    {month:4,type:"Category 3",value:23},
    {month:5,type:"Category 3",value:9},
    {month:6,type:"Category 3",value:17},
    {month:7,type:"Category 3",value:25},
    {month:8,type:"Category 3",value:29},
    {month:9,type:"Category 3",value:32},
    {month:10,type:"Category 3",value:33},
    {month:11,type:"Category 3",value:19},
    {month:12,type:"Category 3",value:24},
    {month:1,type:"Category 4",value:12},
    {month:2,type:"Category 4",value:43},
    {month:3,type:"Category 4",value:12},
    {month:4,type:"Category 4",value:23},
    {month:5,type:"Category 4",value:14},
    {month:6,type:"Category 4",value:19},
    {month:7,type:"Category 4",value:22},
    {month:8,type:"Category 4",value:39},
    {month:9,type:"Category 4",value:22},
    {month:10,type:"Category 4",value:26},
    {month:11,type:"Category 4",value:31},
    {month:12,type:"Category 4",value:25},
    ];

    var radial_labels = ["Category 1","Category 2","Category 3","Category 4"];
    var segment_labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

    loadCircularHeatMap(inputData,"#chart",radial_labels, segment_labels);

  }
}

circular-heatmap.component.css

path:hover{

  fill:#9b59b6;
  }
  
.tooltip {
  background: #eee;
  box-shadow: 0 0 5px #999999;
  color: #333;
  font-size: 12px;
  left: 130px;
  padding: 10px;
  position: absolute;
  text-align: center;
  top: 95px;
  z-index: 10;
  display: block;
  opacity: 0;
}
  
.title{
  font-size:16px;
}

I am certain that the Javascript function is being properly imported as the heatmap itself is getting imported without a problem.

I have even created a single page JS+HTML webpage if that helps.

<!DOCTYPE>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Circular Heat Map</title>

<!-- JavaScript Libraries //-->
<script src="https://d3js.org/d3.v3.min.js"></script>

<!-- CSS Style //-->
<style type="text/css">
    path:hover{

fill:#9b59b6;
}

.tooltip {
    background: #eee;
    box-shadow: 0 0 5px #999999;
    color: #333;
    font-size: 12px;
    left: 130px;
    padding: 10px;
    position: absolute;
    text-align: center;
    top: 95px;
    z-index: 10;
    display: block;
    opacity: 0;
}

.title{
font-size:16px;
}
</style>

<script>
    function loadCircularHeatMap (dataset, dom_element_to_append_to,radial_labels,segment_labels) {

    var margin = {top: 50, right: 50, bottom: 50, left: 50};
    var width = 600 - margin.left - margin.right;

    var height = width;
    var innerRadius = width/14;
    var segmentHeight = (width - margin.top - margin.bottom - 2*innerRadius )/(2*radial_labels.length)

    var chart = circularHeatChart()
    .innerRadius(innerRadius)
    .segmentHeight(segmentHeight)
    .range(["white", "#01579b"])
    .radialLabels(radial_labels)
    .segmentLabels(segment_labels);

    chart.accessor(function(d) {return d.value;})

    var svg = d3.select(dom_element_to_append_to)
    .selectAll('svg')
    .data([dataset])
    .enter()
    .append('svg')
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append('g')
    .attr("transform",
        "translate(" + ( (width )/2 - (radial_labels.length*segmentHeight + innerRadius)  ) + "," + margin.top + ")")
    .call(chart);

    var tooltip = d3.select(dom_element_to_append_to)
    .append('div')
    .attr('class', 'tooltip');

    tooltip.append('div')
    .attr('class', 'month');
    tooltip.append('div')
    .attr('class', 'value');
    tooltip.append('div')
    .attr('class', 'type');

    svg.selectAll("path")
    .on('mouseover', function(d) {
        tooltip.select('.month').html("<b> Month: " + d.month + "</b>");
        tooltip.select('.type').html("<b> Type: " + d.type + "</b>");
        tooltip.select('.value').html("<b> Value: " + d.value + "</b>");

        tooltip.style('display', 'block');
        tooltip.style('opacity',2);
    })
    .on('mousemove', function(d) {

        tooltip.style('top', (d3.event.layerY + 10) + 'px')
        .style('left', (d3.event.layerX - 25) + 'px');
    })
    .on('mouseout', function(d) {
        tooltip.style('display', 'none');
        tooltip.style('opacity',0);
    });
}

function circularHeatChart() {
    var margin = {top: 20, right: 20, bottom: 20, left: 20},
    innerRadius = 20,
    numSegments = 12,
    segmentHeight = 20,
    domain = null,
    range = ["white", "red"],
    accessor = function(d) {return d;},
    radialLabels = segmentLabels = [];

    function chart(selection) {
        selection.each(function(data) {
            var svg = d3.select(this);

            var offset = innerRadius + Math.ceil(data.length / numSegments) * segmentHeight;
            g = svg.append("g")
                .classed("circular-heat", true)
                .attr("transform", "translate(" + parseInt(margin.left + offset) + "," + parseInt(margin.top + offset) + ")");

            var autoDomain = false;
            if (domain === null) {
                domain = d3.extent(data, accessor);
                autoDomain = true;
            }
            var color = d3.scale.linear().domain(domain).range(range);
            if(autoDomain)
                domain = null;

            g.selectAll("path").data(data)
                .enter().append("path")
                .attr("d", d3.svg.arc().innerRadius(ir).outerRadius(or).startAngle(sa).endAngle(ea))
                .attr("stroke", function(d) {return "#4f5b69";})
                .attr("fill", function(d) {return color(accessor(d));});

            // Unique id so that the text path defs are unique - is there a better way to do this?
            var id = d3.selectAll(".circular-heat")[0].length;

            //Radial labels
            var lsa = 0.01; //Label start angle
            var labels = svg.append("g")
                .classed("labels", true)
                .classed("radial", true)
                .attr("transform", "translate(" + parseInt(margin.left + offset) + "," + parseInt(margin.top + offset) + ")");

            labels.selectAll("def")
                .data(radialLabels).enter()
                .append("def")
                .append("path")
                .attr("id", function(d, i) {return "radial-label-path-"+id+"-"+i;})
                .attr("d", function(d, i) {
                    var r = innerRadius + ((i + 0.2) * segmentHeight);
                    return "m" + r * Math.sin(lsa) + " -" + r * Math.cos(lsa) +
                            " a" + r + " " + r + " 0 1 1 -1 0";
                });

            labels.selectAll("text")
                .data(radialLabels).enter()
                .append("text")
                .append("textPath")
                .attr("xlink:href", function(d, i) {return "#radial-label-path-"+id+"-"+i;})
                .style("font-size", "16px")
                .text(function(d) {return d;});

            //Segment labels
            var segmentLabelOffset = 2;
            var r = innerRadius + Math.ceil(data.length / numSegments) * segmentHeight + segmentLabelOffset;
            labels = svg.append("g")
                .classed("labels", true)
                .classed("segment", true)
                .attr("transform", "translate(" + parseInt(margin.left + offset) + "," + parseInt(margin.top + offset) + ")");

            labels.append("def")
                .append("path")
                .attr("id", "segment-label-path-"+id)
                .attr("d", "m0 -" + r + " a" + r + " " + r + " 0 1 1 -1 0");

            labels.selectAll("text")
                .data(segmentLabels).enter()
                .append("text")
                .append("textPath")
                .attr("xlink:href", "#segment-label-path-"+id)
                .style("font-size", "16px")
                .attr("startOffset", function(d, i) {return i * 100 / numSegments + "%";})
                .text(function(d) {return d;});
        });

    }

    /* Arc functions */
    ir = function(d, i) {
        return innerRadius + Math.floor(i/numSegments) * segmentHeight;
    }
    or = function(d, i) {
        return innerRadius + segmentHeight + Math.floor(i/numSegments) * segmentHeight;
    }
    sa = function(d, i) {
        return (i * 2 * Math.PI) / numSegments;
    }
    ea = function(d, i) {
        return ((i + 1) * 2 * Math.PI) / numSegments;
    }

    /* Configuration getters/setters */
    chart.margin = function(_) {
        if (!arguments.length) return margin;
        margin = _;
        return chart;
    };

    chart.innerRadius = function(_) {
        if (!arguments.length) return innerRadius;
        innerRadius = _;
        return chart;
    };

    chart.numSegments = function(_) {
        if (!arguments.length) return numSegments;
        numSegments = _;
        return chart;
    };

    chart.segmentHeight = function(_) {
        if (!arguments.length) return segmentHeight;
        segmentHeight = _;
        return chart;
    };

    chart.domain = function(_) {
        if (!arguments.length) return domain;
        domain = _;
        return chart;
    };

    chart.range = function(_) {
        if (!arguments.length) return range;
        range = _;
        return chart;
    };

    chart.radialLabels = function(_) {
        if (!arguments.length) return radialLabels;
        if (_ == null) _ = [];
        radialLabels = _;
        return chart;
    };

    chart.segmentLabels = function(_) {
        if (!arguments.length) return segmentLabels;
        if (_ == null) _ = [];
        segmentLabels = _;
        return chart;
    };

    chart.accessor = function(_) {
        if (!arguments.length) return accessor;
        accessor = _;
        return chart;
    };

    return chart;
}
</script>
</head>

<body>
    <div style="margin-left:50px;"  id="chart"></div>
</body>
<script>
    var inputData =
    [{month:1,type:"Category 1",value:25},
    {month:2,type:"Category 1",value:15},
    {month:3,type:"Category 1",value:27},
    {month:4,type:"Category 1",value:10},
    {month:5,type:"Category 1",value:54},
    {month:6,type:"Category 1",value:23},
    {month:7,type:"Category 1",value:31},
    {month:8,type:"Category 1",value:17},
    {month:9,type:"Category 1",value:8},
    {month:10,type:"Category 1",value:12},
    {month:11,type:"Category 1",value:32},
    {month:12,type:"Category 1",value:35},
    {month:1,type:"Category 2",value:19},
    {month:2,type:"Category 2",value:24},
    {month:3,type:"Category 2",value:27},
    {month:4,type:"Category 2",value:12},
    {month:5,type:"Category 2",value:19},
    {month:6,type:"Category 2",value:30},
    {month:7,type:"Category 2",value:31},
    {month:8,type:"Category 2",value:25},
    {month:9,type:"Category 2",value:20},
    {month:10,type:"Category 2",value:5},
    {month:11,type:"Category 2",value:21},
    {month:12,type:"Category 2",value:10},
    {month:1,type:"Category 3",value:19},
    {month:2,type:"Category 3",value:3},
    {month:3,type:"Category 3",value:32},
    {month:4,type:"Category 3",value:23},
    {month:5,type:"Category 3",value:9},
    {month:6,type:"Category 3",value:17},
    {month:7,type:"Category 3",value:25},
    {month:8,type:"Category 3",value:29},
    {month:9,type:"Category 3",value:32},
    {month:10,type:"Category 3",value:33},
    {month:11,type:"Category 3",value:19},
    {month:12,type:"Category 3",value:24},
    {month:1,type:"Category 4",value:12},
    {month:2,type:"Category 4",value:43},
    {month:3,type:"Category 4",value:12},
    {month:4,type:"Category 4",value:23},
    {month:5,type:"Category 4",value:14},
    {month:6,type:"Category 4",value:19},
    {month:7,type:"Category 4",value:22},
    {month:8,type:"Category 4",value:39},
    {month:9,type:"Category 4",value:22},
    {month:10,type:"Category 4",value:26},
    {month:11,type:"Category 4",value:31},
    {month:12,type:"Category 4",value:25},
    ];

    var radial_labels = ["Category 1","Category 2","Category 3","Category 4"];
    var segment_labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

    loadCircularHeatMap(inputData,"#chart",radial_labels, segment_labels);
</script>
</html> 

Any leads on this issue is appreciated. Thanks in advance.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.