热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

D3入门系列(2)简单的条形图、折线图、散点图和文本换行

SVG画布HTML5提供两种强有力的“画布”:SVG和Canvas。SVG的特点:SVG绘制的是矢量图,因此对图像进行放大不会失真基于XM

SVG画布

HTML 5 提供两种强有力的“画布”:SVG 和 Canvas。

SVG的特点:

  • SVG 绘制的是矢量图,因此对图像进行放大不会失真
  • 基于 XML,可以为每个元素添加 Javascript 事件处理器
  • 每个图形均视为对象,更改对象的属性,图形也会改变
  • 不适合游戏应用

Canvas特点:

  • 绘制的是位图,图像放大后会失真
  • 不支持事件处理器
  • 能够以 .png 或 .jpg 格式保存图像
  • 适合游戏应用

那么,对于数据可视化,SVG的优势就显而易见了,而且D3中很多图形生成器也是只支持SVG的

注意,在 SVG 中,x 轴的正方向是水平向右,y 轴的正方向是垂直向下的

Step1  添加SVG画布

1 var width = 400; //画布的宽度
2 var height = 400; //画布的高度
3
4 var svg = d3.select("body") //选择文档中的body元素
5 .append("svg") //添加一个svg元素
6 .attr("width", width) //设定宽度
7 .attr("height", height); //设定高度
8
9 //画布周边的空白
10 var padding = {left:30, right:30, top:20, bottom:20};

如此,便可以在画布上作图了

比例尺

利用比例尺的目的主要是将某一区域的值映射到另一区域,其大小关系不变,也就是说,让图形自适应画布的大小。

在数学中,x 的范围被称为定义域,y 的范围被称为值域。D3 中的比例尺,也有定义域和值域,分别被称为 domain 和 range。开发者需要指定 domain 和 range 的范围,如此即可得到一个计算关系。

D3中的比例尺最常用的有两种:

线性比例尺

d3.scale.linear() 返回一个线性比例尺。domain() 和 range() 分别设定比例尺的定义域和值域

1 var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];
2
3 var min = d3.min(dataset);
4 var max = d3.max(dataset);
5
6 var linear = d3.scale.linear()
7 .domain([min, max])
8 .range([0, 300]);
9
10 linear(0.9); //返回 0
11 linear(2.3); //返回 175
12 linear(3.3); //返回 300

注意:d3.scale.linear() 的返回值,是可以当做函数来使用的。因此,才有这样的用法:linear(0.9)。

序数比例尺

d3.scale.ordinal() 返回一个线性比例尺。domain() 和 range() 分别设定比例尺的定义域和值域

1 var index = [0, 1, 2, 3, 4];
2 var color = ["red", "blue", "green", "yellow", "black"];
3
4 var ordinal = d3.scale.ordinal()
5 .domain(index)
6 .range(color);
7
8 ordinal(0); //返回 red
9 ordinal(2); //返回 green
10 ordinal(4); //返回 black

 0 对应颜色 red,1 对应 blue,依次类推

Step2  定义数据和比例尺

1 var dataset=[10, 20, 30, 40, 33, 24, 12, 5];
2
3 //x轴
4 var xScale=d3.scale.ordinal()
5 .domain(d3.range(dataset.length))
6 .rangeRoundBands([0,width-padding.left-padding.right]);
7
8 //y轴
9 var yScale=d3.scale.linear()
10 .domain([0,d3.max(dataset)])
11 .range([height-padding.top-padding.bottom,0]);//y轴正方向向下

ordinal.rangeRoundBands - 用几个离散区间来分割一个连续的区间,区间边界和宽度会取整

 坐标轴

D3中用于定义坐标轴的组件:d3.svg.axis()

1 //数据
2 var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
3 //定义比例尺,其中使用了数组dataset
4 var linear = d3.scale.linear()
5 .domain([0, d3.max(dataset)])
6 .range([0, 250]);
7 //定义坐标轴,其中使用了线性比例尺linear
8 var axis = d3.svg.axis()
9 .scale(linear) //指定比例尺
10 .orient("bottom") //指定刻度的方向
11 .ticks(7); //指定刻度的数量

 追加到画布上:

1 svg.append("g")
2 .attr("class","axis")
3 .attr("transform","translate(20,130)")
4 .call(axis);

注意: svg.append("g").call(axis); 与 axis(svg.append(g)); 是相等的。

为axis设定样式(y也是常用的样式了)

Step3  定义坐标轴

1 //定义x轴
2 var xAxis = d3.svg.axis()
3 .scale(xScale)
4 .orient("bottom");
5
6 //定义y轴
7 var yAxis = d3.svg.axis()
8 .scale(yScale)
9 .orient("left");

