D3.js-添加新节点并进行过渡后,旧链接不会被删除

时间:2020-09-09 19:31:34

标签: javascript svg d3.js

我正在努力使Treeview与某些条件逻辑一起使用。我目前有以下工作提琴:https://jsfiddle.net/zgv9ajn4/4/

在jsfiddle中,您可以看到以下图像。在选择名称为“ division”的节点时,我将显示某些橙色的svg,然后单击右下角的svg,将一个新的子节点添加到“ division”节点。

在添加子节点之前并单击节点“ division”:

enter image description here

添加子节点后:-

enter image description here

如您所见,有一些悬挂的链接/节点,它们并没有被删除。

var margin = {
    top: 20,
    right: 120,
    bottom: 20,
    left: 120
  },
  width = 960 - margin.right - margin.left,
  height = 800 - margin.top - margin.bottom;

function generateEmptyDecisionBox(condition) {
  return condition === 'False' ? [{
    "name": "newDecision",
    "id": "newId",
    "type": "decision",
    "value": "notSure",
    "condition": `${condition}`,
  }, {}] : [{}, {
    "name": "newDecision",
    "id": "newId",
    "type": "decision",
    "value": "notSure",
    "condition": `${condition}`,
  }];
}

var selectedNode;
var selectedLink;


var root = {
  "name": "Root",
  "type": "decision",
  "children": [{
      "name": "analytics",
      "condition": "False",
      "type": "decision",
      "value": "a+b",
      "children": [{
        "name": "distinction",
        "type": "action",
        "condition": "True",
        "value": "5",
      }, {
        "name": "nonDistinction",
        "type": "action",
        "condition": "false",
        "value": "4",
        "children": [],
      }],
    },
    {
      "condition": "True",
      "name": "division",
      "type": "decision",
      "value": "a-b",
      "children": {
        "name": "analytics",
        "condition": "False",
        "type": "decision",
        "value": "a+b",
        "children": [{
          "name": "distinction",
          "type": "action",
          "condition": "True",
          "value": "5",
        }, {
          "name": "nonDistinction",
          "type": "decision",
          "condition": "false",
          "value": "4",
          "children": {
            "name": "analytics",
            "condition": "False",
            "type": "decision",
            "value": "a+b",
            "children": [{
              "name": "distinction",
              "type": "action",
              "condition": "True",
              "value": "5",
            }, {
              "name": "nonDistinction",
              "type": "action",
              "condition": "false",
              "value": "4"
            }],
          },
        }],
      },
    }
  ]
};

var i = 0,
  duration = 500,
  rectW = 120,
  rectH = 60;

var tree = d3.layout.tree().nodeSize([150, 90]);



//LINK FUNCTION TO DRAW LINKS 
var linkFunc = function(d) {
  console.log("linkFunc", d);
  var source = {
    x: d.source.x + rectW / 2,
    y: d.source.y + (rectH / 2)
  };
  var target = {
    x: d.target.x + (rectW / 2),
    y: d.target.y + 3,
  };

  // This is where the line bends
  var inflection = {
    x: target.x,
    y: source.y
  };
  var radius = 5;

  var result = "M" + source.x + ',' + source.y;

  if (source.x < target.x && d.target.type) {
    // Child is to the right of the parent
    result += ' H' + (inflection.x - radius);
  } else if (d.target.type) {
    result += ' H' + (inflection.x + radius);
  } else {
    return;
  }

  // Curve the line at the bend slightly
  result += ' Q' + inflection.x + ',' + inflection.y + ' ' + inflection.x + ',' + (inflection.y + radius);

  result += 'V' + target.y;
  return result;
}

// END OF LINK FUNC //


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

// DRAW TREE //
var svg = d3.select(".tree-diagram").append("svg").attr("width", 1000).attr("height", 1000)
  .call(zm = d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", redraw)).append("g")
  .attr("transform", "translate(" + 350 + "," + 20 + ")");

// ADD ARROW TO THE BOTTOM POINTING TO THE NEXT DECISION.

svg.append("svg:defs").selectAll("marker")
  .data(["end"]) // Different link/path types can be defined here
  .enter().append("svg:marker") // This section adds in the arrows
  .attr("id", String)
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 15)
  .attr("refY", 0.5)
  .attr("markerWidth", 4)
  .attr("markerHeight", 4)
  .attr("orient", "auto")
  .append("svg:path")
  .attr("d", "M0,-5L10,0L0,5");

