关于javascript:D3js值得学习吗

3次阅读

共计 5533 个字符,预计需要花费 14 分钟才能阅读完成。

如果你关注前端数据可视化,那你肯定据说过 D3.js。

什么是 D3.js

D3 的全称是 Data-Driven Documents(数据驱动文档),Documents 指的是能被浏览器渲染的 dom 元素,比方divspansvg 等。

对元素进行增删改,是 JS 的惯例操作。而 D3.js 则是提供一系列的办法,让咱们能够疾速不便地 解决数据 ,并依据这些数据 操作 dom 元素

D3.js 简介

D3.js 诞生于 2011 年,它的次要作者是Mike Bostock,目前在 GitHub 上的 star 数量有102k

尽管咱们罕用 D3.js 绘制各种图表,但它不是图表库,更像是图形工具库,它比图表库更加底层。

如果比照 echarts:echarts 的绘制单位是图表;而 D3 的绘制单位是图形,它须要咱们本人将图形组合起来,失去想要的图表。

以绘制一个柱状图为例:

  • echarts。在配置里,传入图表类型和数据 –> 失去柱状图。
  • D3。增加画布 –> 依据数据绘制矩形(柱子)–> 增加坐标轴 –> 失去柱状图。

能够看出,应用 echarts 绘图更加简略。应用 D3 绘图更加灵便,容易定制,同时它要求你了解更多货色,所以学习曲线会比拟平缓。

要不要学习 D3.js

为了疾速开发,咱们通常会抉择简略易用的图表库。那么,D3.js 还有必要学习吗?

如果你有以下几点需要,强烈推荐你学习:

  • 当现有的图表库无奈满足你的展现需要时,可是试试D3
  • 当你要解决的数据文件格式是 CSV, TSV, JSON, XML 时,D3能够间接解决这些格局的数据。
  • 如果你是图表发烧友,想要得心应手地设计、实现各种各样的酷炫图表,那你肯定要学习D3
  • 如果你不满足绘制图表时只能调用 API,而是想要更深刻地了解图表的组成、含意、绘制过程等,D3也会满足你的要求。并且它提供了一系列工具函数,让你在绘制过程中既晓得本人在做哪一步,同时又很不便。

一些 入门敌对的学习材料

1、D3 的官网,官网下面有很多图表案例,有残缺代码,和文档配合应用能够更快把握。

2、我目前看过感觉还不错的两本入门书:

《数据可视化实战:应用 D3 设计交互式图表》(斯科特. 默里)

《快学熟用 D3》(菲利普.K. 贾纳特)

3、视频教程:

