Пример #1
0
  function update() {
    const links = d3.layout.tree().links(nodes)

    // Restart the force layout.
    force
      .nodes(nodes)
      .links(links)
      .start()

    // Update the links…
    link = link.data(links, (d) => d.target.id )

    // Exit any old links.
    link.exit().remove()

    // Enter any new links.
    link.enter().insert('line', '.node')
      .attr('class', 'link')
      .attr('x1', (d) => d.source.x)
      .attr('y1', (d) => d.source.y)
      .attr('x2', (d) => d.target.x)
      .attr('y2', (d) => d.target.y)

    // Update the nodes…
    node = node.data(nodes, (d) => d.id ).style('fill', color)

    // Exit any old nodes.
    node.exit().remove()

    const drag = force.drag()
      .on('dragstart', () => d3.event.sourceEvent.stopPropagation())

    // Enter any new nodes.
    node.enter().append('circle')
      .attr('class', 'node')
      .attr('cx', (d) => d.x )
      .attr('cy', (d) => d.y )
      .attr('r', (d) => d.size)
      .style('fill', color)
      .on('click', clickNode)
      .call(drag)

    svg.on('dblclick.zoom', (d) => {
      d3.event.stopPropagation()
      var dcx = (window.innerWidth / 2 - d.x * zoom.scale())
      var dcy = (window.innerHeight / 2 - d.y * zoom.scale())
      zoom.translate([dcx, dcy])
      vis.attr('transform', `translate(${dcx},${dcy})scale(${zoom.scale()})`)
    })
  }
Пример #2
0
                render: function () {

                    tree = d3.layout.tree().size([500, 800]);
                    render({});

                    // initialize the id of the nodes
                    svg.selectAll("g.node").each(function (d) {
                        $(this).attr("data-id", d.id); // always set the nodes with their identifiers
                    });

                    // set initial zoom
                    changeZoom([100, 0], 1);
                    
                },
module.exports = function() {
  var div = document.createElement('div');

  var diameter = 1100;

  var tree = d3.layout.tree()
      .size([360, diameter / 2 - 120])
      .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

  var diagonal = d3.svg.diagonal.radial()
      .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

  var svg = d3.select(div).append("svg")
      .attr("width", diameter)
      .attr("height", diameter - 150)
      .style("margin-top", -200)
      .style("margin-left", -40)
      .append("g")
      .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

  var nodes = tree.nodes(flare),
      links = tree.links(nodes);

  var link = svg.selectAll(".link")
      .data(links)
      .enter().append("path")
      .attr("class", "linkRT")
      .attr("d", diagonal);

  var node = svg.selectAll(".node")
      .data(nodes)
      .enter().append("g")
      .attr("class", "nodeRT")
      .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })

  node.append("circle")
      .attr("r", 4.5);

  node.append("text")
      .attr("dy", ".31em")
      .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
      .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
      .text(function(d) { return d.name; });


  d3.select(self.frameElement).style("height", diameter - 150 + "px");

  return div;
}
Пример #4
0
  function update() {
    var nodes = flatten(root),
      links = d3.layout.tree().links(nodes);

    // Restart the force layout.
    force
      .nodes(nodes)
      .links(links)
      .start();

    // Update links.
    link = link.data(links, function(d) {
      return d.target.id;
    });

    link.exit().remove();

    link.enter().insert("line", ".node")
      .attr("class", "link " + (connectionType || ''));

    // Update nodes.
    node = node.data(nodes, function(d) {
      return d.id;
    });

    node.exit().remove();

    var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .on("click", click)
      .on("mouseover", hover)
      .on("mouseout", hideHover)
      .call(force.drag);

    nodeEnter.append("circle")
      .attr("r", function(d) {
        return 25;
      });

    nodeEnter.append("text")
      .attr("dy", ".35em")
      .text(function(d) {
        return d.name;
      });

    node.select("circle")
      .style("fill", color);
  }
Пример #5
0
  initd3: function() {
    var self = this;
    this.width = $(window).width();
    this.height = $(window).height() - this.margin.top;
    this.data.x0 = this.height / 2;
    this.data.y0 = 0;
    this.tree = d3.layout.tree().size([self.height, self.width]);

    this.svg = d3.select(this.el).append('svg')
      .attr('id', 'wikimapper-svg')
      .attr('width', this.width)
      .attr('height', this.height)
      .append('g')
      .attr('transform', 'translate(' + this.margin.left + ',0)');

    // then draw the data
    this.draw(this.data);
  },
Пример #6
0
Template.hello.onCreated(function () {
  // counter starts at 0
  var canvas = d3.select('body').append('svg')
		.attr('width',500)
		.attr('height',500)
		.append('g')
		.attr("transform", "translate(50,50)");
	
	var tree = d3.layout.tree()
		.size([400,400]);
	
	console.log("a;ldkfj");
	d3.json("../../../../../mydata.json", function(data) {
		console.log(data);
		var nodes = tree.nodes(data);
		var links = tree.links(nodes);
		console.log(nodes);
		var node = canvas.selectAll(".node")
			.data(nodes)
			.enter()
			.append("g")
				.attr("class","node")
				.attr("transform", function(d) {return "translate (" + d.x + "," + d.y + ")"; })
		
		node.append("circle")
			.attr("r",5)
			.attr("fill","steelblue");
		
		node.append("text")
			.text(function (d) {return d.name})
		
		var diagnoal = d3.svg.diagonal();
		
		canvas.selectAll(".link")
			.data(links)
			.enter()
			.append("path")
			.attr("class","link")
			.attr("fill","none")
			.attr("stroke","#ADADAD")
			.attr("d",diagnoal);
	});
});
Пример #7
0
  /**
   * generateTree - Generates tree elements (`nodes` and `links`) by
   * grabbing the rootNode from `this.state.data[0]`.
   * Restricts tree depth to `props.initialDepth` if defined and if this is
   * the initial render of the tree.
   *
   * @return {object} Object containing `nodes` and `links`.
   */
  generateTree() {
    const {
      initialDepth,
      depthFactor,
      separation,
      nodeSize,
      orientation,
    } = this.props;


    const tree = layout.tree()
      .nodeSize(orientation === 'horizontal' ?
        [nodeSize.y, nodeSize.x] :
        [nodeSize.x, nodeSize.y]
      )
      .separation((a, b) => deepEqual(a.parent, b.parent) ?
        separation.siblings :
        separation.nonSiblings
      )
      .children((d) => d._collapsed ? null : d._children);

    const rootNode = this.state.data[0];
    const nodes = tree.nodes(rootNode);
    const links = tree.links(nodes);

    // set `initialDepth` on first render if specified
    if (initialDepth !== undefined && this.state.initialRender) {
      this.setInitialTreeDepth(nodes, initialDepth);
    }

    if (depthFactor) {
      nodes.forEach((node) => { node.y = node.depth * depthFactor; });
    }

    return { nodes, links };

  }
  constructor(props) {
    super(props);

    var tree = d3.layout.tree().size([this.props.height, this.props.width]),
        nodes = tree.nodes(this.props.source),
        links = tree.links(nodes);

    nodes.forEach((d, index) => {
      d._children = undefined;
      d.id = index;
      d.y = d.depth * 180;
      d.x0 = d.x;
      d.y0 = d.y;
      d.isDisplay = true;
    });

    this.state = {
      isDragging: false,
      tree: tree,
      nodes: nodes,
      links: links,
      eventNode: nodes[0]
    };
  }