//necessary so that zoom knows where to zoom and unzoom from
zm.translate([350, 20]);

root.x0 = 0;
root.y0 = 0;

update(root);

d3.select(".tree-diagram").style("height", "1000px");

// END OF DRAW TREEE //

function update(source) {

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

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

  // Update the nodes…
  var node = svg.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("g")
    .attr('transform', 'translate(' + source.x0 + ', ' + source.y0 + ')')
    .attr("class", "node")
    .on("click", click)
  //  .on("blur", onNodeBlur);

  nodeEnter.append('path')
    .attr("d", function(d) {
      if (d.type === 'decision') {
        return 'M 60 0 120 30 60 60 0 30 Z';
      } else if (d.type === 'action') {
        return 'M 0 0 120 0 120 60 0 60 Z';
      } else {
        return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
      }
    }).attr("stroke-width", 1)
    .attr('class', 'myPaths')
    .style("fill", function(d) {
      return "lightsteelblue";
    });

  nodeEnter.append("text")
    .attr("x", rectW / 2)
    .attr("y", rectH / 2)
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")
    .text(function(d) {
      return d.name;
    });

  var nodeUpdate = node.transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + (d.x) + "," + (d.y) + ")";
    });


  var nodeExit = node.exit().transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + source.x + "," + source.y + ")";
    })
    .remove();

  nodeExit.select("path")
    .attr("d", function(d) {
      if (d.type === 'decision') {
        return 'M 60 0 120 30 60 60 0 30 Z';
      } else if (d.type === 'action') {
        return 'M 0 0 120 0 120 60 0 60 Z';
      } else {
        return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
      }
    }).attr("stroke-width", 1)
    .attr('class', 'myPaths')
    .style("fill", function(d) {
      return "lightsteelblue";
    });



  nodeExit.select("text");


  // Update the links…
  var link = svg.selectAll("path.link")
    .data(links, function(d) {
      return d.target.id;
    }).classed('link1', true);


  // Enter any new links at the parent's previous position.
  var linkEnter = link.enter().insert("g", "g")
    .attr("class", "link");


  linkEnter.append('path')
    .attr("d", linkFunc)
    .on('click', function(d, i) {
      selectedLink = d;
      // Use the native SVG interface to get the bounding box to
      // calculate the center of the path


      var bbox = this.getBBox();
      var x;
      var y;

      if (d.source.x < d.target.x) {
        // Child is to the right of the parent
        x = bbox.x + bbox.width;
        y = bbox.y;
        plusButton
          .attr('transform', 'translate(' + x + ', ' + y + ')')
          .classed('hide', false);

      } else {
        x = bbox.x;
        y = bbox.y;
        plusButton
          .attr('transform', 'translate(' + x + ', ' + y + ')')
          .classed('hide', false);
      }
    })
    .on('blur', function(d, i) {
      plusButton
        .classed('hide', true);
    }).attr("marker-end", "url(#end)");


  // Add Link Texts.

  linkEnter.append('text')
    .text(function(d, i) {

      if (d.source.x < d.target.x) {
        return 'True';
      } else {
        return 'False';
      }
    }).attr('transform', function(d) {
      console.log(d);
      /*            var bbox = this.getBBox();
                          x=  bbox.x + bbox.width;
                          y=   bbox.y; */
      if (d.source.x < d.target.x && d.target.type) {
        console.log("comes in here for source < target");
        return 'translate(' + (d.source.x + rectW) + ',' + (d.source.y + rectH) + ')';
      } else if (d.target.type) {
        return 'translate(' + (d.source.x - rectW / 2) + ',' + (d.source.y + rectH) + ')';
      } else {
        return;
      }
    });


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

  // Transition links to their new position.

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
    .duration(duration)
    .attr("d", linkFunc)
    .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });
}


// ON CLICK OF NODES 
function click(d) {

  if (d.type === 'action') {
    return;
  }

  selectedNode = d;
  var m = d.x;
  var h = d.y;

  var m = d.x + 110;
  var h = d.y + 35;

  diamondImage
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);

  var m = d.x + 110;
  var h = d.y;

  rectangleShape
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);

  var m = d.x - 20;
  var h = d.y + 35;

  diamondImageFalse
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);

  var m = d.x - 20;
  var h = d.y;

  rectangleShapeFalse
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);
}

/* function onNodeBlur(){
  diamondImage
  .classed('hide', true);
  rectangleShape
    .classed('hide', true);
   diamondImageFalse
     .classed('hide',true);
   rectangleShapeFalse
    .classed('hide',true);  
}
 */