[数据可视化教程 @基于 D3.js] (https://www.bilibili.com/vide…):口音规范,比拟好懂,手把手写代码,很适宜入门。

[D3.js 和数据可视化 Fullstack D3 and Data Visualization] (https://www.bilibili.com/vide…):口音听起来有点吃力,然而对 D3 有很多简洁精准的了解,作者的博客:https://wattenberger.com/。

入门实战:用 D3.js 绘制柱状图

(D3 的所有模块,引自 https://wattenberger.com/blog/d3)

D3 尽管 API 有很多,然而被拆分成了很多模块。一些是绘制图表时基本上都会用到的根底模块,比方操作数据的模块 Array,操作 dom 元素Selections、比例尺Scale、绘制 SVG 形态Line\Polygon\Path 等。另一些是特定的功能模块,地图、色调、动画、定制图表等。

在 github(https://github.com/d3)上列出了有所有模块,及其 API 文档:

D3.js 根本应用

这篇文章中咱们次要探讨根底模块的应用,最终目标是绘制一个这样的柱状图。

操作元素

在操作元素方面,D3Jquery 十分类似,也反对链式语法(d3.selectAll('div').style(...).text(...)),可能间断地调用函数。如果你有 Jquery 的应用教训,那么了解 D3 肯定毫不费力。

<div></div>
<div></div>
<script src="./d3/d3.js"></script>
<script>
   // 抉择所有 div,将它们的宽度设为 300px,背景设为深海绿,文字设为 hello world
   d3.selectAll('div')
   .style('width', '300px').style('background', 'darkseagreen')
   .text('hello world')
</script>

D3抉择元素的根底办法有两个:

  • d3.select:返回匹配指定 CSS 选择器的第一个元素,类比querySelector
  • d3.selectAll:返回匹配指定 CSS 选择器的所有元素,类比querySelectorAll

在抉择元素后,咱们能够对抉择集中的元素进行一系列操作,常见的办法如:

  • style:设置元素的 css 款式
  • attr:设置元素的属性
  • text/html:设置元素的内容
  • append:为元素增加子元素,新子元素排在已有子元素的前面
  • insert:为元素增加子元素,新子元素排在指定子元素的后面,如果没有指定子元素,则排在已有子元素的前面
  • remove:删除元素

appendinsert为例。

  • append:为元素增加子元素,新子元素排在已有子元素的前面

    <body>
      <div id="test">existing div</div>
      <script src="./d3/d3.js"></script>
      <script>
          d3.select('body')
          .append('div')
          .text('appended div')
      </script>
    </body>

  • insert:为元素增加子元素,新子元素排在指定子元素的后面,如果没有指定子元素,则排在已有子元素的前面
<body>
    <div id="test">existing div</div>
    <script src="./d3/d3.js"></script>
    <script>
        d3.select('body')
        .insert('div', '#test')    // 新子元素排在指定子元素 (id=test) 的后面
        // 如果是 insert('div'),则新插入元素会排在已有子元素的前面,和下面 append 成果一样
        .text('inserted div')
    </script>
</body>

基于数据操作元素

D3 的外围是基于数据操作 Dom 元素,咱们曾经理解了如何如何操作元素,那么怎么将数据和 DOM 连接起来呢?

要实现的小指标:将一个数组的数据设为一组 div 的内容。

<div></div>
<div></div>
<div></div>
<script>
    const sports = ['football', 'swimming', 'tennis']
    d3.selectAll('div')
        .data(sports)
        .text((d, i) => d )
</script>

当咱们通过 d3.selectAll('div') 失去蕴含所有 div 的抉择集,调用 data(sports) 就将 sports 数组的数据绑定到了该抉择集上。这是 D3 帮咱们实现的工作,通过 console.dir(document.querySelector('div')) 咱们能够看到数据被绑定到了元素的 __data__ 属性 上(该属性是由 D3 增加的)。

当咱们要应用数据赋值时,.text((d, i) => d ),用到了匿名函数(d, i) => d。事实上,如果抉择集调用的办法要拜访被绑定的数据,个别应用这种匿名函数的形式。

匿名函数的参数 d 代表数据(如 football),i 代表数据的索引(football对应的是0)。匿名函数的返回值就是咱们将要应用的值,能够依据须要批改。比方.text((d, i) => d + ',我喜爱' )

Enter、Update、Exit

数据往往是多变的,咱们不得不思考的状况就是,将 dom 抉择集和数据进行绑定(调用 data 办法)的时候,当数据和 dom 抉择集数量不对等时,咱们要怎么更新 dom?

D3中的 Join 思维就用于解决这个问题,它的外围概念是Enter、Update、Exit

举个例子,如果数据是 ['football', 'swimming', 'tennis'],但 dom 抉择集只有一个div,此时就会有两个数据没有 dom 元素与之对应,D3 会创立两个空的占位元素与数据对应,这部分占位元素汇合就称为 Enter

相似上面的这段代码在 D3 绘图会重复呈现:

 d3.selectAll('div')
    .data(sports)
    .enter()    // 当数据集调用 data 办法后,再调用 enter()办法时,会返回对占位元素汇合的援用。.append('div')    // 为占位元素增加实在的 dom 元素,这里是 `div`

接着上例,已有的一个 div 有数据与之对应,这部分元素汇合被称为 Update

<div></div>
<script>
    const sports = ['football', 'swimming', 'tennis']
    const update = d3.selectAll('div').data(sports)  // 当数据集调用 data 办法,间接返回的就是 Update 这部分元素汇合
            
    update.enter()    // 获取占位元素汇合的援用
        .append('div')   // 为占位元素增加实在的 dom 元素
        .text((d, i) => d + 'enter')  // 设置文本内容
        
    update.text((d,i) => d + 'update')    // 设置 Update 这部分元素的文本内容
</script>

如果数据是['football', 'swimming', 'tennis'],而 dom 抉择集有 4 个div,则会有一个元素没有数据绑定,这部分元素汇合被称为 Exit

<div></div><div></div><div></div><div></div>
<script>
    const sports = ['football', 'swimming', 'tennis']
    const update = d3.selectAll('div').data(sports)
            
    update.exit()   // 获取 Exit 元素汇合的援用
        .text('exit')   // 设置文本内容,但通常是调用 remove 办法删除元素
        
    update.text((d,i) => d + 'update')
</script>

绘制柱状图

D3 并没有规定肯定要应用 svg 中绘图,咱们也能够用 div 来绘制柱状图。但从网页性能和图表灵活性方面思考,还是倡议应用 svg。D3 提供了很多 svg 图形的生成器,Line\Polygon\Path等,简化了绘制过程。对于 SVG 的根底应用,参考 svg 从入门到图标绘制和组件封装。

柱状图次要由矩形、坐标轴、文字标签等组成,咱们首先来绘制矩形(柱子)。

const sales = [20,10,20,50,30,60,35];    // 数据
// 定义 SVG 元素的高度、宽度,柱子的宽度,柱子之间的距离(柱子的高度由数据决定)const svgHeight = 300, svgWidth = 500, barWidth = 30,  gap = 10
// 增加 svg 元素,并设置其宽度和高度
const svg = d3.select("body")
    .append('svg')
    .attr('width', svgWidth)
    .attr('height', svgHeight);
// 依据数据增加矩形        
svg.selectAll('rect')
    .data(sales)
    .enter()
    .append('rect')
    .attr('width', barWidth)
    .attr('height', (d,i) => {  // 将数据的值设置为矩形的高度
        return d
    })
    .attr('x', (d,i) => {   // 依据柱子的宽度和对应数据的索引,计算出矩形的 x 坐标
        return i * (barWidth +  gap)
    })
    .attr('y', (d,i) => {    // 用 SVG 元素的高度减去矩形的高度,计算出矩形的 y 坐标
        return svgHeight - d
    })
    .attr('fill', 'gold')    // 设置填充色

(为了不便察看,咱们给 svg 设置一个蓝色边框)

柱子的高度由数据的大小决定,但咱们显然不能间接应用数据的绝对值设置height,不然数值上千上万的数据展现起来就麻烦了。

要解决这个问题,就须要用到比例尺了。

比例尺与数据映射

比例尺是把一组输出域(domain)映射到输入域(range)的函数,它有点像数学中的函数y=f(x),当输出 x 的值,就能够求得 y 的值。

D3 中有各种比例尺函数,【D3 中罕用的比例尺】(https://segmentfault.com/a/11…) 这篇文章有比拟具体的介绍。

咱们这里要应用的是线性比例尺,用法如下:

let scale = d3.scaleLinear().domain([1,5]).range([0,100])

映射关系:

咱们这里要映射的是domain([0, max of sales]) ---> range([0, height of svg],批改下面的代码。

const yScale = d3.scaleLinear()
    .domain([0, d3.max(sales)])
    .range([0, svgHeight]);   // 返回一个线性比例尺,是一个函数
    
svg.selectAll('rect')
    ...
    .attr('height', (d,i) => {return yScale(d)   // 将数据传入比例尺函数,计算矩形高度
    })
    .attr('y', (d,i) => {return svgHeight - yScale(d)  
    })

结语

咱们曾经绘制了柱状图的雏形,因为篇幅问题,剩下的局部在下一篇文章中持续。感激你的浏览,如果感觉还不错,欢送点赞、评论、珍藏哦❤️❤️!

更多技术交换欢送关注我的公众号:Alasolala

正文完
 0