-1

I'm new to d3.js implementation. Need some help d3.js heatmap

I have a Requirement : A heat map which shows the difference between each record. based on records Severity and Probability types:

Desired Image : enter image description here Data: In the Above output picture , You can see the circles :

Assume those as records being displayed on a graph . Code for that starts after Comment " //Add dots or circles " . Record data example :

{
"group":"Likely",
"variable":"Significant",
"value":79,
"record":"Retention of environmental safety records",
"color":"red"
}

Data for those records are in variable "dots" You can find in the code below. In that I have 3 records . But 2 circles are overlapping . I have worked on a Heatmap Design . Combining :

Heatmap : https://www.d3-graph-gallery.com/graph/heatmap_style.html Connected scatter plot : https://www.d3-graph-gallery.com/graph/connectedscatter_tooltip.html For now , I have just updated the data :

I have 2 Issues :

  1. Overlapping dots issue
  2. Tooltip not showing after Updating to svg

Detail:

1. Overlapping dots issue Data for those records are in variable "dots" You can find in the code below. In that I have 3 records . But 2 circles are overlapping .

The desired Output is something like this : Circles should not be Overlapped .

If two records with same data , It should display 2 records. I need help in implenting that . Any suggestion is appreciated .

** 2. ToolTip Issue :**

I had an Issue with Tooltip (It was working with div tag ) previously it was as shown below : enter image description here Due to Some requirement i had to go with svg tag in the Html rather than Div tag . since This has to be implemented in Lwc in Salesforce.

Html Updated from div to Svg as shown below : enter image description here

After Updating , Entire Heatmap is working except the Tooltip part . Updated the Tooltip part to Svg as shown below :enter image description here Now the Tooltip is not working .