//Redraw for zoom
function redraw() {
  //console.log("here", d3.event.translate, d3.event.scale);
  svg.attr("transform",
    "translate(" + d3.event.translate + ")" +
    " scale(" + d3.event.scale + ")");
}



// oN CALL

function addElement(d, truthy) {
  console.log(d);

  d.children = null;
  d.children = generateEmptyDecisionBox(truthy);
  update(root);
}

// draw elements //

function drawDiamond(centroid) {
  // Start at the top
  console.log(centroid);
  console.log("rectH", rectH, rectW)
  // Start at the top
  var result = 'M' + centroid.x + ',' + (centroid.y - rectH / 2);

  // Go right
  result += 'L' + (centroid.x + rectW / 2) + ',' + centroid.y;

  // Bottom
  result += 'L' + centroid.x + ',' + (centroid.y + rectH / 2);

  // Left
  result += 'L' + (centroid.x - rectW / 2) + ',' + centroid.y;

  // Close the shape
  result += 'Z';

  return result;
}

function drawRect(centroid) {
  // Start at the top left
  console.log(centroid);
  var result = 'M' + (centroid.x - rectW / 2) + ',' + (centroid.y - rectH / 2);

  // Go right
  result += 'h' + rectW;

  // Go down
  result += 'v' + rectH;

  // Left
  result += 'h-' + rectW;

  // Close the shape
  result += 'Z';

  console.log(result);
  return result;
}

var plusButton = svg
  .append('g')
  .classed('button', true)
  .classed('hide', true)
  .on('click', function() {
    console.log("hello");
    /*        addElement(selectedLink.source); */
    console.log("Clicked on Diamond");
    console.log("set hide to true");
    removeAllButtonElements();
  });

plusButton
  .append('rect')
  .attr('transform', 'translate(-8, -8)') // center the button inside the `g`
  .attr('width', 16)
  .attr('height', 16)
  .attr('rx', 2);

plusButton
  .append('path')
  .attr('d', 'M-6 0 H6 M0 -6 V6');

var rectangleShape = svg.append('g')
  .classed('conditionImage', true)
  .classed('hide', true)
  .on('click', function() {
    removeAllButtonElements();
  })

rectangleShape
  .append('rect')
  .attr('width', 30)
  .attr('height', 20)
  .style('fill', 'orange');


var diamondImage = svg.append('g')
  .classed('conditionSvg', true)
  .classed('hide', true)
  .classed('scale', true)
  .on('click', function() {
    console.log("Clicked on Diamond");
    console.log("set hide to true");
    addElement(selectedNode, 'True');
    removeAllButtonElements();
  });

diamondImage
  .append('path')
  .attr('d', 'M 15 0 30 15 15 30 0 15 Z')
  .style("fill", 'orange');


var rectangleShapeFalse = svg.append('g')
  .classed('conditionImage', true)
  .classed('hide', true)
  .on('click', function() {
    console.log("rectangle clicked");
    removeAllButtonElements();
  })

rectangleShapeFalse
  .append('rect')
  .attr('width', 30)
  .attr('height', 20)
  .style('fill', 'orange');

var diamondImageFalse = svg.append('g')
  .classed('conditionImage', true)
  .classed('hide', true)
  .classed('scale', true)
  .on('click', function() {
    console.log("Clicked on Diamond");
    console.log("set hide to true");
    addElement(selectedNode, 'False');
    removeAllButtonElements();
  });

diamondImageFalse
  .append('path')
  .attr('d', 'M 15 0 30 15 15 30 0 15 Z')
  .style("fill", 'orange');


function removeAllButtonElements() {
  plusButton.classed('hide', true);
  diamondImage.classed('hide', true);
  rectangleShape.classed('hide', true);
  diamondImageFalse.classed('hide', true);
  rectangleShapeFalse.classed('hide', true);
}


// draw elements end ..
.node {
  cursor: pointer;
  outline: none !important;
}

.node text {
  font: 10px sans-serif;
}

.button>path {
  stroke: blue;
  stroke-width: 1.5;
  /*   outline: none;  */
}

.button>rect {
  fill: #ddd;
  stroke: grey;
  stroke-width: 1px;
}

.conditionalSvg {
  outline: none;
  display: none;
}

.hide {
  display: none;
  opacity: 0 !important;
  pointer-events: none;
}

