d2.js学习笔记(七)——动态SVG坐标空间

目标

  在这一章,我们将学习如何使SVG坐标空间是动态的,这样我们的数据可视化不论数据是什么,都始终是可见的。

  我们会使得SVG坐标空间尺度上调或下调来适于我们的数据。

三个SVG长方形

  我们就从三个长方形作为开始:

 1   var jsonRectangles = [
 2     { "x_axis": 10, "y_axis": 10, "height": 20, "width":20, "color" : "green" },
 3     { "x_axis": 40, "y_axis": 40, "height": 20, "width":20, "color" : "purple" },
 4     { "x_axis": 70, "y_axis": 70, "height": 20, "width":20, "color" : "red" }];
 5
 6   var svgContainer = d3.select("body").append("svg")
 7                                    .attr("width", 100)
 8                                    .attr("height", 100);
 9
10   var rectangles = svgContainer.selectAll("rect")
11                             .data(jsonRectangles)
12                             .enter()
13                             .append("rect");
14
15   var rectangleAttributes = rectangles
16                          .attr("x", function (d) { return d.x_axis; })
17                          .attr("y", function (d) { return d.y_axis; })
18                          .attr("height", function (d) { return d.height; })
19                          .attr("width", function (d) { return d.width; })
20                          .style("fill", function(d) { return d.color; });

  得到的结果是:

three rectangle

  漂亮!

  其中SVG容器:

1   var svgContainer = d3.select("body").append("svg")
2                                       .attr("width", 100)
3                                       .attr("height", 100);

宽100单位,高100单位。

  也就是说,图中三个长方形中最右下角的点的坐标(90,90)仍然在SVG容器视窗范围内。

  但是,如果紫色的长方形的x坐标,突然增加了四倍,从40变成160,结果会怎么样呢?

 1   //原来
 2   { "x_axis": 40, "y_axis": 40, "height": 20, "width":20, "color" : "purple" }
 3
 4   //变为
 5   { "x_axis": 160, "y_axis": 40, "height": 20, "width":20, "color" : "purple" }
 6
 7   //因此,数据集 jsonRectangles 变成了:
 8   var jsonRectangles = [
 9   { "x_axis": 10, "y_axis": 10, "height": 20, "width":20, "color" : "green" },
10   { "x_axis": 160, "y_axis": 40, "height": 20, "width":20, "color" : "purple" },
11   { "x_axis": 70, "y_axis": 70, "height": 20, "width":20, "color" : "red" }];

  这也就是说,紫色长方形有坐标值(160,40)。

  这个坐标已经超出高100宽100的范围。

  这样我们的数据可视化结果成了:

out of viewport

  就像我们想象的那样,太糟了!

动态调整SVG容器空间

  我们真正需要的是,能够根据我们的数据,对SVG容器的width、height属性进行动态调节。

  我们打算使用基础JavaScript循环(loop)来对JSON对象数组处理,找出最大的X坐标he最大的Y坐标。

  最大的x坐标和最大的y坐标就是长方形的最右下角点的坐标。

 1 //新的jsonRectangle数据(其中紫色长方形的x坐标现在是160)
 2 var jsonRectangles = [
 3 {"x_axis":10,"y_axis":10,"height":20,"width":20,"color":"green"},
 4 {"x_axis":160,"y_axis":40,"height":20,"width":20,"color":"purplr"},
 5 {"x_axis":70,"y_axis":70,"height":20,"width":20,"color":"red"}
 6 ];
 7 
 8 var max_x = 0;//用于存储最大x坐标
 9 var max_y = 0;//用于存储最大y坐标
10 
11 //在jsonRectangle数组上的循环
12 for(var i = 0;i<jsonRectangles.length;i++){
13 var temp_x,temp_y;
14 
15 //为了得到最右的点,我们需要把x坐标和width相加
16 temp_x = jsonRectangles[i].x_axis+jsonRectangles[i].width;
17 
18 //为了得到最下面的点,我们需要把y坐标和height相加
19 temp_y = jsonRectangles[i].y_axis+jsonRectangles[i].height;
20 
21 /**
22 *如果临时x坐标比max_x大,
23 *那么就让max_x等于temp_x
24 *否则,什么都不用做
25 *同理,max_y也一样
26 */
27 if(temp_x>=max_x){
28   max_x = temp_x;  
29 }
30 
31 if(temp_y>=max_y){
32   max_y = temp_y;  
33 }
34 
35 }//循环停止
36 
37 max_x;
38 //返回180
39 
40 max_y;
41 //返回 90

  如果数据发生了变化,max_x和max_y将始终都是数据中的最大值。

  现在,我们可以更新我们的SVG容器:

 1 //原来
 2 var svgContainer = d3.select("body").append("svg")
 3 .attr("height",200)
 4 .attr("width",200);
 5 
 6 //现在(使用变量max_x和max_y)
 7 var svgContainer = d3.select("body").append("svg")
 8 .attr("width",max_x + 20)
 9 .attr("width",max_x + 20);
10 //注意 — 在这里给max_x和max_y各加了20,是为了给元素多一些文本空间

  这样,SVG容器就一直能够显示右边的最大尺寸,我们的数据也就能正确的出现在其内部。

成品

  既然问题解决了,完整的代码如下:

 1   var jsonRectangles = [
 2     { "x_axis": 10, "y_axis": 10, "height": 20, "width":20, "color" : "green" },
 3     { "x_axis": 160, "y_axis": 40, "height": 20, "width":20, "color" : "purple" },
 4     { "x_axis": 70, "y_axis": 70, "height": 20, "width":20, "color" : "red" }];
 5
 6   var max_x = 0;
 7   var max_y = 0;
 8
 9   for (var i = 0; i < jsonRectangles.length; i++) {
10     var temp_x, temp_y;
11     var temp_x = jsonRectangles[i].x_axis + jsonRectangles[i].width;
12     var temp_y = jsonRectangles[i].y_axis + jsonRectangles[i].height;
13
14     if ( temp_x >= max_x ) { max_x = temp_x; }
15
16     if ( temp_y >= max_y ) { max_y = temp_y; }
17   }
18
19   var svgContainer = d3.select("body").append("svg")
20                                    .attr("width", max_x)
21                                    .attr("height", max_y)
22
23   var rectangles = svgContainer.selectAll("rect")
24                             .data(jsonRectangles)
25                             .enter()
26                             .append("rect");
27
28   var rectangleAttributes = rectangles
29                          .attr("x", function (d) { return d.x_axis; })
30                          .attr("y", function (d) { return d.y_axis; })
31                          .attr("height", function (d) { return d.height; })
32                          .attr("width", function (d) { return d.width; })
33                          .style("fill", function(d) { return d.color; });

finished

  现在,所有的长方形都出现啦!

  SVG视窗能够把最右的(max_x+20,max_y+20)包括进去。

  而且,SVG视窗是动态生成,不需要我们去手动的更新width和height。

  使用JavaScript的For循环,我们就能够实现动态的resize我们的SVG视窗容器来适应数据。

  如果数据再次改变,我们的视窗(容器)也能够随时包含全部的数据可视化结果。

posted @ 2014-01-16 12:24  楚狂人  阅读(4142)  评论(2编辑  收藏  举报