【D3.js开发入门1:绘制图表】静态图表

已被阅读 749 次 | 文章分类:javascript | 2022-05-04 01:09

D3.js是用于 HTML 和 SVG 实现的 JavaScript 可视化库。基于数据操作文档的 JavaScript 库。

什么是 D3.js?

D3.js是用于 HTML 和 SVG 实现的 JavaScript 可视化库。基于数据操作文档的 JavaScript 库。

说到D3不得不提到Echarts,Echarts和D3都是一个数据可视化的工具;而且都能实现一些相同的可视化图效果;那他们有什么不同呢?区别还是很大的

库层面的不同:

                                            
1 D3使用svg绘制图形,echarts使用canvas绘制图形

2 D3代码自由度高,相当灵活,但是学习成本也大;相反echarts封装性强,通过配置参数即可简单上手,但是不够灵活扩展性低;对于绝大多数项目够用了
                                            
                                        

应用场景:

                                            
1 如果只是展示一些静态图表;或者有少数鼠标点击、悬浮等效果的图表用echarts首选

2 如果说对绘制的DOM图表有频繁的鼠标交互操作,比如编辑、删除修改等那么echarts首选;D3中的每个图形都是一个标签,可以方便的进行增删操作
                                            
                                        

1 实现效果

D3能实现的效果还是很丰富的,大家感兴趣可以去官网demo查看https://observablehq.com/@d3/gallery

首先展示下本系列1和2能实现的简单demo效果

普通柱状图:

/net/upload/image/20220504/90b67fae091a4d1ba659eb5009e8af9c.png

动起来的柱状图:

/net/upload/image/20220504/d2c2ec91555d492782b0e9d94d501dba.gif

鼠标悬浮动画

/net/upload/image/20220504/948fd6990b4b4152b8c845ca56b50c70.gif

交互的导图

/net/upload/image/20220504/0c1515902d3e4f4baa1b73b5050a35aa.gif

力导向图

/net/upload/image/20220504/44b0b18438864cbd85174653f589b90c.gif

动态添加实体

/net/upload/image/20220504/4b6869e4778649af9805408d1fdbbfc8.gif

2 基础语法

2.1 datum() 方法

                                            
将数据绑定到同一个元素上
                                            
                                        

/net/upload/image/20220504/5a73e9e1af054c95a2054fc772b19a14.png

代码如下

                                            
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>datum():绑定一个数据到选择集上</title>
	<script src="../d3/d3.js"></script>
</head>
<body>
    <p>1</p>
    <p>2</p>
    <p>3</p>
    <p>4</p>
<script>
    var body = d3.select("body"); //选择文档中的body元素
    var p = body.selectAll("p");  
    var str=["dog","cat","snake"];
    p.datum(str).text(function(d,i){
        return "第"+i+"个p"+":"+" "+d;
    })
  </script>
</body>
</html>
                                            
                                        

2.1 data()

                                            
将数据跟元素按顺序对应绑定;
                                            
                                        

/net/upload/image/20220504/afba84c9a3c34da3a5c21b884d2eb407.png

                                            
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>data():绑定一个数组到选择集上</title>
	<script src="../d3/d3.js"></script>
</head>
<body>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
<script>
    var body = d3.select("body"); //选择文档中的body元素
    var p = body.selectAll("p"); 
    var dataset = ["I like dogs","I like cats","I like snakes"];
    p.data(dataset);
    p.text(function(d,i){
        return "第"+i+"个p"+":"+" "+d;
    })
  </script>
</body>
</html>
                                            
                                        

2.3 链式操作

                                            
这里涉及一个概念:选择集

 使用 d3.select() 或 d3.selectAll() 选择元素后返回的对象,就是选择集。

 另外,有人会发现,D3 能够连续不断地调用函数,形如:

 d3.select().selectAll().text()

 这称为链式语法,和 JQuery 的语法很像,常用 JQuery 的朋友一定会感到很亲切。

 因为封装每个方法的时候都会返回当前对象 return  this;
                                            
                                        
                                            
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>选择集</title>
	<script src="../d3/d3.js"></script>