.link:hover {
  ouline: none !important;
  cursor: pointer;
  stroke-width: 3px;
}

.link path {
  outline: none !important;
  fill: none;
  stroke: darkgray;
  stroke-width: 2px;
}

.link path:hover {
  cursor: pointer;
  stroke-width: 4px;
}

.link text {
  font: 10px sans-serif;
}

.colorBlue {
  background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div class="tree-diagram"></div>

尽管要添加新节点,而将旧节点转换到最新位置,但不会删除旧节点/链接。

1 个答案:

答案 0 :(得分:2)

请注意,您的节点运行良好,只是链接不正常。这是因为您使用path.link找到了它们,但实际结构是g.link path,因为首先添加了一个类为g的{​​{1}}元素,然后添加了一个{{1} }。您可以通过将link更改为path来解决此问题,但随后需要分别选择path.linkg.link

我通过在所有所有链接上调用path,而不仅仅是新链接,并在所有文本上调用text.attr('d', linkFunc)来解决此问题。

最后,我更改了文本转换以使用目标的.text(),因为目标确定了行的垂直位置,而不是源。

.attr('transform'
x
var margin = {
    top: 20,
    right: 120,
    bottom: 20,
    left: 120
  },
  width = 960 - margin.right - margin.left,
  height = 800 - margin.top - margin.bottom;

function generateEmptyDecisionBox(condition) {
  return condition === 'False' ? [{
    "name": "newDecision",
    "id": "newId",
    "type": "decision",
    "value": "notSure",
    "condition": `${condition}`,
  }, {}] : [{}, {
    "name": "newDecision",
    "id": "newId",
    "type": "decision",
    "value": "notSure",
    "condition": `${condition}`,
  }];
}

var selectedNode;
var selectedLink;


var root = {
  "name": "Root",
  "type": "decision",
  "children": [{
      "name": "analytics",
      "condition": "False",
      "type": "decision",
      "value": "a+b",
      "children": [{
        "name": "distinction",
        "type": "action",
        "condition": "True",
        "value": "5",
      }, {
        "name": "nonDistinction",
        "type": "action",
        "condition": "false",
        "value": "4",
        "children": [],
      }],
    },
    {
      "condition": "True",
      "name": "division",
      "type": "decision",
      "value": "a-b",
      "children": {
        "name": "analytics",
        "condition": "False",
        "type": "decision",
        "value": "a+b",
        "children": [{
          "name": "distinction",
          "type": "action",
          "condition": "True",
          "value": "5",
        }, {
          "name": "nonDistinction",
          "type": "decision",
          "condition": "false",
          "value": "4",
          "children": {
            "name": "analytics",
            "condition": "False",
            "type": "decision",
            "value": "a+b",
            "children": [{
              "name": "distinction",
              "type": "action",
              "condition": "True",
              "value": "5",
            }, {
              "name": "nonDistinction",
              "type": "action",
              "condition": "false",
              "value": "4"
            }],
          },
        }],
      },
    }
  ]
};

var i = 0,
  duration = 500,
  rectW = 120,
  rectH = 60;

var tree = d3.layout.tree().nodeSize([150, 90]);



//LINK FUNCTION TO DRAW LINKS 
var linkFunc = function(d) {
  console.log("linkFunc", d);
  var source = {
    x: d.source.x + rectW / 2,
    y: d.source.y + (rectH / 2)
  };
  var target = {
    x: d.target.x + (rectW / 2),
    y: d.target.y + 3,
  };

  // This is where the line bends
  var inflection = {
    x: target.x,
    y: source.y
  };
  var radius = 5;

  var result = "M" + source.x + ',' + source.y;

  if (source.x < target.x && d.target.type) {
    // Child is to the right of the parent
    result += ' H' + (inflection.x - radius);
  } else if (d.target.type) {
    result += ' H' + (inflection.x + radius);
  } else {
    return;
  }

  // Curve the line at the bend slightly
  result += ' Q' + inflection.x + ',' + inflection.y + ' ' + inflection.x + ',' + (inflection.y + radius);

  result += 'V' + target.y;
  return result;
}

// END OF LINK FUNC //


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

// DRAW TREE //
var svg = d3.select(".tree-diagram").append("svg").attr("width", 1000).attr("height", 1000)
  .call(zm = d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", redraw)).append("g")
  .attr("transform", "translate(" + 350 + "," + 20 + ")");

// ADD ARROW TO THE BOTTOM POINTING TO THE NEXT DECISION.

svg.append("svg:defs").selectAll("marker")
  .data(["end"]) // Different link/path types can be defined here
  .enter().append("svg:marker") // This section adds in the arrows
  .attr("id", String)
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 15)
  .attr("refY", 0.5)
  .attr("markerWidth", 4)
  .attr("markerHeight", 4)
  .attr("orient", "auto")
  .append("svg:path")
  .attr("d", "M0,-5L10,0L0,5");

//necessary so that zoom knows where to zoom and unzoom from
zm.translate([350, 20]);

root.x0 = 0;
root.y0 = 0;

update(root);

d3.select(".tree-diagram").style("height", "1000px");

// END OF DRAW TREEE //

function update(source) {

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

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

  // Update the nodes…
  var node = svg.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("g")
    .attr('transform', 'translate(' + source.x0 + ', ' + source.y0 + ')')
    .attr("class", "node")
    .on("click", click)
  //  .on("blur", onNodeBlur);

  nodeEnter.append('path')
    .attr("d", function(d) {
      if (d.type === 'decision') {
        return 'M 60 0 120 30 60 60 0 30 Z';
      } else if (d.type === 'action') {
        return 'M 0 0 120 0 120 60 0 60 Z';
      } else {
        return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
      }
    }).attr("stroke-width", 1)
    .attr('class', 'myPaths')
    .style("fill", function(d) {
      return "lightsteelblue";
    });

  nodeEnter.append("text")
    .attr("x", rectW / 2)
    .attr("y", rectH / 2)
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")
    .text(function(d) {
      return d.name;
    });

  var nodeUpdate = node.transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + (d.x) + "," + (d.y) + ")";
    });


  var nodeExit = node.exit().transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + source.x + "," + source.y + ")";
    })
    .remove();

  nodeExit.select("path")
    .attr("d", function(d) {
      if (d.type === 'decision') {
        return 'M 60 0 120 30 60 60 0 30 Z';
      } else if (d.type === 'action') {
        return 'M 0 0 120 0 120 60 0 60 Z';
      } else {
        return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
      }
    }).attr("stroke-width", 1)
    .attr('class', 'myPaths')
    .style("fill", function(d) {
      return "lightsteelblue";
    });



  nodeExit.select("text");

  // Update the links…
  var link = svg.selectAll(".link")
    .data(links, function(d) {
      return d.target.id;
    }).classed('link1', true);


  // Enter any new links at the parent's previous position.
  var linkEnter = link.enter()
    .insert("g", "g")
    .attr("class", "link");

  linkEnter.append('path')
    .on('click', function(d, i) {
      selectedLink = d;
      // Use the native SVG interface to get the bounding box to
      // calculate the center of the path


      var bbox = this.getBBox();
      var x;
      var y;

      if (d.source.x < d.target.x) {
        // Child is to the right of the parent
        x = bbox.x + bbox.width;
        y = bbox.y;
        plusButton
          .attr('transform', 'translate(' + x + ', ' + y + ')')
          .classed('hide', false);

      } else {
        x = bbox.x;
        y = bbox.y;
        plusButton
          .attr('transform', 'translate(' + x + ', ' + y + ')')
          .classed('hide', false);
      }
    })
    .on('blur', function(d, i) {
      plusButton
        .classed('hide', true);
    }).attr("marker-end", "url(#end)");


  // Add Link Texts.
  linkEnter.append('text');

  link.select('path')
    .attr("d", linkFunc);
  
  link.select('text')
    .text(function(d, i) {
      if (d.source.x < d.target.x) {
        return 'True';
      } else {
        return 'False';
      }
    })
    .attr('transform', function(d) {
      console.log(d);
      if (d.source.x < d.target.x && d.target.type) {
        console.log("comes in here for source < target");
        return 'translate(' + (d.target.x + rectW / 2) + ',' + (d.source.y + rectH) + ')';
      } else if (d.target.type) {
        return 'translate(' + (d.target.x + rectW / 2) + ',' + (d.source.y + rectH) + ')';
      } else {
        return;
      }
    });

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

  // Transition links to their new position.

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
    .duration(duration)
    .attr("d", linkFunc)
    .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });
}


