javascriptangularjsd3.jsgraphicicles

D3 graph questions about zoom


I'm setting a Icicle graph on a old angularjs application. I decided to try d3 graphs and doing some tests... So basically two questions, for two different codes:

Question 1: Initially i used this example: https://bl.ocks.org/lorenzopub/c4a226f9c29a20dd0cc152e212a70c9a

I realized that when you zoom in certain areas of the graph, it returns " attribute width: A negative value is not valid. ("-2428.9156626506024")" and even if it makes the zoom it doesnt show the text. Any idea why this happens?

Question 2: Later i tried to make my own structure, using the same json as the previous example. The main difference was that i created a "g" and inside it i placed the "rec" and the "foreignObject", to make it more organized in terms of structure. Code below

I placed the below code in an angularjs directive.

I'm using V4 of d3 "//d3js.org/d3.v4.min.js"


      var totalSize = 0;
      var width = 960, height = 500;
      var x = d3.scaleLinear().range([0, width]);
      var y = d3.scaleLinear().range([0, height]);
      var color = d3.scaleOrdinal(d3.schemeCategory20c);
      var partition = d3.partition()
        .size([width, height])
        .padding(0)
        .round(true);
      var svg = d3.select("#pleaseWork") //.append("svg")
        .attr("width", width)
        .attr("height", height);
      var groups = svg.selectAll("g");

      d3.json("graphs/dataD3.json", function (error, root) {
        //d3.json("graphs/newData.json", function (error, root) {
        if (error) throw error;
        root = d3.hierarchy(d3.entries(root)[0], function (d) {
            return d3.entries(d.value)
          })
          .sum(function (d) {
            return d.value
          })
          .sort(function (a, b) {
            return b.value - a.value;
          });

        partition(root);
        groups = groups
          .data(root.descendants())
          .enter().append("g")
          .attr("fill", function (d) {
            return color((d.children ? d : d.parent).data.key);
          })
          .on("click", clicked);
        //get total size from rect
        totalSize = groups.node().__data__.value;
        console.log(groups.node().__data__.value);
        groups.append('rect')
          .attr("x", function (d) {
            return d.x0;
          })
          .attr("y", function (d) {
            return d.y0;
          })
          .attr("width", function (d) {
            return d.x1 - d.x0;
          })
          .attr("height", function (d) {
            return d.y1 - d.y0;
          });

        groups.append('foreignObject')
          .text(function (d) {
            //return d.data.key + '-' + d.value;
            return d.data.key + ' - ' + (100 * d.value / totalSize).toPrecision(3) + '%';
          })
          .attr("x", function (d) {
            return d.x0;
          })
          .attr("y", function (d) {
            return d.y0;
          })
          .attr("width", function (d) {
            return d.x1 - d.x0;
          })
          .attr("height", function (d) {
            return d.y1 - d.y0;
          });

      });

      function clicked(d) {
        console.log(d);
        x.domain([d.x0, d.x1]);
        y.domain([d.y0, height]).range([d.depth ? 20 : 0, height]);
        groups.transition()
          .duration(750)
          .attr("x", function (d) {
            return x(d.x0);
          })
          .attr("y", function (d) {
            return y(d.y0);
          })
          .attr("width", function (d) {
            return x(d.x1) - x(d.x0);
          })
          .attr("height", function (d) {
            return y(d.y1) - y(d.y0);
          });
      }
    }




When i click on a item to zoom, it enter in the function "clicked" but nothing happens, i wanted to achieve something similar as the first example, where it zooms to that element level. Thanks in advance for the support


Solution

  • Solved the first question with replacing the code from the fo.transition() to:

    .attr("x", function (d) {
            return d.x0;
          })
          .attr("y", function (d) {
            return d.y0;
          })
          .attr("width", function (d) {
            return d.x1 - d.x0;
          })
          .attr("height", function (d) {
            return d.y1 - d.y0;
          })
    

    The second question, i solved like this:

    
          var width = 500,
            height = 300;
          var partitionLayout = d3.partition().size([width, height]);
    
          //needed for zoom ? 
          var x = d3.scaleLinear().range([0, width]);
          var y = d3.scaleLinear().range([0, height]);
    
          //needed to fill the colour
          var colour = d3.scaleOrdinal(d3.schemeCategory20c);
    
          d3.json("graphs/newstructure.json", function (data) {
            var rootNode = d3.hierarchy(data);
            rootNode.sum(function (d) {
              return d.value;
            });
    
            // structure the data for the graph
            partitionLayout(rootNode);
    
            var group = d3.select('#new')
              .selectAll('g')
              .data(rootNode.descendants())
              .enter()
              .append('g')
              .attr("fill", function (d) {
                return colour(d.data.colour);
              })
              .on("click", clicked);
    
            group.append('rect')
              .attr('x', function (d) {
                console.log(d);
                return d.x0;
              })
              .attr('y', function (d) {
                return d.y0;
              })
              .attr('width', function (d) {
                return d.x1 - d.x0;
              })
              .attr('height', function (d) {
                return d.y1 - d.y0;
              })
              .attr('fill', function (d) {
                return d.data.colour;
              });
    
            group
              .append('foreignObject')
              .text(function (d) {
                console.log(d);
                return d.data.name + ' - ' + d.value;
              })
              .attr("x", function (d) {
                return d.x0;
              })
              .attr("y", function (d) {
                return d.y0;
              })
              .attr("width", function (d) {
                return d.x1 - d.x0;
              })
              .attr("height", function (d) {
                return d.y1 - d.y0;
              });
    
            function clicked(d) {
              x.domain([d.x0, d.x1]);
              y.domain([d.y0, height]).range([d.depth ? 20 : 0, height]);
    
              group.transition()
                .duration(750)
                .attr("x", function (d) {
                  return x(d.x0);
                })
                .attr("y", function (d) {
                  return y(d.y0);
                })
                .attr("width", function (d) {
                  return x(d.x1) - x(d.x0);
                })
                .attr("height", function (d) {
                  return y(d.y1) - y(d.y0);
                });
    
              var rects = d3.select('#new')
                .selectAll('g rect');
    
              rects.transition()
                .duration(750)
                .attr("x", function (d) {
                  return x(d.x0);
                })
                .attr("y", function (d) {
                  return y(d.y0);
                })
                .attr("width", function (d) {
                  return x(d.x1) - x(d.x0);
                })
                .attr("height", function (d) {
                  return y(d.y1) - y(d.y0);
                });
    
              var rects = d3.select('#new')
                .selectAll('g foreignObject');
    
              rects.transition()
                .duration(750)
                .attr("x", function (d) {
                  return x(d.x0);
                })
                .attr("y", function (d) {
                  return y(d.y0);
                })
                .attr("width", function (d) {
                  return x(d.x1) - x(d.x0);
                })
                .attr("height", function (d) {
                  return y(d.y1) - y(d.y0);
                });
            }
        });