code :

 <!-- Code from d3-graph-gallery.com -->
    <!DOCTYPE html>
    <meta charset="utf-8">
    
    <!-- Load d3.js -->
    <script src="https://d3js.org/d3.v5.js"></script>
    
    <!-- Create a div where the graph will take place -->
    <div id="my_dataviz">
 <svg
                class="d3"
                width={svgWidth}
                height={svgHeight}
                lwc:dom="manual"
            ></svg></div>
    
    <!-- Load color palettes -->
    
    
    <script>
    
    // set the dimensions and margins of the graph
    var margin = {top: 80, right: 25, bottom: 30, left: 100},
    width = 550 - margin.left - margin.right,
    height = 450 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    var svg = d3.select(this.template.querySelector('svg.d3'))
    .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
    .append("g")
      .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");
    
    //Read the data
    var data = [{"group":"Rare","variable":"Insignificant","value":45,"color":"purple"},{"group":"Rare","variable":"Minimal","value":95,"color":"purple"},{"group":"Rare","variable":"Moderate","value":22,"color":"green"},{"group":"Rare","variable":"Significant","value":14,"color":"green"},{"group":"Rare","variable":"Catastrophic","value":59,"color":"yellow"},{"group":"Unlikely","variable":"Minimal","value":37,"color":"purple"},{"group":"Unlikely","variable":"Insignificant","value":37,"color":"purple"},{"group":"Unlikely","variable":"Moderate","value":81,"color":"green"},{"group":"Unlikely","variable":"Significant","value":79,"color":"yellow"},{"group":"Unlikely","variable":"Catastrophic","value":84,"color":"orange"},{"group":"Probable","variable":"Insignificant","value":96,"color":"purple"},{"group":"Probable","variable":"Minimal","value":37,"color":"green"},{"group":"Probable","variable":"Moderate","value":98,"color":"yellow"},{"group":"Probable","variable":"Significant","value":10,"color":"orange"},{"group":"Probable","variable":"Catastrophic","value":86,"color":"red"},{"group":"Likely","variable":"Insignificant","value":75,"color":"green"},{"group":"Likely","variable":"Minimal","value":18,"color":"yellow"},{"group":"Likely","variable":"Moderate","value":92,"color":"orange"},{"group":"Likely","variable":"Significant","value":43,"color":"red"},{"group":"Likely","variable":"Catastrophic","value":16,"color":"red"},{"group":"Almost Certain","variable":"Insignificant","value":44,"color":"green"},{"group":"Almost Certain","variable":"Minimal","value":29,"color":"yellow"},{"group":"Almost Certain","variable":"Moderate","value":58,"color":"orange"},{"group":"Almost Certain","variable":"Significant","value":55,"color":"red"},{"group":"Almost Certain","variable":"Catastrophic","value":65,"color":"red"}]; // Labels of row and columns -> unique identifier of the column called 'group' and 'variable'
      var myGroups = d3.map(data, function(d){return d.group;}).keys()
      var myVars = d3.map(data, function(d){return d.variable;}).keys()
    
      // Build X scales and axis:
      var x = d3.scaleBand()
        .range([ 0, width ])
        .domain(myGroups)
        .padding(0.05);
      svg.append("g")
        .style("font-size", 15)
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x).tickSize(0))
        .select(".domain").remove()
    
      // Build Y scales and axis:
      var y = d3.scaleBand()
        .range([ height, 0 ])
        .domain(myVars)
        .padding(0.05);
      svg.append("g")
        .style("font-size", 15)
        .call(d3.axisLeft(y).tickSize(0))
        .select(".domain").remove()
    
      // Build color scale
      var myColor = d3.scaleSequential()
        .interpolator(d3.interpolateInferno)
        .domain([1,100])
    
      // create a tooltip
      var tooltip = d3.select("#my_dataviz")
        .append("div")
        .style("opacity", 0)
        .attr("class", "tooltip")
        .style("background-color", "white")
        .style("border", "solid")
        .style("border-width", "2px")
        .style("border-radius", "5px")
        .style("padding", "5px")
        .style("position","fixed")
    
      // Three function that change the tooltip when user hover / move / leave a cell
      var mouseover = function(d) {
        tooltip
          .style("opacity", 1)
        d3.select(this)
          .style("stroke", "black")
          .style("opacity", 1)
      }
      var mousemove = function(d) {
        tooltip
          .html("The exact value of<br>this cell is: " + d.value)
          .style("left", (d3.mouse(this)[0]+70) + "px")
          .style("top", (d3.mouse(this)[1]) + "px")
      }
      var mouseleave = function(d) {
        tooltip
          .style("opacity", 0)
        d3.select(this)
          .style("stroke", "none")
          .style("opacity", 0.8)
      }
    
      // add the squares
      svg.selectAll()
        .data(data, function(d) {return d.group+':'+d.variable;})
        .enter()
        .append("rect")
          .attr("x", function(d) { return x(d.group) })
          .attr("y", function(d) { return y(d.variable) })
          .attr("rx", 4)
          .attr("ry", 4)
          .attr("width", x.bandwidth() )
          .attr("height", y.bandwidth() )
          .style("fill", function(d) { return d.color } )
          .style("stroke-width", 4)
          .style("stroke", "none")
          .style("opacity", 0.8)
        .on("mouseover", mouseover)
        .on("mousemove", mousemove)
        .on("mouseleave", mouseleave)
        
      // Three function that change the tooltip when user hover / move / leave a cell
      var mouseover1 = function(d) {
        tooltip
          .style("opacity", 1)
        d3.select(this)
          .style("stroke", "black")
          .style("opacity", 1)
      }
      var mousemove1 = function(d) {
        tooltip
          .html("4. " + d.record)
          .style("left", (d3.mouse(this)[0]+90) + "px")
          .style("top", (d3.mouse(this)[1]) + "px")
      }
      var mouseleave1 = function(d) {
        tooltip
          .style("opacity", 0)
        d3.select(this)
          .style("stroke", "none")
          .style("opacity", 0.8)
      }
      
      //Add dots or circles     
        var dots = 
    [{"group":"Likely","variable":"Significant","value":79,"record":"Retention of environmental safety records","color":"red"},
    {"group":"Unlikely","variable":"Minimal","value":84,"record":"Risk of Fines from European Union GDPR due to data breach","color":"orange"},
    {"group":"Unlikely","variable":"Minimal","value":84,"record":"Risk Management Case record","color":"green"}];
         // Add the points
        svg
          .append("g")
          .selectAll("dot")
          .data(dots)
          .enter()
          .append("circle")
            .attr("class", "myCircle")
            .attr("cx", function(d) { return x(d.group) + x.bandwidth()/2 } )
            .attr("cy", function(d) { return y(d.variable)+ y.bandwidth()/2 } )
            .attr("r", 8)
            .attr("stroke", "#69b3a2")
            .attr("stroke-width", 3)
            .attr("fill", function(d) { return d.color })
            .on("mouseover", mouseover1)
            .on("mousemove", mousemove1)
            .on("mouseleave", mouseleave1)   
    //})
    
    
    // Add title to graph
    svg.append("text")
            .attr("x", 0)
            .attr("y", -50)
            .attr("text-anchor", "left")
            .style("font-size", "22px")
            .text("A  heatmap");
    
    // Add subtitle to graph
    svg.append("text")
            .attr("x", 0)
            .attr("y", -20)
            .attr("text-anchor", "left")
            .style("font-size", "14px")
            .style("fill", "grey")
            .style("max-width", 400)
            .text("A short description of the take-away message of this chart.");
    
    
    </script>