Пример #9
0
function renderTree(rootNode, _mainContent, display) {
    var root = {
        dom: _mainContent[0],
        jq: _mainContent
    };
    var margin = { top: 30, right: 20, bottom: 30, left: 20 };
    var width = root.jq.width() - margin.left - margin.right;
    var barHeight = 30;
    var barWidth = width * .8;
    var i = 0, duration = 400;
    var tree = d3.layout.tree()
        .nodeSize([0, 20]);
    var diagonal = d3.svg.diagonal()
        .projection(function (d) { return [d.y, d.x]; });
    var graphRoot = d3.select(root.dom).append("svg")
        .attr("width", width + margin.left + margin.right);
    var graph = graphRoot.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var selected;
    select(rootNode);
    function update() {
        var nodes = tree.nodes(rootNode);
        var height = Math.max(500, nodes.length * barHeight + margin.top + margin.bottom);
        d3.select("svg").transition()
            .duration(duration)
            .attr("height", height);
        d3.select(self.frameElement).transition()
            .duration(duration)
            .style("height", height + "px");
        nodes.forEach(function (n, i) {
            n.x = i * barHeight;
        });
        var node = graph.selectAll("g.node")
            .data(nodes, function (d) { return d.id || (d.id = ++i); });
        var nodeEnter = node.enter().append("g")
            .attr("class", "node")
            .attr("transform", function (d) { return "translate(" + rootNode.depth + "," + rootNode.nodeIndex + ")"; })
            .style("opacity", 1e-6);
        nodeEnter.append("rect")
            .attr("y", -barHeight / 2)
            .attr("height", barHeight)
            .attr("width", barWidth)
            .style("fill", color)
            .on("click", select);
        nodeEnter.append("text")
            .attr("dy", 3.5)
            .attr("dx", 5.5)
            .text(function (d) {
            return d.kind;
        });
        nodeEnter.transition()
            .duration(duration)
            .attr("transform", function (d) { return "translate(" + d.y + "," + d.x + ")"; })
            .style("opacity", 1);
        node.transition()
            .duration(duration)
            .attr("transform", function (d) { return "translate(" + d.y + "," + d.x + ")"; })
            .style("opacity", 1)
            .select("rect")
            .style("fill", color);
        node.exit().transition()
            .duration(duration)
            .attr("transform", function (d) { return "translate(" + rootNode.nodeIndex + "," + rootNode.depth + ")"; })
            .style("opacity", 1e-6)
            .remove();
        var link = graph.selectAll("path.link")
            .data(tree.links(nodes), function (d) { return d.target.id; });
        link.enter().insert("path", "g")
            .attr("class", "link")
            .attr("d", function (d) {
            var o = { x: rootNode.depth, y: rootNode.nodeIndex };
            return diagonal({ source: o, target: o });
        })
            .transition()
            .duration(duration)
            .attr("d", diagonal);
        link.transition()
            .duration(duration)
            .attr("d", diagonal);
        link.exit().transition()
            .duration(duration)
            .attr("d", function (d) {
            var o = { x: rootNode.depth, y: rootNode.nodeIndex };
            return diagonal({ source: o, target: o });
        })
            .remove();
    }
    function resize() {
        width = root.jq.width() - margin.left - margin.right;
        d3.select("svg").attr("width", width);
        update();
    }
    d3.select(root.dom).on("resize", resize);
    resize();
    function select(node) {
        display(node);
        selected = node;
        update();
    }
    function color(d) {
        if (selected == d) {
            return "rgb(140, 0, 0)";
        }
        return d.children ? "#000000" : "rgb(29, 166, 0)";
    }
}
Пример #10
0
function drawTree(selector, prereqs, lockedModules, modCode) {
  function isOrAnd (d) { return (d.name === 'or' || d.name === 'and'); }
  function modsFilter (d) { return !isOrAnd(d); }
  function andOrFilter (d) { return isOrAnd(d); }
  function getX (d) { return isOrAnd(d) ? -25 : -60; }
  function getY (d) { return isOrAnd(d) ? -17.5 : -35; }
  function getHeight (d) { return isOrAnd(d) ? 35 : 60; }
  function getWidth (d) { return isOrAnd(d) ? 50 : 120; }
  function getDefaultTranslation() { return [(SVGWidth) / 2, 180]; }
  function mouseOver (d) {
    /* jshint validthis: true */
    if (!isOrAnd(d)) {
      rectangles.filter(modsFilter)
                .classed({'active-rect': false, 'opaque': false, 'translucent': true});
      d3.select(this).selectAll('rect').classed({'active-rect': true, 'opaque': true, 'translucent': false});
    }
  }
  function mouseOut () {
    rectangles.filter(modsFilter)
              .classed({'active-rect': false, 'opaque': true, 'translucent': false});
  }
  function clicked (d) {
    if (!isOrAnd(d) && d.name in allMods) {
      window.location.href = '/modules/' + d.name;
    }
  }
  function resized() {
    SVGWidth = $(selector).width();
    d3.select('#svg').attr('width', SVGWidth);

    interact.translate(getDefaultTranslation());
    d3.select('#drawarea')
      .transition()
      .delay(1)
      .attr('transform', 'translate('+getDefaultTranslation()+') scale('+interact.scale()+')');
  }

  var SVGWidth = $(selector).width(),
      SVGHeight = 400,
      allMods = NUSMods.getAllModules();

  d3.selectAll('svg').remove();
  var canvas = d3.select(selector)
                  .append('svg')
                  .attr('id', 'svg')
                  .attr('width', SVGWidth)
                  .attr('height', SVGHeight),
      interact = d3.behavior.zoom()
                    .scaleExtent([0.0, 5.0])
                    .size([960, 500])
                    .on('zoom', function () {
                      d3.select('#drawarea')
                        .attr('transform', 'translate('+d3.event.translate+') scale('+d3.event.scale+')');
                    });
  interact(d3.select('svg'));
  canvas = canvas.append('g')
                  .attr('id', 'drawarea');

  $(window).on('resize', _.debounce(resized, 100));
  resized();

  var tree = d3.layout.tree().nodeSize([130, 130]);
  var nodes = tree.nodes(prereqs);
  var links = tree.links(nodes);
  var diagonal = d3.svg.diagonal().projection(function (d) { return [d.x, d.y]; });

  var treeLm = d3.layout.tree().nodeSize([130, 130]);
  var nodesLm = treeLm.nodes(lockedModules);
  var linksLm = treeLm.links(nodesLm);
  var diagonalLm = d3.svg.diagonal().projection(function (d) { return [d.x, -d.y]; });

  canvas.selectAll('.link')
      .data(links)
      .enter()
      .append('path')
      .classed({'link': true, 'test': true})
      .attr('d', diagonal);

  canvas.selectAll('.link.locked-modules')
      .data(linksLm)
      .enter()
      .append('path')
      .classed({'link': true, 'locked-modules': true})
      .attr('d', diagonalLm);

  canvas.selectAll('.node')
        .data(nodes)
        .enter()
        .append('g')
        .attr('class', 'node')
        .attr('transform', function (d) {
          return 'translate('+d.x+','+d.y+')';
        });

  canvas.selectAll('.node.locked-modules')
        .data(nodesLm)
        .enter()
        .append('g')
        .classed({'node': true, 'locked-modules': true})
        .attr('transform', function (d) {
          return 'translate('+d.x+','+-d.y+')';
        });
  var nodeAll = canvas.selectAll('.node');

  var rectangles = nodeAll.append('rect')
                        .attr('width', 0)
                        .attr('height', 0)
                        .attr('x', getX)
                        .attr('y', getY)
                        .attr('rx', 20)
                        .attr('ry', 20)
                        .classed({'rect': true, 'opaque': true})
                        .attr('nodeValue', function (d) { return d.name; });
  rectangles.filter(modsFilter)
            .classed({'mod-rect': true, 'non-linkable-mod': true})
            .filter(function (d) { return d.name in allMods; })
            .classed({'non-linkable-mod': false, 'linkable-mod': true});
  rectangles.filter(andOrFilter)
            .classed({'andor-rect': true});
  rectangles.filter(function (d) { return d.name === modCode; })
            .classed({'current-mod-rect': true});

  var labels = nodeAll.append('text')
                    .text(function (d) { return d.name; })
                    .classed({'rect-label': true, 'lead': true, 'transparent': true})
                    .attr('dy', function (d) { return isOrAnd(d)? '10' : ''; });
  labels.filter(andOrFilter)
        .classed({'andor-label': true});
  labels.filter(modsFilter)
        .classed({'non-linkable-mod': true})
        .filter(function (d) { return d.name in allMods; })
        .classed({'non-linkable-mod': false, 'linkable-mod': true});

  canvas.selectAll('path')
        .classed({'opacity-transition': true, 'opaque': true, 'transparent': false});

  nodeAll.selectAll('rect')
          .transition()
          .duration(1000)
          .attr('width', getWidth)
          .attr('height', getHeight)
          .ease('elastic');

  nodeAll.selectAll('text')
      .classed({'opacity-transition': true, 'opaque': true, 'transparent': false});

  nodeAll.on('mouseover', mouseOver);
  nodeAll.on('mouseout', mouseOut);
  nodeAll.on('click', clicked);
}
Пример #11
0
window.onload = function() {
  // new Vue({
  //   el: '#main',
  //   template: template()
  // })

  // let colors = ['red', 'green', 'blue']
  // let svg = d3.select('svg')
  // svg.selectAll('circle')
  // .data(colors)
  // .enter()
  // .append('circle')
  // .attr('cx', (d, i) => {
  //   return (i + 1) * 20
  // })
  // .attr('cy', (d, i) => {
  //   return (i + 1) * 20
  // })
  // .attr('fill', d => {
  //   return d
  // })
  // .attr('r', (d, i) => {
  //   return (i + 1) * 5
  // })
  // .transition()
  // .duration(2000)
  // .ease('bounce')
  // .attr('cy', () => {
  //   return 500
  // })
  // .attr('fill', (d, i) => {
  //   if (i > colors.length - 2) {
  //     return colors[0]
  //   }
  //   return colors[i + 1]
  // })

  // let images = ['debian', 'vim', 'bash']
  // svg.selectAll('image')
  // .data(images)
  // .enter()
  // .append('image')
  // .attr('xlink:href', d => {
  //   return require(`../images/${d}.png`)
  // })
  // .attr('y', () => {
  //   return 100
  // })
  // .attr('x', (d, i) => {
  //   return (i + 1) * 100
  // })
  // .attr('width', 100)
  // .attr('height', 100)

  // let edges = [{
  //   source: 0, target: 1
  // }, {
  //   source: 0, target: 2
  // }]

  // let nodes = images.map(i => {return {name: i}})
  // let imageData = images.map(d => {return require(`../images/${d}.png`)})

  // let force = d3.layout.force()
  // .nodes(nodes)
  // .links(edges)
  // .size([500, 500])
  // .linkDistance(200)
  // .charge([-400])

  // force.start()

  // // console.log(edges)
  // let svg_edges = svg.selectAll('line')
  //   .data(edges)
  //   .enter()
  //   .append('line')
  //   .style('stroke', '#ccc')
  //   .style('stroke-width', 1)
  //   .attr('marker-end', 'url(#arrow)')

  // // let color = d3.scale.category20()

  // let svg_nodes = svg.selectAll('image')
  //   .data(nodes)
  //   .enter()
  //   .append('image')
  //   .attr('xlink:href', (d, i) => {
  //     return imageData[i]
  //   })
  //   .attr('width', 100)
  //   .attr('height', 100)
  //   // .attr('r', 20)
  //   // .style('fill', function(d, i) {
  //   //   return color(i)
  //   // })
  //   .call(force.drag)  //使得节点能够拖动

  // let svg_texts = svg.selectAll('text')
  //   .data(nodes)
  //   .enter()
  //   .append('text')
  //   .style('fill', 'black')
  //   // .attr('dx', 0)
  //   .attr('dy', 100)
  //   .text(function(d) {
  //     return d.name
  //   })

  // force.on('tick', () => {
  //   svg_edges.attr('x1', d => {return d.source.x + 50})
  //   .attr('y1', d => {return d.source.y + 100})
  //   .attr('x2', d => {return d.target.x + 50})
  //   .attr('y2', d => {return d.target.y})

  //   svg_nodes.attr('x', function(d) {return d.x})
  //   .attr('y', d => {return d.y})

  //   svg_texts.attr('x', d => {return d.x})
  //   .attr('y', d => {return d.y})
  // })


  let tree = d3.layout.tree()
    // .size([width, height - 200])
    .nodeSize([150, 250])

  let nodes = tree.nodes(treeData)

  let centerWidth = 2000
  let svg = d3.select('svg')
    .append('g')
    .attr('transform', `translate(${centerWidth}, 100)`)
  // let growTime = 1500

  let draw = nodes => {
    let links = tree.links(nodes)

    let diagonal = d3.svg.diagonal()
      .projection(function(d, i) {
        // 顶点定在首图的下部
        if (i === 0) {
          return [d.x, d.y + 50]
        }
        // 终点定在children图的顶部
        if (i === 3) {
          return [d.x, d.y - 50]
        }
        return [d.x, d.y]
      })

    let lines = svg.selectAll('.link')
      .data(links)
      .enter()
      .append('path')
      .attr({class: 'link'})
      .attr('d', diagonal)
    setTimeout(() => {
      lines.attr({'marker-end': 'url(#arrow)'})
    }, 1000)
    let node = svg.selectAll('.node').data(nodes)

    node
    .enter()
    .append('image')
    .attr('xlink:href', d => {
      return require(`../images/${d.name}.png`)
    }).attr({width: 100, height: 100})
    .attr('x', function(d) {
      return d.x - 50
    })
    .attr('y', function(d) {
      return d.y - 40
    })
    .on('click', function() {
      console.log(this.getBoundingClientRect())
      d3.select(this)
      .style('transform', 'rotate(0deg)')
      .transition()
      .duration(500)
      .ease('bounce')
      .style('transform', 'rotate(30deg)')
    })
    // .on('mousemove', function() {
    //   d3.event.preventDefault()
    //   d3.event.stopPropagation()
    // })
    // .on('mouseout', function() {
    //   d3.select(this)
    //   .transition()
    //   .duration(1000)
    //   .ease('bounce')
    //   .style('transform', 'rotate(0deg)')
    // })
    .classed('revert', true)
  }

  draw(nodes)


  // times(7, t => {
  //   setTimeout(() => {
  //     draw(filter(nodes, n => {
  //       return n.depth <= t
  //     }))
  //     // node.classed('rotateX90', d => {
  //     //   return t < d.depth
  //     // })
  //     // lines.attr({'marker-end': 'url(#arrow)'})
  //   }, growTime * t)
  // })
}
Пример #12
0
exports.drawTree = function (source) {
  var margin = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 50
    },
    width = 1600 - margin.right - margin.left,
    height = 1200 - margin.top - margin.bottom;

  var i = 0; // node id

  var tree = d3.layout.tree()
    .size([height, width]);

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

  var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  //add css stylesheet
  var svg_style = svg.append("defs")
    .append('style')
    .attr('type', 'text/css');
  svg_style.text("<![CDATA[" + fs.readFileSync("./tree.css", "utf8") + "]]>");


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

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

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

  // Enter the nodes.
  var nodeEnter = node.enter().append("g")
    .attr("class", "node")
    .attr("transform", function (d) {
      return "translate(" + d.y + "," + d.x + ")";
    });

  nodeEnter.append("circle")
    .attr("r", 6)
    .style("fill", "#fff");

  nodeEnter.append("text")
    .attr("x", function (d) {
      return d.children || d._children ? -13 : 13;
    })
    .attr("dy", ".35em")
    .attr("text-anchor", function (d) {
      return d.children || d._children ? "end" : "start";
    })
    .text(function (d) {
      return d.name;
    })
    .style("fill-opacity", 1);

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

  // Enter the links
  link.enter().insert("path", "g")
    .attr("class", "link")
    .attr("d", diagonal);

  return d3.select('body').html();
};
Пример #13
0
ns._drawChart = function(el, dispatcher) {
    var nodes = this._flatten(data);
    var links = d3.layout.tree().links(nodes);
    var MinMaxNode = d3.extent(nodes, function(d) { return d.size; });
    var bubbleScale = d3.scale.linear().domain(MinMaxNode).range([20, 80]);
    var linkScale = d3.scale.linear().domain(MinMaxNode).range([80, 320]);

    // Restart the force layout.
    force
        .nodes(nodes)
        .links(links)
        .linkStrength(1)
        .friction(0.5)
        .linkDistance(function(d) { return linkScale(d.target.size); })
        .gravity(0.1)
        .charge(-1500)
        .theta(0.9)
        .alpha(0.1)
        .start();

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

    // Exit any old links.
    link.exit().remove();

    // Enter any new links.
    link.enter().insert("line", ".node")
        .attr("class", function(d) {
            return d.source.name == "flare" ? "" : "link";
        })
        .attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });

    // Update the nodes…
    node = container.selectAll(".node").data(nodes, function(d) { return d.id; });

    // Exit any old nodes.
    node.exit().remove();

    // Enter any new nodes.
    var g = node.enter().append("g")
        .attr("class", "node")
        .call(force.drag);


    g.append("circle")
        .attr("class", ns._color)
        .attr("r", function(d) {
            return bubbleScale(d.size) || 0;
        })
        .on("click", ns._click);

    g.append("text")
        .attr("text-anchor", "start")
        .attr("dx", "-1.5em")
        .attr("dy", "-.35em")
        .attr("font-size", function(d) {
            var val = Math.floor(bubbleScale(d.size) / 3);
            return val > 10 ? val : 10;
        })
        .text(function(d) {
            return d.name !== 'flare' ? d.first_name : '';
        })
        .on("click", ns._click);

    g.append("text")
        .attr("text-anchor", "start")
        .text(function(d) {
            return d.name !== 'flare' ? d.last_name : '';
        })
        .attr("dx", "-1.5em")
        .attr("dy", function(d) {
            var val = Math.floor(bubbleScale(d.size) / 4);
            return val > 10 ? val : 10;
        })
        .attr("font-size", function(d) {
            var val = Math.floor(bubbleScale(d.size) / 3);
            return val > 10 ? val : 10;
        })
        .on("click", ns._click);

};
Пример #14
0
	function initInfo (container, graphJsonUrl) {
		graphJsonUrl = graphJsonUrl || 'graph.json';

		$('.dep-table table', container).stacktable();

		/* d3 graph */

		function createNode (dep) {
			return {
				name: dep.name,
				version: dep.version,
				children: null
			};
		}

		/**
		 * Transform data from possibly cyclic structure into max 10 levels deep visual structure
		 */
		function transformData (rootDep, callback) {

			var transformsCount = 0
				, rootNode = createNode(rootDep);

			// Avoid 'too much recursion' errors
			function scheduleTransform (dep, node, level, maxLevel) {
				setTimeout(function () {
					transform(dep, node, level, maxLevel);
					transformsCount--;

					if (!transformsCount) {
						callback(rootNode);
					}
				}, 0);
			}

			function transform (dep, parentNode, level, maxLevel) {
				level = level || 0;
				maxLevel = maxLevel || 10;

				$.each(dep.deps, function(depName, depDep) {
					var node = createNode(depDep);

					if (level < maxLevel) {
						transformsCount++;
						scheduleTransform(depDep, node, level + 1, maxLevel);
					}

					if (!parentNode.children) {
						parentNode.children = [];
					}

					parentNode.children.push(node);
				});

				if (parentNode.children) {
					parentNode.children = parentNode.children.sort(function(a, b) {
						if (a.name < b.name) {
							return -1;
						} else if (a.name > b.name) {
							return 1;
						} else {
							return 0;
						}
					});
				}
			}

			transform(rootDep, rootNode);
		}

		var m = [20, 120, 20, 120]
			, w = parseInt($(window).width() - $('#main').position().left, 10) - m[1] - m[3]
			, h = 768 - m[0] - m[2]
			, i = 0
			, root = null
			, tree = d3.layout.tree().size([h, w])
			, diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x] });

		var vis = d3.select($('.dep-graph', container)[0]).append('svg:svg')
			.attr('width', w + m[1] + m[3])
			.attr('height', h + m[0] + m[2])
			.append('svg:g')
			.attr('transform', 'translate(' + m[3] + ',' + m[0] + ')');

		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 : d.id = ++i;
				});

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

			nodeEnter.append('svg:circle').attr('r', 0.000001).style('fill', function(d) {
				return d._children ? '#ccc' : '#fff';
			});

			nodeEnter.append('svg:text').attr('x', function(d) {
				return d.children || d._children ? -10 : 10;
			}).attr('dy', '.25em').attr('text-anchor', function(d) {
				return d.children || d._children ? 'end' : 'start';
			}).text(function(d) {
				return d.name + ' ' + d.version;
			}).style('fill-opacity', 0.000001);

			// 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('fill', function(d) {
				return d._children ? '#ccc' : '#fff';
			});

			nodeUpdate.select('text').style('fill-opacity', 1);
			var nodeExit = node.exit().transition().duration(duration).attr('transform', function () {
					return 'translate(' + source.y + ',' + source.x + ')';
				}).remove();

			// Transition exiting nodes to the parent's new position.
			nodeExit.select('circle').attr('r', 0.000001);

			nodeExit.select('text').style('fill-opacity', 0.000001);

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

			// Enter any new links at the parent's previous position.
			link.enter().insert('svg:path', 'g').attr('class', 'link').attr('d', function () {
				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 () {
				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;
			}
		}

		// Load the graph data and render when change view
		var graphLoaded = false
			, graphContainer = $('.dep-graph', container)
			, tableContainer = $('.dep-table', container);

		graphContainer.hide();

		function initGraph () {

			var loading = david.createLoadingEl();
			graphContainer.prepend(loading);

			d3.json(pathname + graphJsonUrl, function(er, json) {

				if (er) {
					return loading.empty().text('Error occurred retrieving graph data');
				}

				transformData(cycle.retrocycle(json), function(node) {
					root = node;
					root.x0 = h / 2;
					root.y0 = 0;

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

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

		var viewSwitchers = $('.switch a', container);

		viewSwitchers.click(function(event) {
			event.preventDefault();
			merge(state, $.deparam.fragment($(this).attr('href')));
			$.bbq.pushState(state);
		});

		function onHashChange () {
			merge(state, $.bbq.getState());

			viewSwitchers.removeClass('selected');

			if (state.view !== 'tree') {
				graphContainer.hide();
				tableContainer.fadeIn();
				viewSwitchers.first().addClass('selected');
			} else {
				tableContainer.hide();
				graphContainer.fadeIn();
				viewSwitchers.last().addClass('selected');

				if (!graphLoaded) {
					graphLoaded = true;
					initGraph();
				}
			}
		}

		/* Init changes links */

		$('.changes', container).click(function(event) {
			event.preventDefault();
			var row = $(this).closest('tr'),
				container = $('<div class="changes-popup"/>').append(david.createLoadingEl());

			var name, from, to;

			if (row.closest('table').is('.stacktable')) {
				name = $('a:first-child', row).text();
				from = $('.st-val', row.next()).text();
				to = $('.st-val', row.next().next()).text();
			} else {
				name = $('.dep a:first-child', row).text();
				from = $('.required', row).text();
				to = $('.stable', row).text();
			}

			$.fancybox.open(container);

			$.ajax({
				url: '/package/' + name + '/changes.json',
				dataType: 'json',
				data: {from: from, to: to},
				success: function(data) {
					data.from = from;
					data.to = to;

					var tpl = fs.readFileSync(__dirname + '/../../dist/inc/changes.html');
					container.html(Handlebars.compile(tpl)(data));
					$.fancybox.update();
				},
				error: function () {
					container.html(fs.readFileSync(__dirname + '/../../dist/inc/changelog-er.html'));
					$.fancybox.update();
				}
			});
		});

		$(window).bind('hashchange', onHashChange);

		onHashChange();
	}
Пример #15
0
			scope.render = function (data) {
				// clear out everything in the svg to render a fresh version
				svg.selectAll("*").remove();

				// set up variables
				var width, height, max;
				width = data[0].children.length * 60;
				height = getDepth(data[0], 1) * 100;
				svg.attr('height', height);
				svg.attr('width', width);

				// Data management
				var treeData = data;

				// ************** Generate the tree diagram	 *****************
				var margin = {top: 10, right: 10, bottom: 10, left: 10},
					width = width - margin.right - margin.left, //groups.length
					height = height - margin.top - margin.bottom;

				var i = 0,
					duration = 750,
					root;

				var tree = d3.layout.tree()
					.size([width, height]);

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

				root = treeData[0];
				root.x0 = width / 2;
				root.y0 = 0;
				update(root);


				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 * 100 + xOffset;
					});

					// 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("class", "node")
						.attr("transform", function (d) {
							return "translate(" + source.x0 + "," + source.y0 + ")";
						})
						.on("click", click);

					nodeEnter.append("circle")
						.attr("r", function (d) {
							return "20px"
						})
						.style("fill", function (d) {
							return d._children ? "lightsteelblue" : "#fff";
						});

					nodeEnter.append("text")
						.attr("y", function (d) {
							return 0;
						})
						.attr("dy", function (d) {
							return ((source.children.indexOf(d) % 2) == 0 ? -(d.score / 40000 * 20 + 15) : (d.score / 40000 * 20 + 15)) + "px"
						})//".35em")
						.attr("text-anchor", "middle")
						.text(function (d) {
							return d.name;
						})
						.style("fill-opacity", 1e-6);

					// 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", function (d) {
							return (d.score / 30000 * 20) + "px"
						})
						.style("fill", function (d) {
							return d._children ? "lightsteelblue" : "#fff";
						});

					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", "0px");

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

				}

				// 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;
					}
					update(d);
				}
			};