</head>
<body>
 
<script>
    var body = d3.select('body');   // 选择body元素
    body.append('h1')               // 向 body元素中插入 h1标签
    .text('Hello xiaobai')          // 给h1标签填充文字为hello world
    .style('color','red');          // 修改样式 字体颜色 为红色
  </script>
</body>
</html>
                                            
                                        

2.4 增加和删除元素

                                            
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增删元素</title>
	<script src="../d3/d3.js"></script>
</head>
<body>
    <h1 id='app'>我h1</h1>
<script>
    var h1 = d3.select('h1');
    // 插入元素
    var body = d3.select('body');
    body.append('h2').text('我是插在body 末尾的元素');
    body.insert('h2','#app').text('我是插在id为APP的元素前面的 h2标签')
    //删除元素
    var app = d3.select('#app');
    app.remove(); //删除 id为app的元素 
  </script>
</body>
</html>
                                            
                                        

3 图表语法

3.1 基础柱状图

先简单解释svg和canvas

                                            
SVG 是什么

 SVG,指可缩放矢量图形(Scalable Vector Graphics),是用于描述二维矢量图形的一种图形格式,是由万维网联盟制定的开放标准。

 SVG 使用 XML 格式来定义图形,除了 IE8 之前的版本外,绝大部分浏览器都支持 SVG,

 可将 SVG 文本直接嵌入 HTML 中显示。

 SVG 有如下特点:

 SVG 绘制的是矢量图,因此对图像进行放大不会失真。

 基于 XML,可以为每个元素添加 JavaScript 事件处理器。

 每个图形均视为对象,更改对象的属性,图形也会改变。

 不适合游戏应用。

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

 Canvas 是什么

 Canvas 是通过 JavaScript 来绘制 2D 图形,是 HTML 5 中新增的元素。

 Canvas 有如下特点:

 绘制的是位图,图像放大后会失真。

 不支持事件处理器。

 能够以 .png 或 .jpg 格式保存图像

 适合游戏应用
                                            
                                        

代码和效果如下:

                                            
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>柱状图</title>
	<script src="../d3/d3.js"></script>
</head>
<body>
<script>
   var w = 400,h = 400;
    var body = d3.select('body');   //选择 body元素
    var data = [50,100,200,150];
    var svg = body.append('svg');  //在body中插入svg 元素  画布
    svg.selectAll('rect')  // 选择svg 中的rect(svg 中提供的矩形标签) 元素
    .data(data)          // 绑定数据
    .enter()             // 当 data.length > rect 的元素个时候用enter()。 update,exit()以后再说
    .append('rect')      // 补充data.length - rect.length 剩余的rect元素
    .attr('x',20)        // 上面说了SVG画布的坐标问题 x就是横向坐标的距离
    .attr('y',function(d,i){  // Y也一样 都是相对 (0,0)点
        return 25 * i;
    })
    .attr('width',function(d,i){  // 设置矩形的宽度
        return d;
    })
    .attr('height',function(d,i){   //设置柱子的高度
        return 20;
    })
    .attr('fill','green');  // 给柱子填充颜色
    // 其实跟canvas 中的fillrect 绘制矩形一样
  </script>
</body>
</html>
                                            
                                        

/net/upload/image/20220504/8f2f3ece5ff844e78f02f94980604461.png

数据映射:上面数据是具体指定的数组,这里介绍一下用线性比例尺的方式绘制映射数据

                                            
线性比例尺,能将一个连续的区间,映射到另一区间。要解决柱形图宽度的问题,就需要线性比例尺。
                                            
                                        