Step4  添加矩形和文字元素

//矩形之间的空白
var rectPadding = 4;//添加矩形元素
var rects = svg.selectAll(".MyRect").data(dataset).enter().append("rect").attr("class","MyRect").attr("transform","translate(" + padding.left + "," + padding.top + ")").attr("x", function(d,i){return xScale(i) + rectPadding/2;
} ).attr("y",function(d){return yScale(d);}).attr("width", xScale.rangeBand() - rectPadding ).attr("height", function(d){return height - padding.top - padding.bottom - yScale(d);})
.attr("fill","steelblue");
//添加文字元素
var texts = svg.selectAll(".MyText").data(dataset).enter().append("text").attr("class","MyText").attr("transform","translate(" + padding.left + "," + padding.top + ")").attr("x", function(d,i){return xScale(i) + rectPadding/2;
} ).attr("y",function(d){return yScale(d);}).attr("dx",function(){return (xScale.rangeBand() - rectPadding)/2;
}).attr("dy",function(d){return 20;}).text(function(d){return d;});

Step5  添加坐标轴元素

1 //添加x轴
2 svg.append("g")
3 .attr("class","axis")
4 .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
5 .call(xAxis);
6
7 //添加y轴
8 svg.append("g")
9 .attr("class","axis")
10 .attr("transform","translate(" + padding.left + "," + padding.top + ")")
11 .call(yAxis);

 

折线图

1 //定义画布
2 var width=400;
3 var height=400;
4
5 var svg=d3.select("body")
6 .append("svg")
7 .attr("width",width)
8 .attr("height",height);
9 //定义内边距
10 var padding={left:20,right:20,top:10,bottom:10};
11
12 //数据
13 var dataset=[11,35,23,78,55,18,98,100,22,65]
14 //定义比例尺
15 var xscale=d3.scale.linear()
16 .domain([0,dataset.length-1])
17 .range([0,width-padding.left-padding.right])
18 var yscale=d3.scale.linear()
19 .domain([0,d3.max(dataset)])
20 .range([height-padding.top-padding.bottom,0])
21 //绘制坐标轴
22 var xAxis=d3.svg.axis()
23 .scale(xscale)
24 .orient("bottom")
25 var yAxis=d3.svg.axis()
26 .scale(yscale)
27 .orient("left")
28 d3.select("svg")
29 .append("g")
30 .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
31 .call(xAxis)
32 .attr("class","axis")
33
34 d3.select("svg")
35 .append("g")
36 .attr("transform","translate("+padding.left+","+padding.top+")")
37 .call(yAxis)
38 .attr("class","axis")
39
40
41 //绘制图形
42 var line_generator=d3.svg.line()
43 .x(function(d,i){
44 return xscale(i)//x轴的点用数据下标表示
45 })
46 .y(function(d){
47 return yscale(d)
48 });
49 //.interpolate("linear")
50 var g=svg.append("g")
51 .attr("transform","translate("+padding.left+","+padding.top+")")
52
53
54 g.append("path")
55 .attr("d",line_generator(dataset))
56 .attr('stroke', 'black')
57 .attr('stroke-width', 1)
58 .attr("fill","none")

 散点图

关键代码如下:

var circle=svg.selectAll("circle").data(dataset).enter().append("circle").attr("fill","black").attr("r",3).attr("cx",function(d){return padding.left+xscale(d[0])}).attr("cy",function(d){return padding.top+yscale(d[1]) //重要!!})

上面标红的地方说明以下,本来想着y轴向下,便写成了 height-padding.bottom-yscale(d[1]) 

但是发现画出的点的位置并不正确,原来原因是上面定义比例尺时,将值域已经设置成了 [height-2*padding.top,0] ,可以说,此时的坐标轴方向已经反转,所以此时的计算只需加上 padding.top 即可

其实,更不易出错的方法是,将点放在一个group内,那么cx, cy只需按比例计算,然后在将group做一个transform变换即可。如上面画折线图的方法。

文本的换行

最后讲一下文本的换行

方法1:利用tspan标签

var str = "云中谁寄锦书来,雁字回时,月满西楼"; var text = svg.append("text").attr("x",30).attr("y",100).attr("font-size",30).attr("font-family","simsun");
//将字符串分段
var strs = str.split(",") ;text.selectAll("tspan").data(strs).enter().append("tspan").attr("x",text.attr("x")) //文本从x=?处开始.attr("dy","1em") //文本较y轴的相对位移,此处也就意味着换行.text(function(d){return d;});

 

方法2:引用库 http://www.ourd3js.com/library/multext.js,其实质仍旧是tspan,只是进行了封装罢了

文件里只实现了一个函数 appendMultiText(),其各参数的意义为:

appendMultiText(container, //文本的容器,可以是 str, //字符串posX, //文本的x坐标posY, //文本的y坐标width, //每一行的宽度,单位为像素fontsize, //文字的大小(可省略),默认为 14fontfamily //文字的字体(可省略),默认为 simsun, arial
)

小实例:

var str = "青青子衿,悠悠我心,但为君故,沉吟至今。"; var multext = appendMultiText(svg,str,30,100,120,20,"simsun");multext.attr("transform","rotate(-20)");

 

转:https://www.cnblogs.com/Hyacinth-Yuan/p/8059734.html



推荐阅读
  • python爬虫Demo
    1爬虫功能:爬取某域名下所有网页,比如爬取python文档 https:docs.python.orgzh-cn3 ,爬取之后, ... [详细]
  • C# 对象转 JSON 字符串的方法与应用
    本文介绍如何在 C# 中使用一般处理程序(ASHX)将对象转换为 JSON 字符串,并通过设置响应类型为 application/json 来确保客户端能够正确解析返回的数据。同时,文章还提供了 HTML 页面中不依赖 jQuery 的 AJAX 方法来接收和处理这些 JSON 数据的具体实现。 ... [详细]
  • 在Ubuntu 16.04中使用Anaconda安装TensorFlow
    本文详细介绍了如何在Ubuntu 16.04系统上通过Anaconda环境管理工具安装TensorFlow。首先,需要下载并安装Anaconda,然后配置环境变量以确保系统能够识别Anaconda命令。接着,创建一个特定的Python环境用于安装TensorFlow,并通过指定的镜像源加速安装过程。最后,通过一个简单的线性回归示例验证TensorFlow的安装是否成功。 ... [详细]
  • Struts2(六) 用Struts完成客户列表显示
    Struts完成客户列表显示所用的基础知识在之前的随笔中已经讲过。这篇是介绍如何使用Struts完成客户列表显示。下面是完成的代码执行逻辑图:抽取项目部分代码相信大家 ... [详细]
  • 优化 DropDownList 与 TextBox 的交互体验
    本文介绍了一种解决方案,通过在 DropDownList 前添加一个 TextBox 来提升用户体验。当选项过多时,用户可以通过在 TextBox 中输入关键词来快速定位并选择相应的选项。 ... [详细]
  • 本文探讨了使用JQuery UI可调整大小插件时遇到的一个常见问题:如何在用户调整元素大小后避免不必要的点击事件触发,导致元素被意外取消选中。 ... [详细]
  • nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文探讨了如何在Python中计算两个给定时间字符串(格式为HH:MM:SS)之间的时间差,并提供了详细的代码示例及解决方案。 ... [详细]
  • MySQL中的Anemometer使用指南
    本文详细介绍了如何在MySQL环境中部署和使用Anemometer,以帮助开发者有效监控和优化慢查询性能。通过本文,您将了解从环境准备到具体配置的全过程。 ... [详细]
  • Facebook PrestoDB 配置指南
    本指南详细介绍了如何安装和配置 Facebook PrestoDB,包括必要的文件设置和启动方法。 ... [详细]
  • 现代软件工程开发体验:结对编程
    距现代软件工程开课已经3周,按照课程安排,在最近的9天中,我们进行了极限编程模式的体验:pairwork(结对编程,具体见链接),对象是在academicsearchmap上添加一些新特性。经过选 ... [详细]
  • Linux环境下Redmine快速搭建指南
    本文将详细介绍如何在Linux操作系统中使用Bitnami Redmine安装包快速搭建Redmine项目管理平台,帮助读者轻松完成环境配置。 ... [详细]
  • 使用爬虫测试Django网站的稳定性
    本文介绍如何通过爬虫频繁访问Django网站以测试其稳定性和性能。首先需要禁用Django的CSRF保护,然后使用Python爬虫脚本进行POST请求测试。 ... [详细]
  • 本文深入探讨了在Java编程语言中,如何使用`org.apache.polygene.api.association.AssociationDescriptor.qualifiedName()`方法,并提供了多个实际应用的代码示例。这些示例源自GitHub、StackOverflow和Maven等知名平台,旨在帮助开发者更好地理解和应用这一方法。 ... [详细]
  • 本文详细介绍了DOM(文档对象模型)的基本概念、结构及操作方法。DOM作为一种API,允许开发者以编程方式访问HTML和XML文档的结构,实现页面内容的动态修改。 ... [详细]
author-avatar
绿林VS逍遥
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有