Пример #16
0
var showGraph = function(treeData, remove) {
  // console.log(data, remove);
  // console.log("treeData in dndTree",treeData);
  if (panTimer === undefined) {
    var panTimer = false;
  }
  var dragStarted;
  // Calculate total nodes, max label length
  var totalNodes = 0;
  var maxLabelLength = 10;
  // variables for drag/drop
  var selectedNode = null;
  var draggingNode = null;
  // panning variables
  var panSpeed = 200;
  var panBoundary = 1; // Within 20px from edges will pan when dragging.
  // Misc. variables
  var i = 0;
  var duration = 750;
  var root;
  // size of the diagram
  var viewerWidth = $(document).width() * 5 / 12;
  // var viewerHeight = 1500;
  // var viewerWidth = $('#tree-container').width() ;
  // var viewerWidth = $(document).width() ;

  var viewerHeight = $(document).height();

  var tree = d3.layout.tree().size([viewerHeight, viewerWidth]);

  // define a d3 diagonal projection for use by the node paths later on.
  var diagonal = d3.svg.diagonal().projection(function(d) {
    return [d.y, d.x];
  });

  // A recursive helper function for performing some setup by walking through all nodes

  function visit(parent, visitFn, childrenFn) {
    console.log('parent: ', parent);
    if (!parent) return;

    visitFn(parent);

    var children = childrenFn(parent);
    if (children) {
      var count = children.length;
      for (var i = 0; i < count; i++) {
        visit(children[i], visitFn, childrenFn);
      }
    }
  }

  // Call visit function to establish maxLabelLength
  visit(
    treeData,
    function(d) {
      totalNodes++;
      maxLabelLength = Math.max(d.name.length, maxLabelLength);
    },
    function(d) {
      return d.children && d.children.length > 0 ? d.children : null;
    }
  );

  // sort the tree according to the node names

  function sortTree() {
    tree.sort(function(a, b) {
      return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1;
    });
  }
  // Sort the tree initially incase the JSON isn't in a sorted order.
  sortTree();

  // TODO: Pan function, can be better implemented.

  function pan(domNode, direction) {
    var speed = panSpeed;
    var translateX = 0;
    var translateY = 0;
    if (panTimer) {
      clearTimeout(panTimer);
      var translateCoords = d3.transform(svgGroup.attr('transform'));
      if (direction == 'left' || direction == 'right') {
        translateX =
          direction == 'left'
            ? translateCoords.translate[0] + speed
            : translateCoords.translate[0] - speed;
        translateY = translateCoords.translate[1];
      } else if (direction == 'up' || direction == 'down') {
        translateX = translateCoords.translate[0];
        translateY =
          direction == 'up'
            ? translateCoords.translate[1] + speed
            : translateCoords.translate[1] - speed;
      }
      var scaleX = translateCoords.scale[0];
      var scaleY = translateCoords.scale[1];
      var scale = zoomListener.scale();
      svgGroup
        .transition()
        .attr(
          'transform',
          'translate(' + translateX + ',' + translateY + ')scale(' + scale + ')'
        );
      d3
        .select(domNode)
        .select('g.node')
        .attr('transform', 'translate(' + translateX + ',' + translateY + ')');
      zoomListener.scale(zoomListener.scale());
      zoomListener.translate([translateX, translateY]);
      panTimer = setTimeout(function() {
        pan(domNode, speed, direction);
      }, 50);
    }
  }

  // Define the zoom function for the zoomable tree

  function zoom() {
    svgGroup.attr(
      'transform',
      'translate(' + d3.event.translate + ')(' + d3.event.scale + ')'
    );
  }

  // define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
  var zoomListener = d3.behavior
    .zoom()
    .scaleExtent([0.1, 3])
    .on('zoom', zoom);

  function initiateDrag(d, domNode) {
    draggingNode = d;
    d3
      .select(domNode)
      .select('.ghostCircle')
      .attr('pointer-events', 'none');
    d3.selectAll('.ghostCircle').attr('class', 'ghostCircle show');
    d3.select(domNode).attr('class', 'node activeDrag');

    svgGroup.selectAll('g.node').sort(function(a, b) {
      // select the parent and sort the path's
      if (a.id != draggingNode.id)
        return 1; // a is not the hovered element, send "a" to the back
      else return -1; // a is the hovered element, bring "a" to the front
    });

    // remove parent link
    var parentLink = tree.links(tree.nodes(draggingNode.parent));
    svgGroup
      .selectAll('path.link')
      .filter(function(d, i) {
        if (d.target.id == draggingNode.id) {
          return true;
        }
        return false;
      })
      .remove();

    dragStarted = null;
  }

  // define the baseSvg, attaching a class for styling and the zoomListener
  var baseSvg = d3
    .select('#tree-container')
    .append('svg')
    .attr('width', viewerWidth)
    .attr('height', viewerHeight)
    .attr('class', 'overlay')
    .call(zoomListener);

  // Define the drag listeners for drag/drop behaviour of nodes.
  var dragListener = d3.behavior
    .drag()
    .on('dragstart', function(d) {
      if (d == root) {
        return;
      }
      dragStarted = true;
      var nodes = tree.nodes(d);
      d3.event.sourceEvent.stopPropagation();
      // it's important that we suppress the mouseover event on the node being dragged. Otherwise it will absorb the mouseover event and the underlying node will not detect it d3.select(this).attr('pointer-events', 'none');
    })
    .on('drag', function(d) {
      if (d == root) {
        return;
      }
      if (dragStarted) {
        var domNode = this;
        initiateDrag(d, domNode);
      }

      // get coords of mouseEvent relative to svg container to allow for panning
      var relCoords = d3.mouse($('svg').get(0));
      if (relCoords[0] < panBoundary) {
        panTimer = true;
        pan(this, 'left');
      } else if (relCoords[0] > $('svg').width() - panBoundary) {
        panTimer = true;
        pan(this, 'right');
      } else if (relCoords[1] < panBoundary) {
        panTimer = true;
        pan(this, 'up');
      } else if (relCoords[1] > $('svg').height() - panBoundary) {
        panTimer = true;
        pan(this, 'down');
      } else {
        try {
          clearTimeout(panTimer);
        } catch (e) {}
      }

      d.x0 += d3.event.dy;
      d.y0 += d3.event.dx;
      var node = d3.select(this);
      node.attr('transform', 'translate(' + d.y0 + ',' + d.x0 + ')');
      updateTempConnector();
    })
    .on('dragend', function(d) {
      if (d == root) {
        return;
      }
      var domNode = this;
      var index = draggingNode.parent.children.indexOf(draggingNode);
      if (index > -1) {
        draggingNode.parent.children.splice(index, 1);
      }

      remove(draggingNode.id);

      if (selectedNode) {
        // now remove the element from the parent, and insert it into the new elements children
        var index = draggingNode.parent.children.indexOf(draggingNode);
        if (index > -1) {
          draggingNode.parent.children.splice(index, 1);
        }
        expand(selectedNode);
        sortTree();
        remove(draggingNode.id);

        endDrag();
      } else {
        endDrag();
      }
    });

  function endDrag() {
    var domNode = this;
    selectedNode = null;
    d3.selectAll('.ghostCircle').attr('class', 'ghostCircle');
    d3.select(domNode).attr('class', 'node');
    // now restore the mouseover event or we won't be able to drag a 2nd time
    d3
      .select(domNode)
      .select('.ghostCircle')
      .attr('pointer-events', '');
    updateTempConnector();
    if (draggingNode !== null) {
      update(root);
      draggingNode;
      draggingNode = null;
    }
  }

  // Helper functions for collapsing and expanding nodes.

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

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

  // Function to update the temporary connector indicating dragging affiliation
  var updateTempConnector = function() {
    var data = [];
    if (draggingNode !== null && selectedNode !== null) {
      // have to flip the source coordinates since we did this for the existing connectors on the original tree
      data = [
        {
          source: {
            x: selectedNode.y0,
            y: selectedNode.x0
          },
          target: {
            x: draggingNode.y0,
            y: draggingNode.x0
          }
        }
      ];
    }
    var link = svgGroup.selectAll('.templink').data(data);

    link
      .enter()
      .append('path')
      .attr('class', 'templink')
      .attr('d', d3.svg.diagonal())
      .attr('pointer-events', 'none');

    link.attr('d', d3.svg.diagonal());

    link.exit().remove();
  };

  // Function to center node when clicked/dropped so node doesn't get lost when collapsing/moving with large amount of children.

  function centerNode(source) {
    var scale = zoomListener.scale();
    // var x = -source.y0;
    // var y = -source.x0;
    var x = x * scale + viewerWidth / 2;
    var y = y * scale + viewerHeight / 2;
    d3
      .select('g')
      .transition()
      .duration(duration)
      .attr('transform', 'translate(' + x + ',' + y + ')scale(' + scale + ')');
    zoomListener.scale(scale);
    zoomListener.translate([x, y]);
  }

  // Toggle children function

  function toggleChildren(d) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else if (d._children) {
      d.children = d._children;
      d._children = null;
    }
    return d;
  }

  // Toggle children on click.

  function click(d) {
    if (d3.event.defaultPrevented) return; // click suppressed
    d = toggleChildren(d);
    update(d);
    centerNode(d);
  }

  function update(source) {
    // Compute the new height, function counts total children of root node and sets tree height accordingly.
    // This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed
    // This makes the layout more consistent.
    var levelWidth = [1];
    var childCount = function(level, n) {
      if (n.children && n.children.length > 0) {
        if (levelWidth.length <= level + 1) levelWidth.push(0);

        levelWidth[level + 1] += n.children.length;
        n.children.forEach(function(d) {
          childCount(level + 1, d);
        });
      }
    };
    childCount(0, root);
    var newHeight = d3.max(levelWidth) * 15; // 25 pixels per line
    tree = tree.size([newHeight, viewerWidth]);

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

    // Set widths between levels based on maxLabelLength.
    nodes.forEach(function(d) {
      d.y = d.depth * (viewerWidth / 3); //maxLabelLength * 10px
      // alternatively to keep a fixed scale one can set a fixed depth per level
      // Normalize for fixed-depth by commenting out below line
      // d.y = (d.depth * 100); //500px per level.
    });

    // Update the nodes…
    var node = svgGroup.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')
      .call(dragListener)
      .attr('class', 'node')
      .attr('transform', function(d) {
        return 'translate(' + source.y0 + ',' + source.x0 + ')';
      })
      .on('click', click);

    nodeEnter
      .append('circle')
      .attr('class', 'nodeCircle')
      .attr('r', 0)
      .style('fill', function(d) {
        return d._children ? 'lightsteelblue' : '#fff';
      });

    nodeEnter
      .append('text')
      .attr('x', function(d) {
        return d.children || d._children ? -10 : 10;
      })
      .attr('dy', '.35em')
      .attr('class', 'nodeText')
      .attr('text-anchor', function(d) {
        return d.children || d._children ? 'end' : 'start';
      })
      .text(function(d) {
        return d.name;
      })
      .style('fill-opacity', 0);

    // Update the text to reflect whether node has children or not.
    node
      .select('text')
      .attr('x', function(d) {
        return d.children || d._children ? -10 : 10;
      })
      .attr('text-anchor', function(d) {
        return d.children || d._children ? 'end' : 'start';
      })
      .text(function(d) {
        return d.name;
      });

    // Change the circle fill depending on whether it has children and is collapsed
    node
      .select('circle.nodeCircle')
      .attr('r', 4.5)
      .style('fill', function(d) {
        return d._children ? 'lightsteelblue' : '#fff';
      });

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

    // Fade the text in
    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.y + ',' + source.x + ')';
      })
      .remove();

    nodeExit.select('circle').attr('r', 0);

    nodeExit.select('text').style('fill-opacity', 0);

    // Update the links…
    var link = svgGroup.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;
    });
  }

  // Append a group which holds all nodes and which the zoom Listener can act upon.
  var svgGroup = baseSvg.append('g');
  // Define the root
  root = treeData;
  root.x0 = viewerHeight / 2;
  root.y0 = 0;

  // Layout the tree initially and center on the root node.
  update(root);
  centerNode(root);
};
Пример #17
0
function jsonldVis (jsonld, selector, config = {}) {
  if (!jsonld && !selector) return jsonldVis;

  let h = config.h || 600
    , w = config.w || 800
    , maxLabelWidth = config.maxLabelWidth || 250
    , transitionDuration = config.transitionDuration || 750
    , transitionEase = config.transitionEase || 'cubic-in-out'
    , minRadius = config.minRadius || 5
    , scalingFactor = config.scalingFactor || 2
    , i = 0
    , tree = d3.layout.tree().size([h, w])
    , diagonal = d3.svg.diagonal().projection(d => [d.y, d.x])
    , svg = d3.select(selector).append('svg')
              .attr('width', w)
              .attr('height', h)
              .append('g')
              .attr('transform', 'translate(' + maxLabelWidth + ',0)')
    , tip = d3.tip()
              .direction(d => (d.children || d._children ? 'w' : 'e'))
              .offset(d => (d.children || d._children ? [0, -3] : [0, 3]))
              .attr('class', 'd3-tip')
              .html(d => '<span>' + d.valueExtended + '</span>')
  ;
  svg.call(tip);

  let root = jsonldTree(jsonld);
  root.x0 = h / 2;
  root.y0 = 0;
  root.children.forEach(collapse);

  function changeSVGWidth (newWidth) {
    if (w !== newWidth) d3.select(selector + ' > svg').attr('width', newWidth);
  }

  function jsonldTree (source) {
    let tree = {};
    if ('@id' in source) {
      tree.isIdNode = true;
      tree.name = source['@id'];
      if (tree.name.length > maxLabelWidth / 9) {
        tree.valueExtended = tree.name;
        tree.name = '…' + tree.valueExtended.slice(-Math.floor(maxLabelWidth / 9));
      }
    }
    else {
      tree.isIdNode = true;
      tree.isBlankNode = true;
      // random id, can replace with actual uuid generator if needed
      tree.name = '_:b' + Math.random().toString(10).slice(-7);
    }

    let children = [];
    Object.keys(source).forEach(key => {
      if (key === '@id' || key === '@context' || source[key] === null) return;
      let valueExtended
        , value
      ;
      if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
        children.push({
          name: key,
          children: [jsonldTree(source[key])]
        });
      }
      else if (Array.isArray(source[key])) {
        children.push({
          name: key,
          children: source[key].map(item => {
            if (typeof item === 'object') return jsonldTree(item);
            return { name: item };
          })
        });
      }
      else {
        valueExtended = source[key];
        value = valueExtended;
        if (value.length > maxLabelWidth / 9) {
          value = value.slice(0, Math.floor(maxLabelWidth / 9)) + '…';
          children.push({
            name: key,
            value,
            valueExtended,
          });
        }
        else {
          children.push({
            name: key,
            value,
          });
        }
      }
    });

    if (children.length) tree.children = children;
    return tree;
  }

  function update (source) {
    let nodes = tree.nodes(root).reverse()
      , links = tree.links(nodes)
    ;
    nodes.forEach(d => (d.y = d.depth * maxLabelWidth));
    let node = svg.selectAll('g.node')
                  .data(nodes, d => (d.id || (d.id = ++i)))
      , nodeEnter = node.enter()
                        .append('g')
                        .attr('class', 'node')
                        .attr('transform', () => `translate(${source.y0},${source.x0})`)
                        .on('click', click)
    ;
    nodeEnter.append('circle')
              .attr('r', 0)
              .style('stroke-width', d => (d.isIdNode ? '2px' : '1px'))
              .style('stroke', d => (d.isIdNode ? '#F7CA18' : '#4ECDC4'))
              .style('fill', d => {
                if (d.isIdNode) return d._children ? '#F5D76E' : 'white';
                return d._children ? '#86E2D5' : 'white';
              })
              .on('mouseover', d => { if (d.valueExtended) tip.show(d); })
              .on('mouseout', tip.hide)
    ;
    nodeEnter.append('text')
              .attr('x', d => {
                let spacing = computeRadius(d) + 5;
                return d.children || d._children ? -spacing : spacing;
              })
              .attr('dy', '4')
              .attr('text-anchor', d => (d.children || d._children ? 'end' : 'start'))
              .text(d => (d.name + (d.value ? ': ' + d.value : '')))
              .style('fill-opacity', 0)
              .on('mouseover', d => { if (d.valueExtended) tip.show(d); })
              .on('mouseout', tip.hide)
    ;
    let maxSpan = Math.max.apply(Math, nodes.map(d => d.y + maxLabelWidth));
    if (maxSpan + maxLabelWidth + 20 > w) {
      changeSVGWidth(maxSpan + maxLabelWidth);
      d3.select(selector).node().scrollLeft = source.y0;
    }

    let nodeUpdate = node.transition()
                          .duration(transitionDuration)
                          .ease(transitionEase)
                          .attr('transform', d => `translate(${d.y},${d.x})`)
    ;
    nodeUpdate.select('circle')
              .attr('r', d => computeRadius(d))
              .style('stroke-width', d => (d.isIdNode ? '2px' : '1px'))
              .style('stroke', d => (d.isIdNode ? '#F7CA18' : '#4ECDC4'))
              .style('fill', d => {
                if (d.isIdNode) return d._children ? '#F5D76E' : 'white';
                return d._children ? '#86E2D5' : 'white';
              })
    ;
    nodeUpdate.select('text').style('fill-opacity', 1);

    let nodeExit = node.exit().transition()
                      .duration(transitionDuration)
                      .ease(transitionEase)
                      .attr('transform', () => `translate(${source.y},${source.x})`)
                      .remove()
    ;
    nodeExit.select('circle').attr('r', 0);
    nodeExit.select('text').style('fill-opacity', 0);

    let link = svg.selectAll('path.link').data(links, d => d.target.id);
    link.enter().insert('path', 'g')
        .attr('class', 'link')
        .attr('d', () => {
          let o = { x: source.x0, y: source.y0 };
          return diagonal({ source: o, target: o });
        })
    ;
    link.transition()
        .duration(transitionDuration)
        .ease(transitionEase)
        .attr('d', diagonal);
    link.exit().transition()
        .duration(transitionDuration)
        .ease(transitionEase)
        .attr('d', () => {
          let o = { x: source.x, y: source.y };
          return diagonal({ source: o, target: o });
        })
        .remove()
    ;

    nodes.forEach(d => {
      d.x0 = d.x;
      d.y0 = d.y;
    });
  }

  function computeRadius (d) {
    if (d.children || d._children) return minRadius + (numEndNodes(d) / scalingFactor);
    return minRadius;
  }

  function numEndNodes (n) {
    let num = 0;
    if (n.children) n.children.forEach(c => (num += numEndNodes(c)));
    else if (n._children) n._children.forEach(c => (num += numEndNodes(c)));
    else num++;
    return num;
  }

  function click (d) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    }
    else {
      d.children = d._children;
      d._children = null;
    }
    update(d);

    // fast-forward blank nodes
    if (d.children) {
      d.children.forEach(child => {
        if (child.isBlankNode && child._children) click(child);
      });
    }
  }

  function collapse (d) {
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
  }
  update(root);
}
Пример #18
0
function update(source, domelem) {
    var w = 960,
        h = 800,
        i = 0,
        barHeight = 20,
        barWidth = w * .8,
        duration = 400,
        root;

    root = {
        name: 'return',
        children: d3.nest().entries(fmt(source)),
        x0: 0,
        y0: 0,
    };

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

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

    var vis = d3.select(domelem).append("svg:svg")
        .attr("width", w)
        .attr("height", h)
        .append("svg:g")
        .attr("transform", "translate(20,30)");

  // Compute the flattened node list. TODO use d3.layout.hierarchy.
  var nodes = tree.nodes(root);

  // Compute the "layout".
  nodes.forEach(function(n, i) {
    n.x = i * barHeight;
  });

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

  var nodeEnter = node.enter().append("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
      .style("opacity", 1e-6);

  // Enter any new nodes at the parent's previous position.
  nodeEnter.append("svg:rect")
      .attr("y", -barHeight / 2)
      .attr("height", barHeight)
      .attr("width", barWidth)
      .style("fill", color)
      .on("click", click);

  nodeEnter.append("svg:text")
      .attr("dy", 3.5)
      .attr("dx", 5.5)
      .text(function(d) {
          if (d.val) {
              return d.name + ": " + d.val;
          }
          return d.name;
      });

  // Transition nodes to their new position.
  nodeEnter.transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
      .style("opacity", 1);

  node.transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
      .style("opacity", 1)
    .select("rect")
      .style("fill", color);

  // Transition exiting nodes to the parent's new position.
  node.exit().transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
      .style("opacity", 1e-6)
      .remove();

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

  // Enter any new links at the 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;
  });
}
Пример #19
0
    function draw(drawObject)
    {
        var bracket = drawObject.bracket;
        var drawprofile = drawObject.drawprofile;

        if (drawObject.mode == 'SE') {
            size.width = drawprofile.ceil_root * (template.matchW + template.gapW);
            size.height = drawprofile.ceil * (template.matchH);
        } else {
            size.width = drawprofile.loseBracket.roundArray.length * (template.matchW + template.gapW);
            size.height = drawprofile.ceil * (template.matchH);
        }

        var tree = d3.layout.tree()
            .sort(null)
            .size([size.height, size.width])
            .children(function (d)
            {
                return (!d.child || d.child.length === 0) ? null : d.child;
            });


        var nodes = tree.nodes(bracket);
        var links = tree.links(nodes);

        var layoutRoot = d3.select('body').append('div')
            .attr('id', 'bracket_container')
            .append('svg')
                .attr('id', 'svg_container')
                .attr('width', 900 + margin.left + margin.right)
                .attr('height', 900 + margin.bottom + margin.top)
                .style("background-color","#EEEEEE")
                .style('overflow', 'scroll')
                .append('svg:g')
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
                    .attr('class', 'drawarea');

        var link = d3.svg.diagonal()
            .source(function(d)
            {
                return {x: (size.width - template.matchW) - d.source.y, y: d.source.x};
            })
            .target(function(d)
            {
                return {x: size.width - d.target.y, y: d.target.x};
            });

        var elbow = function(d, i) {
            return "M" + ((size.width - template.matchW) - d.source.y - 20) + "," + d.source.x
                + "V" + d.target.x + "H" + (size.width - d.target.y);
        }


        layoutRoot.selectAll('path.link')
            .data(links)
            .enter()
            .append('svg:path')
            .attr('class', 'link')
            .attr('d', elbow);

        var matchGroup = layoutRoot.selectAll('g.match')
            .data(nodes)
            .enter()
            .append('svg:g')
            .attr('id', function(d)
            {
                return 'r' + d.round + 'm' +  d.match;
            })
            .attr('class', 'match')
            .attr('transform', function(d)
            {
                return 'translate(' + ((size.width - template.matchW) - d.y) + ',' + (d.x-template.matchH/2+4)+ ')';
            });

        matchGroup.append('svg:polygon')
            .attr('class', 'player1')
            .attr('points', '0,0 210,0 220,25 10,25')
            .attr('style', 'fill: dimgrey; fill-opacity: 0.7');

        matchGroup.append('svg:text')
            .attr('id', function(d){
                return 'r' + d.round + 'm' + d.match + 'p1name';
            })
            .attr('class', 'p1name')
            .attr('text-anchor', 'start')
            .attr('x', 10)
            .attr('y', 16.5)
            .text('Player 1 Name');

        matchGroup.append('svg:polygon')
            .attr('class', 'score1')
            .attr('points', '180,0 210,0 220,25 190,25')
            .attr('style', 'fill: orange; fill-opacity: 0.7');

        matchGroup.append('svg:text')
            .attr('id', function(d){
                return 'r' + d.round + 'm' + d.match + 'p1score';
            })
            .attr('class', 'p1score')
            .attr('text-anchor', 'start')
            .attr('x', 195)
            .attr('y', 16.5)
            .text('X');

        matchGroup.append('svg:polygon')
            .attr('class', 'player2')
            .attr('points', '10,27 220,27 210,52 0,52')
            .attr('style', 'fill: dimgrey; fill-opacity: 0.7');

        matchGroup.append('svg:text')
            .attr('id', function(d){
                return 'r' + d.round + 'm' + d.match + 'p2name';
            })
            .attr('class', 'p2name')
            .attr('text-anchor', 'start')
            .attr('x', 10)
            .attr('y', 42.5)
            .text('Player 2 Name');

        matchGroup.append('svg:polygon')
            .attr('class', 'score2')
            .attr('points', '190,27 220,27 210,52 180,52')
            .attr('style', 'fill: orange; fill-opacity: 0.7');

        matchGroup.append('svg:text')
            .attr('id', function(d){
                return 'r' + d.round + 'm' + d.match + 'p2score';
            })
            .attr('class', 'p2score')
            .attr('text-anchor', 'start')
            .attr('x', 195)
            .attr('y', 42.5)
            .text('X');

        matchGroup.append('svg:text')
            .attr('id', 'status')
            .attr('text-anchor', 'start')
            .attr('x', 0)
            .attr('y', 62)
            .text('');

        var string = d3.select('#bracket_container').node().outerHTML;
        return string;
    }
