D3 org chart, измените кривые линии на прямую - PullRequest
0 голосов
/ 22 января 2019

Я работаю над организационной диаграммой d3.js, ниже приведен пример из codepen https://codepen.io/pablojgarea/pen/PPYLLa

enter image description here

Как изменить кривые линии на прямые. Я попробовал много возможностей из приведенных ниже, поэтому ссылки не помогли.

D3 js - можно ли нарисовать прямые линии между узлами дерева?

функция getParameterByName (name) { name = name.replace (/ [[] /, "\ ["). replace (/ []] /, "\]"); var regex = new RegExp ("[\? &]" + name + "= ([^ & #] *)"), results = regex.exec (location.search); вернуть результаты === ноль? "": decodeURIComponent (результаты 1 .replace (/ + / g, "")); }

function generarImagen() {
  var html = d3.select("svg")
    .attr("title", "test")
    .attr("version", 1.1)
    .attr("xmlns", "http://www.w3.org/2000/svg")
    .node().parentNode.innerHTML;
  $(".preview").html("<img src=data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(html))) + ">");
}

function collapse(d) {
  if (d.children) {
    d._children = d.children;
    d._children.forEach(collapse);
    d.children = null;
  }
}



  /*        $(".node .texto .cuadro-nodo-texto i.fa.fa-info-circle").unbind("click").on("click", function(e){
            var cuadroEnlaces=$(this).closest("g").parent().find(".cuadro-nodo-enlaces");

            if(cuadroEnlaces.is(':visible')){
              cuadroEnlaces.hide()  
            }else{
              cuadroEnlaces.show()  
            }

             //e.preventDefault();
             e.stopPropagation();
             //console.log("enlace");
          });*/
}

function getDepth(obj) {
  var depth = 0;
  if (obj.children) {
    obj.children.forEach(function(d) {
      var tmpDepth = getDepth(d)
      if (tmpDepth > depth) {
        depth = tmpDepth
      }
    })
  }
  return 1 + depth
}

function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
      words = text.text().split(/\s+/).reverse(),
      word,
      line = [],
      lineNumber = 0,
      lineHeight = 1.2, // ems
      x = text.attr("x"),
      y = text.attr("y"),
      dy = text.attr("dy") ? text.attr("dy") : 0;

    tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");
    while (word = words.pop()) {
      line.push(word);
      tspan.text(line.join(" "));
      var centradox = x + (width - tspan.node().getComputedTextLength()) / 2;

      if (tspan.node().getComputedTextLength() > width) {
        line.pop();
        tspan.text(line.join(" "));
        line = [word];
        tspan = text.append("tspan").attr("x", x).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
  });
}

var _queryTreeSort = function(options) {
  var cfi, e, i, id, o, pid, rfi, ri, thisid, _i, _j, _len, _len1, _ref, _ref1;
  id = options.id || "id";
  pid = options.parentid || "parentid";
  ri = [];
  rfi = {};
  cfi = {};
  o = [];
  _ref = options.q;
  for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
    e = _ref[i];
    rfi[e[id]] = i;
    if (cfi[e[pid]] == null) {
      cfi[e[pid]] = [];
    }
    cfi[e[pid]].push(options.q[i][id]);
  }
  _ref1 = options.q;
  for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
    e = _ref1[_j];
    if (rfi[e[pid]] == null) {
      ri.push(e[id]);
    }
  }
  while (ri.length) {
    thisid = ri.splice(0, 1);
    o.push(options.q[rfi[thisid]]);
    if (cfi[thisid] != null) {
      ri = cfi[thisid].concat(ri);
    }
  }
  return o;
};

var _makeTree = function(options) {
  var children, e, id, o, pid, temp, _i, _len, _ref;
  id = options.id || "id";
  pid = options.parentid || "parentid";
  children = options.children || "children";
  temp = {};
  o = [];
  _ref = options.q;
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
    e = _ref[_i];
    e[children] = [];
    temp[e[id]] = e;
    if (temp[e[pid]] != null) {
      temp[e[pid]][children].push(e);
    } else {
      o.push(e);
    }
  }
  return o;
};

var _renderTree = function(tree) {
  var e, html, _i, _len;
  html = "<ul class='sections'>";
  for (_i = 0, _len = tree.length; _i < _len; _i++) {
    e = tree[_i];
    html += "<li class='department'><a href=''><span>" + e.name + "</span></a>";
    if (e.children != null) {
      html += _renderTree(e.children);
    }
    html += "</li>";
  }
  html += "</ul>";
  return html;
};