// ON CLICK OF NODES 
function click(d) {

  if (d.type === 'action') {
    return;
  }

  selectedNode = d;
  var m = d.x;
  var h = d.y;

  var m = d.x + 110;
  var h = d.y + 35;

  diamondImage
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);

  var m = d.x + 110;
  var h = d.y;

  rectangleShape
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);

  var m = d.x - 20;
  var h = d.y + 35;

  diamondImageFalse
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);

  var m = d.x - 20;
  var h = d.y;

  rectangleShapeFalse
    .attr('transform', 'translate(' + m + ', ' + h + ')')
    .classed('hide', false);
}

/* function onNodeBlur(){
  diamondImage
  .classed('hide', true);
  rectangleShape
    .classed('hide', true);
   diamondImageFalse
     .classed('hide',true);
   rectangleShapeFalse
    .classed('hide',true);  
}
 */
//Redraw for zoom
function redraw() {
  //console.log("here", d3.event.translate, d3.event.scale);
  svg.attr("transform",
    "translate(" + d3.event.translate + ")" +
    " scale(" + d3.event.scale + ")");
}



// oN CALL

function addElement(d, truthy) {
  console.log(d);

  d.children = null;
  d.children = generateEmptyDecisionBox(truthy);
  update(root);
}

// draw elements //