Пример #20
0
export default function(DOMNode, options = {}) {
  const {
    id,
    style,
    size,
    aspectRatio,
    initialZoom,
    margin,
    isSorted,
    widthBetweenNodesCoeff,
    heightBetweenNodesCoeff,
    transitionDuration,
    state,
    rootKeyName,
    pushMethod,
    tree,
    tooltipOptions,
    onClickText
    } = deepmerge(defaultOptions, options)

  const width = size - margin.left - margin.right
  const height = size * aspectRatio - margin.top - margin.bottom
  const fullWidth = size
  const fullHeight = size * aspectRatio

  const attr = {
    id,
    preserveAspectRatio: 'xMinYMin slice'
  }

  if (!style.width) {
    attr.width = fullWidth
  }

  if (!style.width || !style.height) {
    attr.viewBox = `0 0 ${fullWidth} ${fullHeight}`
  }

  const root = d3.select(DOMNode)
  const zoom = d3.behavior.zoom()
    .scaleExtent([0.1, 3])
    .scale(initialZoom)
  const vis = root
    .append('svg')
    .attr(attr)
    .style({cursor: '-webkit-grab', ...style})
    .call(zoom.on('zoom', () => {
      const { translate, scale } = d3.event
      vis.attr('transform', `translate(${translate})scale(${scale})`)
    }))
    .append('g')
    .attr({
      transform: `translate(${margin.left + style.node.radius}, ${margin.top}) scale(${initialZoom})`
    })

  let layout = d3.layout.tree().size([width, height])
  let data

  if (isSorted) {
    layout.sort((a, b) => b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1)
  }

  return function renderChart(nextState = tree || state) {
    data = !tree ? map2tree(nextState, {key: rootKeyName, pushMethod}) : nextState

    if (isEmpty(data) || !data.name) {
      data = { name: 'error', message: 'Please provide a state map or a tree structure'}
    }

    let nodeIndex = 0
    let maxLabelLength = 0

    visit(data,
        node => maxLabelLength = Math.max(node.name.length, maxLabelLength),
        node => node.children && node.children.length > 0 ? node.children : null
    )

    data.x0 = height / 2
    data.y0 = 0
    /*eslint-disable*/
    update(data)
    /*eslint-enable*/

    function update(source) {
      // path generator for links
      const diagonal = d3.svg.diagonal().projection(d => [d.y, d.x])
      // set tree dimensions and spacing between branches and nodes
      const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data))

      layout = layout.size([maxNodeCountByLevel * 25 * heightBetweenNodesCoeff, width])

      let nodes = layout.nodes(data)
      let links = layout.links(nodes)

      nodes.forEach(node => node.y = node.depth * (maxLabelLength * 7 * widthBetweenNodesCoeff))

      // process the node selection
      let node = vis.selectAll('g.node').data(nodes, d => d.id || (d.id = ++nodeIndex))

      let nodeEnter = node.enter().append('g')
        .attr({
          'class': 'node',
          transform: d => `translate(${source.y0},${source.x0})`
        })
        .style({
          fill: style.text.colors.default,
          cursor: 'pointer'
        })
        .on({
          mouseover: function mouseover(d, i) {
            d3.select(this).style({
              fill: style.text.colors.hover
            })
          },
          mouseout: function mouseout(d, i) {
            d3.select(this).style({
              fill: style.text.colors.default
            })
          }
        })

      if (!tooltipOptions.disabled) {
        nodeEnter.call(d3tooltip(d3, 'tooltip', {...tooltipOptions, root})
          .text((d, i) => getTooltipString(d, i, tooltipOptions))
          .style(tooltipOptions.style)
        )
      }

      nodeEnter.append('circle')
        .attr({
          'class': 'nodeCircle'
        })
        .on({
          click: clickedNode => {
            if (d3.event.defaultPrevented) return
            update(toggleChildren(clickedNode))
          }
        })

      nodeEnter.append('text')
        .attr({
          'class': 'nodeText',
          dy: '.35em'
        })
        .style({
          'fill-opacity': 0
        })
        .text(d => d.name)
        .on({
          click: onClickText
        })

      // update the text to reflect whether node has children or not
      node.select('text')
        .attr({
          x: d => d.children || d._children ? -(style.node.radius + 10) : style.node.radius + 10,
          'text-anchor': d => d.children || d._children ? 'end' : 'start'
        })
        .text(d => d.name)

      // change the circle fill depending on whether it has children and is collapsed
      node.select('circle.nodeCircle')
        .attr({
          r: style.node.radius
        })
        .style({
          stroke: 'black',
          'stroke-width': '1.5px',
          fill: d => d._children ? style.node.colors.collapsed : (d.children ? style.node.colors.parent : style.node.colors.default)
        })

      // transition nodes to their new position
      let nodeUpdate = node.transition()
        .duration(transitionDuration)
        .attr({
          transform: d => `translate(${d.y},${d.x})`
        })

      // fade the text in
      nodeUpdate.select('text')
        .style('fill-opacity', 1)

      // transition exiting nodes to the parent's new position
      let nodeExit = node.exit().transition()
        .duration(transitionDuration)
        .attr({
          transform: d => `translate(${source.y},${source.x})`
        })
        .remove()

      nodeExit.select('circle')
        .attr('r', 0)

      nodeExit.select('text')
        .style('fill-opacity', 0)

      // update the links
      let link = vis.selectAll('path.link')
        .data(links, d => d.target.id)

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

      // transition links to their new position
      link.transition()
        .duration(transitionDuration)
        .attr({
          d: diagonal
        })

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

      // stash the old positions for transition
      nodes.forEach(d => {
        d.x0 = d.x
        d.y0 = d.y
      })
    }
  }
}
Пример #21
0
  setup () {
    // Destroy, if it exists.
    this.destroy()

    // Get data set in `render`.
    const data = this.data

    // Exit, if no data.
    if (!data || !Object.keys(data).length) {
      return
    }

    const setPan = this.setPan.bind(this)

    const width = this.el.offsetWidth
    const config = this.config

    const rectW = config.rectW
    const rectH = config.rectH

    const offset = (width / 2) - (rectW / 2)

    this.tree = d3.layout.tree()

    this.tree.separation(function (d) {
      var n = 1

      if (d.type === 'account') {
        n = 0
      }

      if (d.type === 'taxEntity') {
        n = 1.15
      }

      return n
    })

    // Set default node size.
    this.tree.nodeSize([
      rectW + 20,
      rectH + 20
    ])

    this.root = d3
      .select(this.el)
      .append('svg')
      .call(
        d3
          .behavior
          .zoom()
          .translate([offset, 20])
          .scaleExtent([0.25, 2])
          .on('zoom', setPan)
      )

    // Add images to the `<defs>`.
    this.buildIcons()

    // Add the parent group.
    this.svg = this.root
      .append('g')
      .attr('transform', 'translate(' + offset + ',' + 20 + ')')

    // Update UI.
    this.update(data)
  }
