vendredi 20 avril 2018

d3.layout.tree [collapsable] -> behaviour + not active check box

I am creating a collapsible tree diagram with check boxes next to node labels, when required. Nevertheless, I am having some issues:

1) it started reacting strangely to mouse clicks (e.g., I click on a child node but it expands another node two rows above).

2) I add the check boxes, it's okay, but when I run to test, it does not always allow me to tick the box.

Please see the fiddle demonstrating these two problems. Can anyone please help me with it?

(You could please check field acqusition > motion detection > sensors> ... for the demo)

var m = [60, 60, 30, 30],
  w = 1280 - m[1] - m[3],
  h = 600 - m[0] - m[2],
  i = 0,
  r = 800,
  x = d3.scale.linear().domain([0, w]).range([0, w]),
  y = d3.scale.linear().domain([0, h]).range([0, h]),
  root;

var vis = d3.select("#tree").append("svg:svg")
  .attr("viewBox", "0 0 1280 600")
  .attr("width", w + m[1] + m[3])
  .attr("height", h + m[0] + m[2])
  .append("svg:g")
  //.attr("pointer-events", "all")
  .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
  //.call(d3.behavior.zoom().scaleExtent([1,8]).on("zoom",zoom));
  //.call(d3.behavior.zoom().x(x).y(y).scaleExtent([1, 8]).on("zoom", zoom))
  ;

vis.append("rect")
  .attr("class", "overlay")
  .attr("width", w + m[1] + m[3])
  .attr("height", h + m[0] + m[2])
  .attr("opacity", 0);

var tree = d3.layout.tree()
  .size([h, w]);

var diagonal = d3.svg.diagonal()
  .projection(function(d) {
    return [d.y, d.x];
  });


root = treedata;
root.x0 = h / 2;
root.y0 = 0;

function toggleAll(d) {
  if (d.children) {
    d.children.forEach(toggleAll);
    toggle(d);
  }
};
console.log(root)

// initialize the display to show a few nodes.
root.children.forEach(toggleAll);
//toggle(root.children[1]);
//toggle(root.children[9]);

update(root);

function update(source) {
  var duration = d3.event && d3.event.altKey ? 5000 : 500;

  // Compute the new tree layout.
  var nodes = tree.nodes(root).reverse();

  // Normalize for fixed-depth.
  nodes.forEach(function(d) {
    d.y = d.depth * 180;
  });

  // Update the nodes...
  var node = vis.selectAll("g.node")
    .data(nodes, function(d) {
      return d.id || (d.id = ++i);
    });

  // Enter any new nodes at the parent's previous position.
  var nodeEnter = node.enter().append("svg:g")
    .attr("class", "node")
    .attr("id", function(d) {
      return "node-" + d.id;
    })
    .attr("transform", function(d) {
      return "translate(" + source.y0 + "," + source.x0 + ")";
    })
    .on("click", function(d) {
      toggle(d);
      update(d);
      if (d['info']) {
        playvid(d['info']);
      }
    });

  nodeEnter.append("svg:circle")
    .attr("r", 1e-6)
        .style("stroke", function(d) {
            if(d.type == "activity_DataCollection") return "#aa1008";
            if(d.type == "main_DataCollection") return "#aa1008";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "#e0a90e";         
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "#336600";    
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "#805e4b";       
            if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "#8996b9";         
            if(d.type == "descriptor") return "#bcaeac";
        if(d.type == "descriptorvalue") return "#92d050";           
        })
        .style("fill", function(d) {
          if(d.type == "activity") return "#805e4b";
          if(d.type == "activity_DataCollection") return "#aa1008";       
          if(d.type == "main_DataCollection") return "white";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "white";   
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "white";
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "white"; 
                        if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "white";
            if(d.type == "descriptor") return "white";
        if(d.type == "descriptorvalue") return "white";         
            });
//modification end according to color requirements



  var nodeText = nodeEnter
    .append("svg:foreignObject")
    //.attr("y", function(d) { return d.children || d._children ? -10 : 10; })
    //.attr("dx", ".35em")
    //.attr("x", function(d) {
    //  return d.children || d._children ? -10 : 10;
    //})
    .attr("y", -30)
    .attr("x", -5)
    .attr("text-anchor", function(d) {
      return d.children || d._children ? "end" : "start";
    })
    .style("fill-opacity", 1e-6)
    .attr('width', 300)
    .attr('height', 100)
    .append('xhtml:div')
    .attr("class", function(d) {
      return "node-label" + " node-" + d.type
    })
    .classed("disabled", function(d) {
        return d.enable !== undefined && !d.enable;
    })

    .on("mouseover", function (d) {
            var r = d3.select(this).node().getBoundingClientRect();
            d3.select("div#tooltip")
                .style("display", "inline")
                .style("top", (r.top+25) + "px")
                .style("left", r.left + "px")
                .style("position", "absolute")
                .text(d.definition+" "+d.example);
        })
    .on("mouseout", function(){
        d3.select("div#tooltip").style("display", "none")
    });


  //Enable node button
  nodeText.filter(function(d) {
      return d.enablable;
    })
    .append("input", ".")
    .attr("type", "checkbox")
    .property("checked", function(d) {
        return d.enable;
    })
    .on("change", toggleEnable, true)
    .on("click", stopPropogation, true);

  //Node label
  nodeText.append("span")
    .attr("class", "node-text")
    .text(function(d) {
      return d.name;
    });  

  //Edit node button
  nodeText.filter(function(d) {
      return d.editable;
    })
    .append("a")
    .attr("class", "node-edit")
    .on("click", onEditNode, true)
    .append("i")
    .attr("class", "fa fa-pencil");

  //Add node button
  nodeText.filter(function(d) {
      return d.addable;
    })
    .append("a")
    .attr("class", "node-add")
    .on("click", onAddNode, true)
    .append("i")
    .attr("class", "fa fa-plus");

  //Remove node button
  nodeText.filter(function(d) {
      return d.removable;
    })
    .append("a")
    .attr("class", "node-remove")
    .on("click", onRemoveNode, true)
    .append("i")
    .attr("class", "fa fa-times");

  // Transition nodes to their new position.
  var nodeUpdate = node.transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + d.y + "," + d.x + ")";
    });

  nodeUpdate.select("circle")
    .attr("r", 4.5)
        .style("stroke", function(d) {
            if(d.type == "activity_DataCollection") return "#aa1008";
            if(d.type == "main_DataCollection") return "#aa1008";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "#e0a90e";         
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "#336600";    
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "#805e4b";       
            if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "#8996b9";     
            if(d.type == "descriptor") return "#bcaeac";
        if(d.type == "descriptorvalue") return "#92d050";           
        })
        .style("fill", function(d) {
          if(d.type == "activity") return "#805e4b";
          if(d.type == "activity_DataCollection") return "#aa1008";       
          if(d.type == "main_DataCollection") return "white";
            if(d.type == "activity_DataAnalysis") return "#e0a90e";
            if(d.type == "main_DataAnalysis") return "white";   
            if(d.type == "activity_DataFiltering") return "#336600";
            if(d.type == "main_DataFiltering") return "white";
            if(d.type == "activity_AddedValue") return "#805e4b";
            if(d.type == "main_AddedValue") return "white"; 
                        if(d.type == "activity_Finalisation") return "#8996b9";
            if(d.type == "main_Finalisation") return "white";
            if(d.type == "descriptor") return "white";
        if(d.type == "descriptorvalue") return "white";         
            });