比如将[0.3,0.9,1,2,2.5]这组数据用柱状图绘制,显然值太小;那么可有利用相关方法做映射,这里我们将上面的数据集映射到0-300的范围;

                                            
var dataset = [0.3,0.9,1,2,2.5]; //要把这个区间映射到0-300的范围
var max = d3.max(dataset);
var linear = d3.scaleLinear()
  .domain([0,max])
  .range([0,300]);
                                            
                                        
                                            
// 用比列尺转换为柱状图  就以上面那个线型比例尺为列 
    var body = d3.select('body');   //选择 body元素
    var svg = body.append('svg');  //在body中插入svg 元素  画布
    svg.selectAll('rect')
      .data(dataset)
      .enter()
      .append('rect')
      .attr('x',20)
      .attr('y',function(d,i){
          return i * 25;
      })
      .attr('width',function(d,i){
          return linear(d);
      })
      .attr('height',function(d,i){
          return 20;
      })
      .attr('fill','blue');
                                            
                                        

3.2 带坐标轴的柱状图

/net/upload/image/20220504/7d9171cc29a24a0b851afb2696b3e8fa.png

首先绘制上面3.1的映射柱状图;接下来是创建坐标轴的代码

                                            
// 创建比例尺
var linear = d3.scaleLinear().domain([0, max]).range([0, 300]);
                                            
                                        

添加坐标轴

                                            
//添加坐标轴
      var axis = d3
        .axisBottom()   // v4: axisBottom 表示向下的比例尺  v3: d3.svg.axis().scale(linear).orient('bottom').ticks(5)   v4  和v3差别真大
        .scale(linear)  // 指定比例尺
        .ticks(5);       // 指定刻度数量
      svg.append('g')     // svg 提供的标签,不知道的可以去熟悉下svg
        .attr('transform', function (d, i) {
          return 'translate(' + 20 + ',' + 25 * 5 + ')'; // 把坐标轴移到对应的位置
        })
        .call(axis);
                                            
                                        

3.3 坐标轴和标注

/net/upload/image/20220504/7d080d90cf6d4179b5bf35f7a77c0cc1.png

(1)添加svg画布

                                            
// 画布大小
var width = 400;
var height = 400;
 
// 在 body 里添加一个 SVG 画布
var svg = d3
  .select('body')
  .append('svg')
  .attr('width', width)
  .attr('height', height);
// 画布周边的空白
var padding = { left: 30, right: 30, top: 20, bottom: 20 };
                                            
                                        

(2)定义数据集

                                            
// 定义一个数组
var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
                                            
                                        

(3)定义x和y轴

                                            
// x轴的比例尺
var xScale = d3.scale
  .ordinal()
  .domain(d3.range(dataset.length))
  .rangeRoundBands([0, width - padding.left - padding.right]);
// y轴的比例尺
var yScale = d3.scale
  .linear()
  .domain([0, d3.max(dataset)])
  .range([height - padding.top - padding.bottom, 0]);
// 定义x轴
var xAxis = d3.svg.axis().scale(xScale).orient('bottom');
// 定义y轴
var yAxis = d3.svg.axis().scale(yScale).orient('left');
                                            
                                        

(4)矩形柱状图

                                            
// 矩形之间的空白
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);
  });
                                            
                                        

(5)添加文字标注

                                            
// 添加文字元素
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;
});
                                            
                                        

(6)添加x和y轴

                                            
// 添加x轴
svg
  .append('g')
  .attr('class', 'axis')
  .attr(
    'transform',
    'translate(' + padding.left + ',' + (height - padding.bottom) + ')'
  )
  .call(xAxis);
 
// 添加y轴
svg
  .append('g')
  .attr('class', 'axis')
  .attr(
    'transform',
    'translate(' + padding.left + ',' + padding.top + ')'
  )
  .call(yAxis);
                                            
                                        

QQ:3410192267 | 技术支持 微信:popstarqqsmall

Copyright ©2017 xiaobaigis.com . 版权所有 鲁ICP备17027716号