$(document).ready(function() {

  var id_padre = getParameterByName('organigrama_id_padre');
  if (id_padre == '') {
    id_padre = 1;
  }

  var indiceNodo = 0;

  resultado = _queryTreeSort({
    q: orgJSON
  });
  //    $('#arbol_resultado').html(JSON.stringify(sqlquery, true, 2));

  var treeBD;
  treeBD = _makeTree({
    q: resultado
  });

  var html_arbol = _renderTree(treeBD);
  //    $('#arbol_ordenado').html(JSON.stringify(treeBD, true, 2));

  var margin = {
      top: 20,
      right: 30,
      bottom: 20,
      left: 30
    },
    width = $(".org-chart.cf").width() - margin.right - margin.left,
    height = 1200 - margin.top - margin.bottom;

  var i = 0,
    duration = 750,
    root;

  var tree = d3.layout.tree()
    .size([width, height])
    .separation(function separation(a, b) {
      return (a.parent == b.parent ? 1 : 2) * a.depth;
    });

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

  var svg = d3.select(".org-chart").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    //.attr("viewbox", "0 0 500 500")
    .call(zm = d3.behavior.zoom().scaleExtent([0.5, 3]).on("zoom", redraw))
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .style("text-rendering", "optimizeLegibility")
    .style("shape-rendering", "default");

  var slider = d3.select(".sliderZoom").append("p").append("input")
    .datum({})
    .attr("type", "range")
    .attr("value", 1)
    .attr("min", zm.scaleExtent()[0])
    .attr("max", zm.scaleExtent()[1])
    .attr("step", (zm.scaleExtent()[1] - zm.scaleExtent()[0]) / 100)
    .on("input", slided);

  function slided(d) {
    zm.scale(d3.select(this).property("value"))
      .event(svg);
  }

  zm.translate([margin.left, margin.top]);
  var flare = treeBD[0];

  root = flare;
  root.x0 = width / 2;
  root.y0 = 0;

  var num_nodo = 0;
  /*

      function getIndiceHijo(nodo){
        var padre=
      }*/

  function update(source) {

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

      //var hijosPares = (source._children != null) ? 1 - (source._children.length % 2) : 0;
      //var numeroHijos = 0;
      var profundidadActual = source.depth;
      // Normalize for fixed-depth.
      var indice = 0;
      var niveles = [];

      for (n = 0; n < profundidadArbol; n++) {
        niveles[n] = 0;
      }

      nodes.forEach(function(d, i) {
        //var index = d3.select(this).indexOf(d3.select(this.parentNode).datum());
        //var hijosPares=(d._children != null) ? (1-d._children.length) % 2 : 0;
        //console.log("update");

        /* indice=i-numeroHijos;
         if (d.depth > profundidadActual) {
           numeroHijos=(d._children != null) ? d._children.length  : 0;
         }*/

        niveles[d.depth] = niveles[d.depth] + 1;
        indice = niveles[d.depth];
        //console.log(d.name+":"+d.depth+":"+i+":"+indice);
        if (d.depth > 1) {
          d.y = d.depth * 200;
          if (d.parent.children.length > 2) {
            d.y += (indice % 2) * 75;
          }

        } else if (d.depth == 1) { //primer nivel, menos separación
          d.y = d.depth * 100;
          if (d.parent.children.length > 2) {
            d.y += (indice % 2) * 75;
          }
        } else {
          d.y = 0;
        }

      });

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

      // Enter any new nodes at the parent's previous position.

      var nodeEnter = node.enter();
      var grupoNodo = nodeEnter.append("g")
        .attr("class", "node")
        .attr("id", function(d) {
          return d.id
        })
        .attr("transform", function(d, i) {
          return "translate(" + source.x0 + "," + source.y0 + ")";
        })
        .on("mouseover", mouseover)
        .on("mouseout", mouseout)
        //.call(drag);
      ;

      var grupoTexto = grupoNodo.append("g")
        .attr("class", "texto");

      grupoTexto.append("circle")
        .attr("r", 1e-6)
        .on("click", click)
        .style("fill", function(d) {
          return d._children ? "lightsteelblue" : "lightgrey";
        });

      /*          var cuadroTexto = grupoTexto.append('foreignObject');
                cuadroTexto.attr('dx', function(d) { return 2*d.name.length} )
                      .attr('y', function(d) { return d.children || d._children ? 0 : 100; })
                      .on("click", click)
                      .html(function(d,i) { 
                    var cuadroNodoEnlaces = '<div class="cuadro-nodo-enlaces"><div class="enlaces-nodo">'
                    +'<a title="Ver en directorio" href="/directorio?id='+d.id+'"><i class="fa fa-list-alt"></i></a>'
                    +'<a title="Ver Organigrama" href="<?php echo $_SERVER['REQUEST_URI']; ?>&organigrama_id_padre='+d.id+'"><i class="fa fa-sitemap"></i></a>'
                    +'</div></div>';

                    var cuadroNodo = '<div class="cuadro-nodo-texto">'
                    +cuadroNodoEnlaces
                    +'<div class="texto-nodo">'
                    +d.name
                    +'</div></div>'; 
                        return cuadroNodo;
                    });*/

      //si tiene hijos 

      grupoTexto.append('rect')
        .on("click", click)
        .attr("x", "-75px")
        .attr("y", "20")
        .attr("rx", 4)
        .attr("ry", 4)
        .attr("width", 150)
        .attr("height", 50)
        .attr("fill", "#fff")
        .attr("class", "rectangulo-hijos")
        .style("stroke", "#777")
        //.attr("transform", "rotate(-2)")
        .style("stroke-width", function(d) {
          var hijos = 0;
          if (d._children != null) {
            hijos = d._children.length;
          }
          return (hijos <= 0) ? "0px" : "0.2px";
        });

      grupoTexto.append('rect')
        .on("click", click)
        .attr("x", "-75px")
        .attr("y", "20")
        .attr("rx", 4)
        .attr("ry", 4)
        .attr("width", 150)
        .attr("height", 50)
        .attr("fill", "#fff")
        .attr("class", "rectangulo-hijos2")
        .style("stroke", "#777")
        //.attr("transform", "rotate(2)")
        .style("stroke-width", function(d) {
          var hijos = 0;
          if (d._children != null) {
            hijos = d._children.length;
          }
          return (hijos <= 0) ? "0px" : "0.2px";
        });

      //Dibujamos el cuadro con la barra de enlaces y con el texto de cada departamento
      grupoTexto.append('rect')
        .attr("class", "barra-enlaces")
        .attr("x", "-75px")
        .attr("y", "0")
        .attr("width", 150)
        .attr("height", 20)
        .attr("fill", "#247497")
        .attr("stroke", "#ccc")
        .attr("stroke-width", "0.2px");

      grupoTexto.append('a')
        .attr("x", "-50px")
        .attr("y", "10")
        .attr("xlink:href", function(d) {
          return '/directorio?id=' + d.id;
        })
        .attr("xlink:title", "Ver directorio")
        .attr("fill", "white")
        .attr("height", 20)
        .attr("width", 150)
        .attr("font-size", 12)
        .append('text')
        .attr("font-family", "FontAwesome")
        .attr("x", "40px")
        .attr("y", "15")
        .text('\uf095');

      grupoTexto.append('a')
        .attr("x", "25px")
        .attr("y", "10")
        .attr("xlink:href", function(d) {
          return window.location.href + "&organigrama_id_padre=" + d.id;
        })
        .attr("xlink:title", "Ver organigrama")
        .attr("fill", "white")
        .attr("height", 20)
        .attr("width", 150)
        .attr("font-size", 12)
        .append('text')
        .attr("font-family", "FontAwesome")
        .attr("x", "55px")
        .attr("y", "15")
        .text('\uf0e8');

      grupoTexto.append('rect')
        .on("click", click)
        .attr("x", "-75px")
        .attr("y", "20")
        .attr("rx", 4)
        .attr("ry", 4)
        .attr("width", 150)
        .attr("height", 50)
        .attr("fill", "white")
        .classed("rectangulo-texto", true)
        .attr("stroke", "#777")
        .attr("stroke-width", "0.2px");

      grupoTexto.append('text')
        .on("click", click)
        .text(function(d, i) {
          return d.name;
        })
        .attr("x", "0")
        .attr("text-anchor", "middle")
        .attr("y", "33")
        .attr("font-size", 11)
        .attr("fill", "#555")
        .call(wrap, 140);

      var grupoEnlaces = grupoNodo.append("g").attr("class", "nodo-enlaces");

      /*            grupoEnlaces.append('foreignObject')
                      .attr('dx', function(d) { return 2*d.name.length} )
                    .attr('y', function(d) { return d.children || d._children ? 0 : 100; })
                    .html(function(d,i) { 
                  var cuadroNodo = '<div class="cuadro-nodo-enlaces"><div class="enlaces-nodo">'
                  +'<a href="/directorio?id='+d.id+'"><i class="fa fa-list-alt"></i></a>'
                  +'<a href="<?php echo $_SERVER['REQUEST_URI']; ?>&organigrama_id_padre='+d.id+'"><i class="fa fa-sitemap"></i></a>'
                  +'</div></div>';
                      return cuadroNodo;
                  });*/

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

      nodeUpdate.select("circle")
        .attr("r", 4.5)
        .style("fill", function(d) {
          return d._children ? "lightsteelblue" : "lightgrey";
        });

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

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

      nodeExit.select("circle")
        .attr("r", 1e-6);

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

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

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

      // 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;
      });

      actualizarEventos();
      //d3.selectAll(".node").call(drag);

      /*var delay=2000; //1 seconds

      setTimeout(function(){
        generarImagen();
      }, delay); */
    } //fin update

  // Toggle children on click.
  function click(d) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else {
      d.children = d._children;
      d._children = null;
    }
    /*      var nodo = d3.select(this.parentNode.parentNode);
      activo = nodo.attr("activo");
      if (activo == 1){

        //nodo.moveToBack();

        nodo.attr("activo",0);
        nodo.attr("class","noactivo");

        //d3.select(this.parentNode).select("rect").style("fill","#0079c2");
      }else{
        //nodo.moveToFront();
        nodo.attr("activo",1);
        nodo.attr("class","activo");

        //d3.select(this.parentNode).select("rect").style("fill","#229be4");

      }
      */

    update(d);

  }

  d3.selection.prototype.moveToFront = function() {
    return this.each(function() {
      //this.parentNode.appendChild(this);
      //        this.parentNode.replaceChild(this, this)
    });
  };

  d3.selection.prototype.moveToBack = function() {
    return this.each(function() {
      var firstChild = this.parentNode.firstChild;
      if (firstChild) {
        //    this.remove();
        //this.parentNode.insertBefore(this, firstChild); 
      }
    });
  };

  function redraw(d) {
    $(".sliderZoom input").val(d3.event.scale);
    /*    $( ".texto-nodo" ).each(function() {
          var width = $( this ).outerWidth();
          var maximo =  parseInt($(this).css("max-width")); 
          var minimo = parseInt($(this).css("min-width"));
          if(minimo > width) width=minimo;
        var marginLeft = width / 2;

          if(maximo < (width + marginLeft)){
            width=maximo;   
          }else{
            width = width + marginLeft;
          }
          marginLeft = width / 2;
        // set css
        //$(this).css('margin-left', -marginLeft).css("width", width);

          var position = $(this).offset().top;
          if (position < 180){

            $(this).parent().css("opacity",0);
          }else{
            $(this).parent().css("opacity",1)
          }


      });
    */

    /* var delay=2000; //1 seconds

     setTimeout(function(){
       generarImagen();
     }, delay); */

    var escala = 1;
    var d3scale = d3.event.scale;
    escala = (d3scale > 1) ? (1.1 / d3scale) : 0.8;
    if (d3scale == 1) escala = 1;

    d3.selectAll(".texto").attr("transform", "scale(" + escala + ")");
    //console.log("here", d3.event.translate, d3.event.scale);
    svg.attr("transform",
      "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
  }

  // Initialize the display to show a few nodes.
  //    root.children.forEach(toggleAll);

  root.children.forEach(collapse);
  update(root);

  d3.select(self.frameElement).style("height", "600px").style("width", width);

  /*    $(".cuadro-nodo-enlaces a").on("click", function(e){
        window.location = $(this).attr('href');
         //e.preventDefault();
         e.stopPropagation();
         console.log("enlace");
      });*/

  /*    $(".node .texto .cuadro-nodo-texto i.fa-info-circle").on("click", function(e){
        var cuadroEnlaces=$(this).closest("g").parent().find(".cuadro-nodo-enlaces");

        if(cuadroEnlaces.is(':visible')){
          cuadroEnlaces.hide()  
        }else{
          cuadroEnlaces.show()  
        }
         e.stopPropagation();
         console.log("enlace2");
      });*/
  //d3.selectAll(".node").call(drag);

});
...