//modification-2 end according to color requirements        

  nodeUpdate.select("text")
    .style("fill-opacity", 1);

  // Transition exiting ndoes to the parent's new position.
  var nodeExit = node.exit().transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + source.y + "," + source.x + ")";
    })
    .remove();

  nodeExit.select("circle")
    .attr("r", 1e-6);
  nodeExit.select("text")
    .style("fill-opacity", 1e-6);

  // Update the links...
  var link = vis.selectAll("path.link")
    .data(tree.links(nodes), function(d) {
      return d.target.id;
    });

  // Enter any new links at hte parent's previous position
  link.enter().insert("svg:path", "g")
    .attr("class", "link")
    .attr("d", function(d) {
      var o = {
        x: source.x0,
        y: source.y0
      };
      return diagonal({
        source: o,
        target: o
      });
    })
    .transition()
    .duration(duration)
    .attr("d", diagonal);

  // Transition links to their new position.
  link.transition()
    .duration(duration)
    .attr("d", diagonal);

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
    .duration(duration)
    .attr("d", function(d) {
      var o = {
        x: source.x,
        y: source.y
      };
      return diagonal({
        source: o,
        target: o
      });
    })
    .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });
}
// Toggle children
function toggle(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
}

// zoom in / out
function zoom(d) {
  //vis.attr("transform", "transl3ate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
  var nodes = vis.selectAll("g.node");
  nodes.attr("transform", transform);

  // Update the links...
  var link = vis.selectAll("path.link");
  link.attr("d", translate);

  // Enter any new links at hte parent's previous position
  //link.attr("d", function(d) {
  //      var o = {x: d.x0, y: d.y0};
  //      return diagonal({source: o, target: o});
  //    });
}

function transform(d) {
  return "translate(" + x(d.y) + "," + y(d.x) + ")";
}

function translate(d) {
  var sourceX = x(d.target.parent.y);
  var sourceY = y(d.target.parent.x);
  var targetX = x(d.target.y);
  var targetY = (sourceX + targetX) / 2;
  var linkTargetY = y(d.target.x0);
  var result = "M" + sourceX + "," + sourceY + " C" + targetX + "," + sourceY + " " + targetY + "," + y(d.target.x0) + " " + targetX + "," + linkTargetY + "";
  //console.log(result);

  return result;
}


function onEditNode(d) {
  var length = 9;
  var id = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, length);
  addChildNode(d.id, {
    "name": "new child node",
    "id": id,
    "type": "type2"
  });
    stopPropogation();
}

function onAddNode(d) {
  var length = 9;
  var id = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, length);
  addChildNode(d.id, {
    "name": "new child node",
    "id": id,
    "type": "type2"
  });
  stopPropogation();
}

function onRemoveNode(d) {
  var index = d.parent.children.indexOf(d);
  if (index > -1) {
    d.parent.children.splice(index, 1);
  }
  update(d.parent);
  stopPropogation();
}

function addChildNode(parentId, newNode) {
  var node = d3.select('#' + 'node-' + parentId);
  var nodeData = node.datum();
  if (nodeData.children === undefined && nodeData._children === undefined) {
    nodeData.children = [newNode];
  } else if (nodeData._children != null) {
    nodeData._children.push(newNode);
    toggle(nodeData);
  } else if (nodeData.children != null) {
    nodeData.children.push(newNode);
  }
  update(node);
  stopPropogation();
}

function toggleEnable(d) {
  d.enable = !d.enable;
  var node = d3.select('#' + 'node-' + d.id + " .node-label")
    .classed("disabled", !d.enable);
    stopPropogation();
}


function stopPropogation() {
    d3.event.stopPropagation();
}




Aucun commentaire:

Enregistrer un commentaire