Пример #22
0
export function drawTree(selectString, treeData, maxDepth, maxWidth) {
  let margin = {top: 20, right: 120, bottom: 20, left: 120};
  let width = maxWidth * 400 - margin.right - margin.left;
  let height = maxDepth * 50 - margin.top - margin.bottom;

  let i = 0;
  let duration = 750;
  let root;

  let tree = d3.layout.tree()
    .size([height, width])
    .children(d =>{ return d.children; });

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

  let svg = d3.select('body').append('svg')
    .attr('width', width + margin.right + margin.left)
    .attr('height', height + margin.top + margin.bottom)
  .append('g')
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');


  root = treeData[0];
  root.x0 = height / 2;
  root.y0 = 0;

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

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

  d3.select(self.frameElement).style('height', '800px');

  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 * 240; });

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

    // Enter any new nodes at the parent's previous position.
    var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
      .on("click", click);

    nodeEnter.append("circle")
      .attr("r", 1e-6)
      .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

    function wordwrap2(text) {
      return text.split(" ")
    }

    nodeEnter.append("text")
      .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
      .attr("dy", ".35em")
      //.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
      .style("fill-opacity", 1e-6)
      .each(function (d) {
        //var lines = wordwrap2(d.name)
        var lines = [];
        var index = 0;
        if (d.value) {
          lines[index] = d.value;
          index += 1;
        }
        if (d.name) {
          lines[index] = d.name;
          index += 1;
        }
        if (d.extra) {
          lines[index] = d.extra;
          index += 1;
        }
        if (d.type) {
          lines[index] = d.type;
          index += 1;
        }
        if (!index) {
          lines[index] = "UnknownNode";
        }
        for (var i = 0; i < lines.length; i++) {
          if (i == 0) { // if that's the first line - make it bold
            /*if (d.value != "" && d.value != undefined) {
             d3.select(this).append("tspan")
             .attr("style", "font-weight: bold")
             .attr("dy",23)
             .attr("x",function(d) {
             return d.children || d._children ? -10 : 10; })
             .text(lines[i] + " \"" + d.value + "\"")
             }/ else {*/
            d3.select(this).append("tspan")
              .attr("style", "font-weight: bold")
              .attr("dy",23)
              .attr("x",function(d) {
                return d.children || d._children ? -10 : 10; })
              .text(lines[i])
            //}
          } else { // otherwise small font
            d3.select(this).append("tspan")
              .attr("style", "font: 8px sans-serif;")
              .attr("dy",13)
              .attr("x",function(d) {
                return d.children || d._children ? -10 : 10; })
              .text(lines[i])
          }
        }
      });

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

  nodeUpdate.select('circle')
    .attr('r', 4.5)
    .style('fill', d => { return d._children ? 'lightsteelblue' : '#fff'; });

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

  // Transition exiting nodes to the parent's new position.
  let nodeExit = node.exit().transition()
    .duration(duration)
    .attr('transform', 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…
  let link = svg.selectAll('path.link')
    .data(links, d => { return d.target.ids; });

  // Enter any new links at the parent's previous position.
  link.enter().insert('path', 'g')
    .attr('class', 'link')
    .attr('d', d => {
      let 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', d => {
      let o = {x: source.x, y: source.y};
      return diagonal({source: o, target: o});
    })
    .remove();

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

  // 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;
    }
    update(d);
  }
}
Пример #23
0
  drawChart(treeData) {
    d3.selectAll("#svg > *").remove();
    console.log("dddd", treeData);

    // ************** Generate the tree diagram	 *****************
    var margin = {top: 20, right: 120, bottom: 20, left: 120},
      width = 960 - margin.right - margin.left,
      height = 500 - margin.top - margin.bottom;

    var i = 0,
      duration = 750,
      root;

    var tree = d3.layout.tree()
      .size([height, width]);

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

    var svg = d3.select("#svg").append("svg")
      .attr("width", width + margin.right + margin.left)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    root = treeData[0];
    root.x0 = height / 2;
    root.y0 = 0;

    update(root);

    d3.select(window.self.frameElement).style("height", "500px");

    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 * 180; });

      // 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("class", "node")
        .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; });


      nodeEnter.append("circle")
        .attr("r", 1e-6)
        .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
        .on("click", click)
        .on("dblclick",dnclickOnText);

      nodeEnter.append("text")
        .attr("x", function(d) { return d.children || d._children ? -13 : 13; })
        .attr("dy", ".35em")
        .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
        .text(function(d) { return d.name; })
        .style("fill-opacity", 1e-6)
        .on("click", clickOnText);

      // 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", 10)
        .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

      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.y + "," + source.x + ")"; })
        .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;
      });
    }

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

    function dnclickOnText(d) {
      window.location = '/schema/'+d.id + "/_addNew";
    }

    // Edit on click.
    function clickOnText(d) {
      window.location = '/schema/'+d.id;
    }
  }
