2017-08-04 84 views
1

我开始一个新的项目,主要目的是学习一些基本的d3.js。这里是我的玩具问题:我想绘制一个带有几个矩形的交互式流程图,当用户悬停/点击一个矩形时,我想用指向场景中其他矩形的箭头显示相关性。我还想在其他地方显示一些文本,并以此用户操作为条件。箭头和文字下面的点击和悬停

最终目标是这样的:

enter image description here

这里是我的出发点,通过一些基本的教程启发:

的index.html

<!DOCTYPE html> 
<html> 
    <head> 
     <script src="https://d3js.org/d3.v4.min.js"></script> 
    </head> 
    <body> 
     <script src="script.js"></script> 
    </body> 
</html> 

script.js

var s = 50; 
var w = 200; 
var h = 100; 

var jsonBoxes = [ 
    {"name": "Box A", "x_axis": s, "y_axis": s, "width": w, "content": "content of Box A", "depends" : "Box C"}, 
    {"name": "Box B", "x_axis": w + 2*s, "y_axis": s, "width": w, "content": "content of Box B", "depends" : "Box D"}, 
    {"name": "Box C", "x_axis": 2*(w + s) + s, "y_axis": s, "width": w, "content": "content of Box C", "depends" : "Box D" }, 
    {"name": "Box D", "x_axis": s, "y_axis": 2*s +h, "width": w, "content" : "content of Box D" , "depends": "Box F"}, 
    {"name": "Box E", "x_axis": w + 2*s, "y_axis": 2*s+h, "width": w, "content": "content of Box E", "depends" : "Box F" }, 
    {"name": "Box F", "x_axis": 2*(w + s) + s, "y_axis": 2*s+h, "width": w, "content": "content of Box F", "depends" : "Box A" }]; 

var svgContainer = d3.select("body").append("svg") 
            .attr("width", 800) 
            .attr("height", 300); 

var rectangles = svgContainer.selectAll("rect") 
          .data(jsonBoxes) 
          .enter() 
          .append("rect"); 

var rectanglesAttributes = rectangles 
         .attr("x", function (d) { return d.x_axis; }) 
         .attr("y", function (d) { return d.y_axis; }) 
         .attr("width", function (d) { return d.width; }) 
         .attr("height", 100) 
         .style("fill", function(d) { return "Cornsilk"; }); 

var p = d3.select("body").selectAll("p") 
    .data(jsonBoxes) 
    .enter() 
    .append("p") 
    .text(function(d) { return d.name + ": " + d.content; }); 

有人可以说明(/指向我)处理悬停或点击并在此基础上生成内容(箭头,文本)的一般过程吗? PS:我很乐意R以更合适的格式预处理数据。我使用yaml作为输入格式,并且根据需要似乎很容易生成json。 d3映射和交互性是我是一个全新手的地方。

回答

1

第一:在<svg>,你有<text>而不是<p>,令人沮丧的是,它不会包装自己。要包装文字,请查看Mike Bostock's Block

总体上,点击功能采用这种形式:

selection.on('click', function (data, index) { 
    stuff(); 
}) 

徘徊在click的地方使用mouseovermouseout。对于这个问题,看起来click将是一个明智的选择,以显示箭头和mouseover'其他文字'。在你的情况下,它可能是这个样子:

rectangles.on('click', function (d, i) { //1 
    d3.select('svg').append('path').attr('d', pathString); //2 
    d3.selectAll('rect').filter(function (k, j) { 
     return k.name == d.depends; //3 
    }).each(function() { 
     d3.select(this).on('click')(); //4 
    }); 
}).on('mouseover', function (d, i) { //5 
    d3.select('text#moreinfo').text(d.extraInfo); 
}); 

箭头将需要path元素,除非添加polygon元素,每头他们不会有头。

  1. 将点击事件附加到每个矩形。
  2. 追加到svg a path元素(它是一行)。
  3. 从它的名字找到必备课程的rect
  4. 为这些(或单数)前提矩形中的每一个调用click事件。请注意,因为每个点击事件都是以这种方式设置的,所以这实际上是一个递归调用,它将为链中的每个先决条件绘制箭头。
  5. 附加一个鼠标悬停处理程序,它将更改“其他文本”text元素的文本,只要您先前创建该元素。

为了使箭头变得很酷和弯曲,就像在图像中一样,您需要计算路径的控制点。 Here是一个很酷的图形来解释如何使用CubicBézier曲线的路径。你应该能够用一些基本的几何图形来计算控制点。

我建议首先真正熟悉svg

+0

谢谢。我看到了文本环绕的块,但它是一个相当复杂的例子,因为它是条形图的一部分。我希望能找到更简单的东西,只需要一个'div'或者更远一点的东西(也许与svg分开)。关于箭头和贝塞尔曲线,根据我见过的例子(可折叠树等),我会认为d3可以为我制作漂亮的路径。话虽如此,由于我的布局是静态的,我可以简单地在自己的绘画中绘制箭头,并且在点击/悬停时只有d3才会改变颜色。 – baptiste

+0

这似乎是一个很酷的想法,如果你愿意,我肯定会动态地做到这一点。我坦率地不太熟悉[树](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap)(我不知道它们适合你的情况有多好) ,但是你可以做一些类似[this](http://bl.ocks.org/robschmuecker/7880033)的东西,但是要制作'节点的矩形,并把'text'放在它的上面。 –

+0

同样对于'div'的想法,你可以使用'd3'作为'DOM'操纵器,就像jQuery一样,语句如:'d3.select('body')。append('div').text('foo' );'这肯定会使包装变得更容易; –