Output (Updated) : enter image description here

Can someone help me in resolving these issues. I need to display the multiple dots inside the same squares, each dot as a seperate element . when you hover over it It should display the record it represents.

Any suggestion is appreciated . Thankyou

Tarun teja
  • 59
  • 3
  • 7

1 Answers1

0

Give your tooltip a position of fixed:

.style("position","fixed")

This will allow the top and left attributes to impact its positioning.

To make the dots appear within the boxes, change your cx attribute to:

.attr("cx", function(d) { return x(d.group) + x.bandwidth()/2 } )

That should center the dots within each box.

To give the dots their own positioning, the dots need to have their own y and x scales. Just make sure it has the same width and height.

Do you have another dataset for this? If not, I wonder if a different scale would give you the outcome you are looking for.

rguttersohn
  • 464
  • 5
  • 15
  • Hi @rguttersohn, Thanks alot . Added to the code . Need some more help. I Added the code to Commented as " #Add the dots " and Updated the output picture as well . I need to display the dots inside the squares as a seperate element . Scenario :1. When i hover the square It should display the value(as it showing). 2. When i hover on the dot inside the square . It should display the Record name . – Tarun teja Mar 05 '21 at 14:39
  • Just updated my answer for the dots cx issue. Can you let me know if that addressed it? – rguttersohn Mar 05 '21 at 15:02
  • Yes ,@rguttersohn , This worked . i have updated the both cx and cy . Then it moved to center . But As per my requirement . I need the dots needs to be a seperate component . Which are added on the different data on only few boxes. – Tarun teja Mar 05 '21 at 18:29
  • Great. Just updated my answer. It sounds like the dots need their own scales. – rguttersohn Mar 06 '21 at 20:15
  • Hi @rguttersohn,Thanks tried what you said and it worked thanks. I had another issue with the Tooltip which was working with the div tag . But i had to used an svg element in the html code . Now Tooltip is not working . Can you please help on this .Updated the question with Tooltip Issue – Tarun teja Mar 10 '21 at 20:51
  • Yikes. That's tough. Can you add another svg element below this svg element? That would be the easiest route as an alternative to using a tag. – rguttersohn Mar 12 '21 at 13:43
  • Hi @rguttersohn, Thanks for responding . Can you help in adding the svg element .I have updated the code and the question. Now i have two issues. – Tarun teja Mar 12 '21 at 15:00
  • If you don't mind me asking, why can't you use a non-svg element for the tooltip? – rguttersohn Mar 12 '21 at 22:19
  • Hi @rguttersohn, Actually i had to add this component in salesforce Lightning Web Component . In that adding d3.js to div tag is not working for me . I am following this example of Salesforce https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_third_party_library – Tarun teja Mar 13 '21 at 10:18
  • When you attempted to add the
    , did an error occur? What happens if append a new to #myDataViz with the same attributes? I guess I am not understanding why this would block you from doing basic DOM manipulation.
    – rguttersohn Mar 13 '21 at 14:41