Пример #24
0
import Store from './Store';
import AppDispatcher from '../dispatcher/AppDispatcher';
import {ActionTypes} from '../constants/AppConstants';
import CategoryStore from './CategoryStore';
import d3 from 'd3';

let root;
let width = 1000, height = 500;
let nodes;
let paths;
let urls = [];
let selected = {};
let tree = d3.layout.tree().size([height, width]);	
let diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });
let total;


function _cleartree(){
	root = {};
	selected = {};
	total = 0;
	urls = [];
	paths = [];
	nodes = [];
}

function toggle(d){
	if (d.children) {
    	d._children = d.children;
    	d.children = null;
  	} else {
Пример #25
0
        var SvgTree = function (options) {

            options = Arguments.get(
                options,
                {
                    // the dom container for the tree
                    container: ".svg-tree",
                    width: 500,
                    height: 500,

                    // the data tree (js-utils-lib/Tree)
                    tree: null,

                    node: {

                        radius: 20,

                        /**
                         * Get the node text
                         * 
                         * @param  {Object} node
                         * @return {String}
                         */
                        text: function(node){
                            return node.name;
                        },

                        /**
                         * Gets the CssClass of the node
                         * 
                         * @param  {Object} node
                         * @return {String}
                         */
                        cssClass: function(node){
                            return "node-dot";
                        }

                    }
                    
                });

            // initialize this instance as an EventEmitter
            OOP.super(this, EventEmitter);

            // variable to handle the returned revealing module pattern
            var _this = null;

            // private module variables
            var scope = this,
                draggingOver = null,
                draggingOverResetTimeout = null;


            /// create the tree
            var d3Zoom = d3.behavior.zoom(),
                tree = d3.layout.tree()
                .size([options.height, options.width])
                // the children accessor
                .children(function (d) {
                    return d.children;
                });
            
            /// create the svg container
            var svg = d3.select(options.container)
                .append("svg:svg")
                .attr("width", "100%")
                .append("svg:g")
                .attr("class", "svg-tree");

            // FF / IE compatible
            // explicitly set the dimentions of the svg tag
            new Element($("> svg", options.container)).fill($(options.container));
            
            var diagonal = d3.svg.diagonal().projection(function (d) { return [d.y, d.x]; });


            /**
             *
             * Gets the element
             * 
             * @param  {Number} id
             * @return {HtmlElement}
             */
            var getElement = function(id) {
                return $("[data-id=" + id + "]", options.container);
            };

            /*
             * Toogle's a node children visibility
             *
             * @return {}
             */
            var toogleChildrens = function(d) {
                
                // always use _children to store
                if (!d._children) {
                    d._children = d.children;
                }
                
                if (d.children) {
                    d.children = null;
                } else {
                    d.children = d._children;
                }

            };

            /**
             * Apply zoom in the container. 
             *
             * @param {Array} translate The translation array
             * @param {Number} translate The zoom value
             */
            var zoom = function(translate, scale) {

                d3.event = d3.event || {};

                scale = scale || d3.event.scale || 1;
                translate = translate || d3.event.translate;

                d3.select(".svg-tree")
                    .attr("transform", "translate(" + translate + ")" + " scale(" + scale + ")");

                render();
                
            };
            
            /**
             * Chage the zooming of the view 
             *
             * @param {Array} translate The translation array
             * @param {Number} translate The zoom value
             */
            function changeZoom(translate, scale) {
                var self = this;
                return d3.transition()
                         .tween("zoom", function () {
                    
                            var iTranslate = d3.interpolate(d3Zoom.translate(), translate),
                                iScale = d3.interpolate(d3Zoom.scale(), scale);

                            return function (t) {
                                
                                if(scale){
                                    d3Zoom.scale(iScale(t));
                                }
                                
                                d3Zoom.translate(iTranslate(t));
                                
                                zoom(translate, scale);

                            };

                        });
            }


            /*
             * Renders the entire tree
             *
             * @param {Object?} source The base element of the animation
             * 
             */
            var render = function(source) {

                // update screen dimension (always on the same rate as the node count!)
                var levels = options.tree.squareSize();
                tree.size([levels.height * 100, levels.width * 200]);

                // Compute the new tree layout.
                // This creates a .parent key on each object linking to the parent
                var nodes = tree.nodes(options.tree.get()),
                    links = tree.links(nodes);

                // Update the nodes and set their id's
                var treeNodes = svg.selectAll("g.node")
                                    .data(nodes, function (d) {
                                        return d.id;
                                    });
                
                var treeLinks = svg.selectAll("path.link")
                                    .data(links, function(d) {
                                        $(this).attr({ "data-source-id": d.source.id, "data-target-id": d.target.id });
                                        return d.target.id;
                                    });
                
                // create links between nodes
                var link = d3.svg.diagonal()
                    .projection(function (d) {
                        return [d.y, d.x];
                    });

                treeLinks
                    .enter()
                    .append("svg:path")
                    .attr("class", "link")
                    .attr("d", link);

                // transitions that are no longer needed are removed
                treeNodes.exit().remove();

                // Bind the nodes with their data
                var svgNodes = treeNodes
                    .enter()
                    .append("svg:g")
                    .attr("class", "node");
                
                svgNodes.append("svg:circle")
                    .attr("class", function (d) { return options.node.cssClass(d); })
                    .attr("r", options.node.radius)
                    .attr("fill", "red")
                    .on("click", function (d) {

                        d3.event.preventDefault();
                        d3.event.stopPropagation();
                        
                        _this.emitEvent("selected", [d]);

                    })
                    .on("mouseover", function (d) {
                        d3.select(this).style({ opacity: '0.8' });
                    })
                    .on("mouseout", function (d) {
                        d3.select(this).style({ opacity: '1' });
                    });
                
                // create text on the nodes
                svgNodes.append("svg:text")
                    .attr("text-anchor", function (d) {
                        return d.children ? "end" : "start";
                    })
                    .attr("dx", function (d) {
                        var gap =options.node.radius + 5;
                        return d.children ? -gap : gap;
                    })
                    .attr("dy", function (d) {
                        var gap = 5;
                        return d.children ? gap : 5;
                    })
                    .text(function (d) {
                        return options.node.text(d);
                    });
                
                // links that are no longer needed are removed
                treeLinks.exit().remove();
                
                // when a transition occours put the node's on the right position
                treeNodes
                  //.transition()
                  //.duration(500)
                  .attr("transform", function (d) { return "translate(" + d.y + "," + d.x + ")"; });

                // when a transition occours put the link's on the right position
                treeLinks
                  //.transition()
                  //.duration(500)
                  .attr("d", diagonal);
                
                // Workaround: draging tracking ( on SVG the drop event does not work )
                svgNodes.on("mouseover", function (d) {
                    
                    /// cancel the draggingOverReset timeout if exists 
                    /* jshint -W041 */
                    if(draggingOverResetTimeout != null){
                       clearTimeout(draggingOverResetTimeout);
                    }

                    /// sets the dragging over element
                    draggingOver = d;

                    /// TODO: apply animation
                    $("circle", this).attr("r", options.node.radius * 1.3);

                })
                .on("mouseout", function (d) {
                    $("circle", this).attr("r", options.node.radius);  
                    /// Workaround to avoid loosing draggingOver right after 
                    /// the event
                    draggingOverResetTimeout = setTimeout(function(){ draggingOver = null; }, 300);
                });

                
            };


            // panning and zooming
            d3Zoom.on("zoom", zoom);
            d3.select("svg").call(d3Zoom);


            _this = {
          
                /*
                * Get the viewport size
                *
                * @return {Object} { x: , y: }
                *
                */
                viewportSize: function() {
                    
                    return {
                        x: $(options.container).width(),
                        y: $(options.container).height()
                    };
                    
                },

                /**
                 *
                 * Get the tree content size
                 * 
                 * @return {Object} { x: , y: , scale: }
                 */
                contentSize: function(){

                    var tree = $(".svg-tree", options.container),
                        treeElement = new Element(tree), /// SVG width/height can be tricky
                        position = ElementAttributeParser.transform(tree.attr("transform"));


                    return {
                        x: treeElement.width(),
                        y: treeElement.height(),
                        scale: position.scale
                    };

                },

                /**
                 * 
                 * Get the tree viewport position
                 * 
                 * @return {Object} { x: , y: , scale: }
                 * 
                 */
                contentPosition: function(){

                    var treeElement = $(".svg-tree", options.container),
                        t = ElementAttributeParser.transform(treeElement.attr("transform"));

                    return {
                        x: t.translateX,
                        y: t.translateY,
                        scale: t.scale
                    };

                },

                /**
                 * 
                 * Gets the node position ( relative to the tree's viewport )
                 *
                 * @param {Number} nodeId
                 * 
                 * @return {Object} { x: , y: }
                 * 
                 */
                nodePosition: function(nodeId){

                    nodeId = Safe.getNumber(nodeId);

                    var nodeElement = getElement(nodeId);
                        nodePosition = ElementAttributeParser.transform($(nodeElement).attr("transform"));

                    return {
                        x: nodePosition.translateX,
                        y: nodePosition.translateY
                    };

                },

                /**
                 * Gets the offset position of a node
                 * 
                 * @param  {Number} node
                 * @param  {Number} scale
                 * @return {Object}
                 *         {
                 *             x: ,
                 *             y: ,
                 *             scale: 
                 *         }
                 */
                centerOffset: function(nodeId, scale){

                    /// if scale is not specified get the using 
                    if(!scale){  
                        scale =  _this.contentPosition().scale; 
                    }

                    /// finds the offset to center the node
                    var nodePosition = _this.nodePosition(nodeId),
                        viewportSize = _this.viewportSize();
    
                    var x = ( (viewportSize.x / 2) - nodePosition.x) * scale,
                        y = ( (viewportSize.y / 2) - nodePosition.y) * scale;
                    
                    return {
                        x: x,
                        y: y,
                        scale: scale
                    };

                },

                /*
                 * Get the current Dragging Element
                 *
                 * @return {Object} the node structure
                 *
                 */
                currentDraggingOn: function() {
                    return draggingOver;
                },
                
                /*
                 * Refresh the Tree rendered
                 *
                 * @return {Object} the data
                 *
                 */
                render: function () {

                    tree = d3.layout.tree().size([500, 800]);
                    render({});

                    // initialize the id of the nodes
                    svg.selectAll("g.node").each(function (d) {
                        $(this).attr("data-id", d.id); // always set the nodes with their identifiers
                    });

                    // set initial zoom
                    changeZoom([100, 0], 1);
                    
                },
                
                /*
                 * Toogles the visibility of the given node
                 *
                 * @param {Object} The tree node
                 *
                 */
                /*toogle: function(node) {

                    if (!node) return;
                    
                    toogleChildrens(node);
                    render({});
                    
                },*/
                
                /**
                 *
                 * Refresh's the text of a tree node
                 *
                 * @param {Object} node
                 * 
                 */
                refreshText: function(node){

                    var element = getElement(node.id);
                    var text = options.node.text(node);

                    $("text", element).text(text);

                },

                /**
                 * 
                 * Zoom operation
                 *
                 * @param {opts} options
                 *        {
                 *            x: ,
                 *            y: ,
                 *            scale: 
                 *        }
                 *
                 */
                zoom: function(opts){

                    opts = Arguments.get(opts, {
                        x: 0,
                        y: 0,
                        scale: 0
                    });
                    
                    changeZoom([opts.x, opts.y], opts.scale);

                },

                /**
                 * Scale to fit the screen
                 * 
                 * @param  {Object} opts
                 * 
                 */
                scaleToFit: function(opts){

                    opts = Arguments.get(opts, {
                        x: 0
                    });

                    var viewportSize = _this.viewportSize(),
                        contentSize = _this.contentSize();

                    /// calculate the scaled size of the content
                    var realContentSize = 
                        {
                            x: Math.round( contentSize.x / contentSize.scale),
                            y: Math.round( contentSize.y / contentSize.scale)
                        };

                    /// calculate scale size
                    var toScale = Math.min( viewportSize.x / realContentSize.x, viewportSize.y / realContentSize.y );
                    
                    /// maximum scale is 1
                    if(toScale > 1) toScale = 1;

                    /// is opt.x is not defined the centering position is 
                    /// calculated
                    if(!opts.x){

                        /// calculate the centering position
                        opts.x = (viewportSize.x - (realContentSize.x * toScale)) / 2;
                        
                        /// TODO the top position must be proportional to the scale applied
                        opts.y = (viewportSize.y - (realContentSize.y * toScale)) / 2;
                        
                    }

                    changeZoom([opts.x, opts.y], toScale);

                },

                /**
                 * 
                 * Higlight the given node path
                 *
                 * @param {Object} node
                 *
                 */
                highlightPath: function(node){

                    /// Apply selected on the element
                    /// remove all the selected elements
                    $("[selected]", options.container).removeAttr("selected");
                    /// add the selected node
                    var nodeElement = getElement(node.id);
                    $(nodeElement).attr("selected", "");


                    /// apply opacity in every node's
                    svg.selectAll("g.node, path.link").style("opacity", 0.4);

                    /// select all the node's and path's to highlight
                    var elementsToHighlight = [];
                    while(node) {

                        var element = getElement(node.id);
                        elementsToHighlight.push(element[0]);

                        var path = $("path[data-target-id=" + node.id + "]", options.container);
                        if(path.length) {
                            elementsToHighlight.push(path[0]);
                        }

                        node = node.parent;

                    }

                    /// apply opacity to all elements to show
                    d3.selectAll(elementsToHighlight).style("opacity", 1);

                }



            };

            // inherit from EventEmiter
            OOP.inherit(_this, EventEmitter.prototype);

            return _this;

        };
    draw: function () {
        var nodes = this.flatten(this.state.root),
            links = d3.layout.tree().links(nodes),
            selectedThreat, ids, nodeEnter;

        selectedThreat = SuspiciousStore.getSelectedThreat();

        ids = selectedThreat ? this._getThreatIdChain(selectedThreat) : [];

        // Restart the force layout
        this.force
            .nodes(nodes)
            .links(links)
            .start();

        // Update links
        this.link = this.canvas.selectAll('.edge')
            .data(links.filter((link) => link.target.visible), function(d) { return d.source.id + '-' + d.target.id; });

        // Insert new links
        this.link.enter().insert("line", ".node")
                                                .classed('edge', true)
                                                .classed('blink_me', d => ids.indexOf(d.target.id)>-1);

        // Delete old links
        this.link.exit().remove();

        // Update nodes
        this.node = this.canvas.selectAll('.node, .proxy_node')
            .data(nodes.filter((node) => node.visible), function(d) { return d.id; });

        this.node.transition().select('circle')
            .attr("r", d => {
                return this.sizeScale( d.root || d.expanded ? 0 : d.size );
            });

        nodeEnter = this.node.enter().append('g');

        nodeEnter.filter(node => !node.root)
            .call(this.force.drag)
            .on('mousedown', d => {
                d3.event.stopPropagation();
            })
            .append("circle")
                .attr("r", d => this.sizeScale( d.root || d.expanded ? 0 : d.size ));

        nodeEnter.filter(node => node.root)
                                        .append('text')
                                                .classed('glyphicon', true)
                                                .attr('x', -10)
                                                .attr('y', 10)
                                                .text('\u002a');

        nodeEnter
            .attr('class', d => OniUtils.CSS_RISK_CLASSES[d.rep])
            .classed('node', d => !d.root)
            .classed('proxy_node', d => d.root)
            .classed('blink_me', d => ids.indexOf(d.id)>-1)
            .classed('leaf', d => !d.children)
            .on("dblclick", this.onNodeDblClick)
            .on("contextmenu", (d, i) => {
                d3.event.preventDefault();

                if (!d.isDataFilter) return;

                this.tip.hide();

                EdInActions.setFilter(d.filter || d.name);
                EdInActions.reloadSuspicious();
            })
            .on("mouseover", d => {
                var direction = '';

                // Where should the tooltip be displayed?

                // Vertically
                if (d3.event.layerY<this.tip.box[0]) {
                    direction = 's';
                }
                else if (d3.event.layerY>this.tip.box[2]) {
                    direction = 'n';
                }

                // Horizontally
                if (d3.event.layerX>this.tip.box[1]) {
                    direction += 'w';
                }
                else if (d3.event.layerX<this.tip.box[3]) {
                    direction += 'e'
                }

                direction = direction || 'n';

                this.tip.direction(direction);
                this.tip.show.call(this, d);
            })
            .on("mouseout", () => {
                this.tip.hide();
            });

        // Delete old nodes
        this.node.exit().remove();
    },
Пример #27
0
            {"name" : "A311" },
            {"name" : "A312" }
            ]}] }
    ]};