function drawDiamond(centroid) {
  // Start at the top
  console.log(centroid);
  console.log("rectH", rectH, rectW)
  // Start at the top
  var result = 'M' + centroid.x + ',' + (centroid.y - rectH / 2);

  // Go right
  result += 'L' + (centroid.x + rectW / 2) + ',' + centroid.y;

  // Bottom
  result += 'L' + centroid.x + ',' + (centroid.y + rectH / 2);

  // Left
  result += 'L' + (centroid.x - rectW / 2) + ',' + centroid.y;

  // Close the shape
  result += 'Z';

  return result;
}

function drawRect(centroid) {
  // Start at the top left
  console.log(centroid);
  var result = 'M' + (centroid.x - rectW / 2) + ',' + (centroid.y - rectH / 2);

  // Go right
  result += 'h' + rectW;

  // Go down
  result += 'v' + rectH;

  // Left
  result += 'h-' + rectW;

  // Close the shape
  result += 'Z';

  console.log(result);
  return result;
}

var plusButton = svg
  .append('g')
  .classed('button', true)
  .classed('hide', true)
  .on('click', function() {
    console.log("hello");
    /*        addElement(selectedLink.source); */
    console.log("Clicked on Diamond");
    console.log("set hide to true");
    removeAllButtonElements();
  });

plusButton
  .append('rect')
  .attr('transform', 'translate(-8, -8)') // center the button inside the `g`
  .attr('width', 16)
  .attr('height', 16)
  .attr('rx', 2);

plusButton
  .append('path')
  .attr('d', 'M-6 0 H6 M0 -6 V6');

var rectangleShape = svg.append('g')
  .classed('conditionImage', true)
  .classed('hide', true)
  .on('click', function() {
    removeAllButtonElements();
  })

rectangleShape
  .append('rect')
  .attr('width', 30)
  .attr('height', 20)
  .style('fill', 'orange');


var diamondImage = svg.append('g')
  .classed('conditionSvg', true)
  .classed('hide', true)
  .classed('scale', true)
  .on('click', function() {
    console.log("Clicked on Diamond");
    console.log("set hide to true");
    addElement(selectedNode, 'True');
    removeAllButtonElements();
  });

diamondImage
  .append('path')
  .attr('d', 'M 15 0 30 15 15 30 0 15 Z')
  .style("fill", 'orange');


var rectangleShapeFalse = svg.append('g')
  .classed('conditionImage', true)
  .classed('hide', true)
  .on('click', function() {
    console.log("rectangle clicked");
    removeAllButtonElements();
  })

rectangleShapeFalse
  .append('rect')
  .attr('width', 30)
  .attr('height', 20)
  .style('fill', 'orange');

var diamondImageFalse = svg.append('g')
  .classed('conditionImage', true)
  .classed('hide', true)
  .classed('scale', true)
  .on('click', function() {
    console.log("Clicked on Diamond");
    console.log("set hide to true");
    addElement(selectedNode, 'False');
    removeAllButtonElements();
  });

diamondImageFalse
  .append('path')
  .attr('d', 'M 15 0 30 15 15 30 0 15 Z')
  .style("fill", 'orange');


function removeAllButtonElements() {
  plusButton.classed('hide', true);
  diamondImage.classed('hide', true);
  rectangleShape.classed('hide', true);
  diamondImageFalse.classed('hide', true);
  rectangleShapeFalse.classed('hide', true);
}


// draw elements end ..