var d3 = require('d3');

// Create a svg canvas
var vis = d3.select("#viz").append("svg:svg")
.attr("width", 400)
.attr("height", 300)
.append("svg:g")
.attr("transform", "translate(40, 0)"); // shift everything to the right

// Create a tree "canvas"
var tree = d3.layout.tree()
    .size([300,150]);

var diagonal = d3.svg.diagonal()
// change x and y (for the left to right tree)
    .projection(function(d) { return [d.y, d.x]; });

// Preparing the data for the tree layout, convert data into an array of nodes
var nodes = tree.nodes(treeData);
// Create an array with all the links
var links = tree.links(nodes);

console.log(treeData)
console.log(nodes)
console.log(links)
Пример #28
0
			scope.render = function (data) {
				// clear out everything in the svg to render a fresh version
				svg.selectAll("*").remove();

				// set up variables
				var diameter = 960;
				svg.attr("width", diameter)
					.attr("height", diameter - 150)
					.append("g")
					.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

				// Data management
				var treeData = data;

				var i = 0,
					duration = 750,
					root;

				var tree = d3.layout.tree()
					.size([360, diameter / 2 - 120])
					.separation(function (a, b) {
						return (a.parent == b.parent ? 1 : 2) / a.depth;
					});

				var diagonal = d3.svg.diagonal.radial()
					.projection(function (d) {
						return [d.y, d.x / 180 * Math.PI];
					});

				root = treeData[0];
				root.x0 = diameter / 2;
				root.y0 = diameter / 2;

				update(root);

				function update(source) {
					var nodes = tree.nodes(root),
						links = tree.links(nodes);

					var link = svg.selectAll(".link")
						.data(links)
						.enter().append("path")
						.attr("class", "link")
						.attr("d", diagonal)
						.attr("transform", function (d) {
							return "translate(" + root.x0 + ", " + root.y0 + ")";
						});

					var node = svg.selectAll(".node")
						.data(nodes)
						.enter().append("g")
						.attr("class", "node")
						.attr("transform", function (d) {
							return "translate(" + root.x0 + ", " + root.y0 + ")rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
						})

					node.append("circle")
						.attr("r", function (d) {
							return (d.score / 40000 * 20) + "px"
						})

					node.append("text")
						.attr("dy", ".31em")
						.attr("text-anchor", function (d) {
							return d.x < 180 ? "start" : "end";
						})
						.attr("transform", function (d) {
							return (d.x < 180 ? "translate(20)" : "rotate(180)translate(-20)");
						})
						.text(function (d) {
							return d.name;
						});

					d3.select(self.frameElement).style("height", diameter - 150 + "px");

				}
			};
Пример #29
0
function createTree(root, divId, model) {

	// dimensions
	var margin = {
		top : 5,
		right : 10,
		bottom : 5,
		left : 130
	};
	var boxWidth = 200;
	var boxHeight = 60;

	var width = 1000;

	var firstLineDY = -14;
	var lineSpaceDY = 18;
	var lineDX = -(boxWidth / 2) + 5;

	// compute
	var countLeafs = 0;
	transformElement(root);

	var widthCore = 750;
	var heightCore = countLeafs * (boxHeight + 47);
	if (heightCore < 200) {
		heightCore = 200;
	}
	var height = heightCore + margin.top + margin.bottom;

	var cluster = d3.layout.tree().size([ heightCore, widthCore ]);
	var diagonal = d3.svg.diagonal().projection(function(d) {
		return [ d.y, d.x ];
	});

	$(divId).empty();
	var svg = d3.select(divId).append("svg").attr("viewBox", "0 0 " + width + " " + height).attr("preserveAspectRatio",
			"xMidYMid").append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	var nodes = cluster.nodes(root);
	var links = cluster.links(nodes);

	var link = svg.selectAll(".link").data(links).enter().append("path").attr("class", "link").attr("d", diagonal);

	var node = svg.selectAll(".node").data(nodes).enter().append("g").attr("class", "node").attr("transform",
			function(d) {
				return "translate(" + d.y + "," + d.x + ")";
			});

	// set box
	node.append("rect").attr("x", -(boxWidth / 2)).attr("y", -(boxHeight / 2)).attr("width", boxWidth).attr("height",
			boxHeight).attr("rx", 7).attr("ry", 7).attr("data-toggle", "tooltip").attr("title", function(d) {
		return "Click to view lifecycle";
	}).on("click", function(d) {
		model.showThisGroup(d.name);
		d3.event.stopPropagation();
	});

	// set lines
	node.append("text").attr("dx", lineDX).attr("dy", firstLineDY + (lineSpaceDY * 0)).text(function(d) {
		return d.type;
	});
	node.append("text").attr("dx", 40).attr("dy", firstLineDY + (lineSpaceDY * 0)).text(function(d) {
		if (typeof d.ip !== 'undefined') {
			return d.ip;
		} else {
			return "";
		}
	});
	node.append("text").attr("class", "bold").attr("dx", lineDX).attr("dy", firstLineDY + (lineSpaceDY * 1)).text(
			function(d) {
				return d.name;
			});
	node.append("text").attr("class", function(d) {

		if (d.state === "DEPLOYED") {
			return "bold svg_ok";
		} else if (d.state === "ERROR") {
			return "bold svg_error";
		} else {
			return "bold svg_warn";
		}
	}).attr("dx", lineDX).attr("dy", firstLineDY + (lineSpaceDY * 2)).text(function(d) {
		return d.state;
	});

	function transformElement(element) { // traverse all elements recursively

		if (element.children.length === 0) {
			countLeafs = countLeafs + 1;
		}

		for (var i = 0; i < element.children.length; i++) {
			transformElement(element.children[i]);
		}
	}

}