戳蓝字「高级前端进阶」关注我们哦!
[h1]前言[/h1]近年来一直是最重要的数据可视化库之一,在创建者的维护下,前景依然无量,至少现在没有能打的:
- 与众多其他库的区别在于无限定制的能力(直接操作)。
- 它的底层提供对原生元素的直接控制,但它也带来了高学习曲线的成本。
- 我们将把和结合在一起 - 使用的动态数据绑定,清晰的语法和模块化结构,可以充分发挥的最佳性能。
根据广泛定义,D3可拆分为以下几种分库:
- 绝大部分的课程或书籍,都会着重讲解在其操作功能上,但这明显与近几年来的web框架理念相违背。
- 用于数据可视化的,其核心在于使用绘图指令装饰数据,从源数据创建新的可绘制数据,生成路径以及从数据和方法在中创建数据可视化元素(如轴)的功能。
- 有许多用于管理DOM的工具,所有这些工具都可以在中集成数据可视化功能。这也是能与无缝结合的原因之一。
于此,我们不需要从操作功能开始学起,直接通过实例来入门。
[h1]D3.js 渐进入门[/h1]以下实例的模版均为以下形式:
- [/code]
- [/list][h2]1. 选择和操作[/h2][img]https://201907.oss-cn-shanghai.aliyuncs.com/wc/1811847-262563bf3aa8c8bf2c71b50213cfe7b8[/img]
- 你需要学习的第一件事是如何使用D3.js选择和操作DOM元素。该库在操作DOM方面实际上非常强大,因此理论上可以将其用作 [code]jQuery
复制代码 的替代品。以下代码请逐行添加运行。
- d3.select('h1').style('color', 'red')
复制代码- .attr('class', 'heading')
复制代码
- d3.select('body').append('p').text('First Paragraph');
复制代码- d3.select('body').append('p').text('Second Paragraph');
复制代码- d3.select('body').append('p').text('Third Paragraph');
复制代码
- d3.selectAll('p').style('')
复制代码 [h2]2.数据加载和绑定[/h2]
当你要创建可视化时,了解如何加载数据以及将其绑定到DOM非常重要。所以在这个实例中,你将学到这两点。
- let dataset = [1, 2, 3, 4, 5];
复制代码
- .append('p') // appends paragraph for each data element
复制代码- .text('D3 is awesome!!');
复制代码- //.text(function(d) { return d; });
复制代码 [h2]3.创建一个简单的柱状图[/h2]
首先需要添加一个标签
- [/code]
- [/list]然后在 [code]index.js
复制代码 中添加(已添加关键注释):
- let dataset = [80, 100, 56, 120, 180, 30, 40, 120, 160];
复制代码- let svgWidth = 500, svgHeight = 300, barPadding = 5;
复制代码- let barWidth = (svgWidth / dataset.length);
复制代码
- let svg = d3.select('svg')
复制代码- .attr("height", svgHeight);
复制代码
- // 文档:http://www.w3school.com.cn/svg/svg_rect.asp
复制代码
- let barChart = svg.selectAll("rect")
复制代码- .enter() // 指定选择集的enter部分
复制代码- .append("rect") // 添加足够数量的矩形
复制代码- .attr("y", d => svgHeight - d ) // d为数据集每一项的值, 取y坐标
复制代码- .attr("height", d => d) // 设定高度
复制代码- .attr("width", barWidth - barPadding) // 设定宽度
复制代码- .attr("transform", (d, i) => {
复制代码- let translate = [barWidth * i, 0];
复制代码- return "translate("+ translate +")";
复制代码 [h2]4. 在图形上方显示数值[/h2]
这时就需要在上述代码中创建的文本
- let text = svg.selectAll("text")
复制代码- .attr("y", (d, i) => svgHeight - d - 2)
复制代码- .attr("x", (d, i) => barWidth * i)
复制代码- .attr("fill", "#A64C38");
复制代码 过程比较简单,就是返回文本,计算x/y坐标,并填充颜色。
[h2]5.: 比例尺函数[/h2]中有个重要的概念就是比例尺。比例尺就是把一组输入域映射到输出域的函数。映射就是两个数据集之间元素相互对应的关系。比如输入是1,输出是100,输入是5,输出是10000,那么这其中的映射关系就是你所定义的比例尺。中有各种比例尺函数,有连续性的,有非连续性的,在本例子中,你将学到,线性比例尺。
[h3]5.1,线性比例尺[/h3]使用创造一个线性比例尺,其中:
- 是输入域
- 是输出域
- 相当于将中的数据集映射到的数据集中。
- let scale = d3.scaleLinear().domain([1,5]).range([0,100])
复制代码 映射关系:
值得注意的是,上述代码只是定义了一个映射规则,映射的输入值并不局限于中的输入域。
于是我们来改造的例子:
- let dataset = [1,2,3,4,5];
复制代码
- let svgWidth = 500, svgHeight = 300, barPadding = 5;
复制代码- let barWidth = (svgWidth / dataset.length);
复制代码
- let svg = d3.select('svg')
复制代码- .attr("height", svgHeight);
复制代码
- let yScale = d3.scaleLinear()
复制代码- .domain([0, d3.max(dataset)])
复制代码
- let barChart = svg.selectAll("rect")
复制代码- .attr("y", d => svgHeight - yScale(d))
复制代码- .attr("height", d => yScale(d))
复制代码- .attr("width", barWidth - barPadding)
复制代码- .attr("transform", (d, i) => {
复制代码- let translate = [barWidth * i, 0];
复制代码- return "translate("+ translate +")";
复制代码 然后就会得到以下图形:
[h2]6.:轴[/h2]
轴是任何图表的组成部分,本例子中将会用到上面讲到的比例尺函数。
- let data= [80, 100, 56, 120, 180, 30, 40, 120, 160];
复制代码
- let svgWidth = 500, svgHeight = 300;
复制代码
- let svg = d3.select('svg')
复制代码- .attr("height", svgHeight);
复制代码
- let xScale = d3.scaleLinear()
复制代码- .domain([0, d3.max(data)])
复制代码
- let yScale = d3.scaleLinear()
复制代码- .domain([0, d3.max(data)])
复制代码
- let x_axis = d3.axisBottom()
复制代码
- let y_axis = d3.axisLeft()
复制代码
- // 在svg中提供了如g元素这样的将多个元素组织在一起的元素。
复制代码- // 由g元素编组在一起的可以设置相同的颜色,可以进行坐标变换等,类似于Vue中的
复制代码
- .attr("transform", "translate(50, 10)")
复制代码
- let xAxisTranslate = svgHeight - 20;
复制代码
- .attr("transform", "translate(50, " + xAxisTranslate +")")
复制代码 [h2]7. 创建简易的元素[/h2]
在这里面,你会创建和- [/code]元素
- [list=1][*][code]let svgWidth = 600, svgHeight = 500;
复制代码- let svg = d3.select("svg")
复制代码- .attr("height", svgHeight)
复制代码- .attr("class", "svg-container")
复制代码
- let line = svg.append("line")
复制代码
- let rect = svg.append("rect")
复制代码- .attr("fill", "#9B95FF");
复制代码
- let circle = svg.append("circle")
复制代码- .attr("fill", "#7CE8D5");
复制代码 [h2]8. 创建饼图[/h2]
- {"platform": "Android", "percentage": 40.11},
复制代码- {"platform": "Windows", "percentage": 36.69},
复制代码- {"platform": "iOS", "percentage": 13.06}
复制代码
- let svgWidth = 500, svgHeight = 300, radius = Math.min(svgWidth, svgHeight) / 2;
复制代码- let svg = d3.select('svg')
复制代码- .attr("height", svgHeight);
复制代码
- //Create group element to hold pie chart
复制代码- .attr("transform", "translate(" + radius + "," + radius + ")") ;
复制代码
- // d3.scaleOrdinal() 序数比例尺
复制代码- // schemeCategory10, 颜色比例尺
复制代码- // D3提供了一些颜色比例尺,10就是10种颜色,20就是20种:
复制代码- let color = d3.scaleOrdinal(d3.schemeCategory10);
复制代码
- let pie = d3.pie().value(d => d.percentage);
复制代码
- let arc = g.selectAll("arc")
复制代码
- .attr("fill", d => color(d.data.percentage));
复制代码
- .attr("transform", d => `translate(${label.centroid(d)})`)
复制代码- .attr("text-anchor", "middle")
复制代码- .text(d => `${d.data.platform}:${d.data.percentage}%`);
复制代码 [h2]9. 创建折线图[/h2]
最后,你将学习如何创建折线图以显示近四个月的比特币价格。要获取数据,你将使用外部API。这个项目还将你在整个课程中学到的很多概念结合在一起,所以这是一个很好的可视化课程结束。
- const api = 'https://api.coindesk.com/v1/bpi/historical/close.json?start=2019-03-31&end=2019-07-01';
复制代码
- document.addEventListener("DOMContentLoaded", function(event) {
复制代码- .then(response => response.json())
复制代码- let parsedData = parseData(data);
复制代码- .catch(err => console.log(err))
复制代码
- for (let i in data.bpi) {
复制代码- date: new Date(i), //date
复制代码- value: +data.bpi[i] //convert string to number
复制代码
- let svgWidth = 600, svgHeight = 400;
复制代码- let margin = { top: 20, right: 20, bottom: 30, left: 50 };
复制代码- let width = svgWidth - margin.left - margin.right;
复制代码- let height = svgHeight - margin.top - margin.bottom;
复制代码
- let svg = d3.select('svg')
复制代码- .attr("height", svgHeight);
复制代码
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
复制代码
- .rangeRound([height, 0]);
复制代码
- x.domain(d3.extent(data, function(d) { return d.date }));
复制代码- y.domain(d3.extent(data, function(d) { return d.value }));
复制代码
- .attr("transform", "translate(0," + height + ")")
复制代码
- .attr("transform", "rotate(-90)")
复制代码- .attr("text-anchor", "end")
复制代码
- .attr("stroke", "steelblue")
复制代码- .attr("stroke-linejoin", "round")
复制代码- .attr("stroke-linecap", "round")
复制代码- .attr("stroke-width", 1.5)
复制代码 以上原实例均来自:Learn D3 for free。scrimba是一个非常神奇的网站。它是使用交互式编码截屏工具构建的。
所有的操作都是:
暂停截屏视频 → 编辑代码 → 运行它!→ 查看更改
非常值得安利一波。接下来进入第二部分:中使用的正确姿势
[h1]2.中使用的正确姿势[/h1]我们将使用和构建一个基本的柱状图组件。网上有一堆例子,但我们将专注于写,而不是滥用D3。
[h2]1. 安装依赖[/h2]首先,我们需要为项目安装依赖项。我们可以简单地安装和使用整库:
但我在前面讲到,实际上是几个分库的集合,考虑到项目的优化,我们只安装所需的模块。
使用初始化项目即可。
[h2]2. 创建柱状图[/h2]
[h2]3. 柱状图模块导入[/h2]
[h2]4. 创建元素[/h2]
因数据响应的特性,我们不需要用到操作的那套链式创建。
[h2]5. 数据与窗口大小响应[/h2]
在钩子中,我们将为窗口调整大小事件添加一个监听器,它将触发绘制动画,并将- [/code]大小设置为新窗口的比例。我们不会立即渲染,而是等待 [code]300
复制代码 毫秒,以确保完全调整窗口大小。
以下是完整的,请配合注释食用:
- import { scaleLinear, scaleBand } from "d3-scale";
复制代码- import { max, min } from "d3-array";
复制代码- import { selectAll } from "d3-selection";
复制代码- import { transition } from "d3-transition";
复制代码
- this.svgWidth = document.getElementById("container").offsetWidth * 0.75;
复制代码- this.AddResizeListener();
复制代码- return this.yScale(d[this.yKey]);
复制代码- return this.svgHeight - this.yScale(d[this.yKey]);
复制代码- window.addEventListener("resize", () => {
复制代码- this.$data.redrawToggle = false;
复制代码- this.$data.redrawToggle = true;
复制代码- document.getElementById("container").offsetWidth * 0.75;
复制代码- return max(this.data, d => {
复制代码- return min(this.data, d => {
复制代码- .rangeRound([0, this.svgWidth])
复制代码- .rangeRound([this.svgHeight, 0])
复制代码- .domain([this.dataMin > 0 ? 0 : this.dataMin, this.dataMax]);
复制代码- return this.svgWidth / 1.61803398875; // 黄金比例
复制代码- transition: r 0.2s ease-in-out;
复制代码
- [/code]
- [/list]我们将从父组件 [code]App.vue
复制代码 获取数据:
- import BarChart from "./components/BarChart.vue";
复制代码
- font-family: "Open Sans", Helvetica, Arial, sans-serif;
复制代码- -webkit-font-smoothing: antialiased;
复制代码- -moz-osx-font-smoothing: grayscale;
复制代码- [/code]
- [/list]这时候 [code]yarn run serve
复制代码 后将会看到:
好像还缺点显示数值,考虑到该图高度是根据比例尺生成,我们调整下y坐标:
- .rangeRound([this.svgHeight, 0])
复制代码- .domain([this.dataMin > 0 ? 0 : this.dataMin + 2, this.dataMax + 2]);
复制代码 在末尾添加:
最后在- [/code]元素中添加:
- [list=1][*][code]{{ item[xKey]}} {{ item[yKey]}}
复制代码- [/code]
- [/list][img]https://201907.oss-cn-shanghai.aliyuncs.com/wc/1811847-baa48749a6e55bcad1d9a8afb1f76471[/img]
- [h1]3. 参考文章[/h1]
- [img]https://201907.oss-cn-shanghai.aliyuncs.com/wc/1811847-124bd4848857866e677e58f3399f6f91[/img]
- [list][*]D3 is not a Data Visualization Library
- [*]D3中常用的比例尺
- [*]D3 vs G2 vs Echarts
- [*]Dynamic Data Visualizations With Vue.js and D3
- [/list][h1]4. 总结[/h1]该库几乎凭 [code]MikeBostock
复制代码 一人之力完成,且在学术界、专业团队中享有极大声誉。
- 更接近底层,与、不同,能直接操作,所以拥有极大的自由度,几乎可以实现任何 2d 的设计需求。
- 正如其名,其本质是将数据与绑定,并将数据映射至属性上。
- 长于可视化,而不止于可视化,还提供了、、操作等诸多功能。
- 如果有想深耕数据可视化方面的前端,不得不学。
掌握后,限制作品水平的只会是想象力而不再是技术。
源码地址:点这里
[h1]作者掘金文章总集[/h1]需要转载到公众号的喊我加下白名单就行了。
- 「真全栈之路」Web前端开发的后端指南
- 「Vue实践」5分钟撸一个Vue CLI 插件
- 「Vue实践」武装你的前端项目
- 「中高级前端面试」JavaScript手写代码无敌秘籍
- 「从源码中学习」面试官都不知道的Vue题目答案
- 「从源码中学习」Vue源码中的JS骚操作
- 「从源码中学习」彻底理解Vue选项Props
- 「Vue实践」项目升级vue-cli3的正确姿势
- 为何你始终理解不了JavaScript作用域链?
[h2] 看完三件事[/h2]如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:
- 点个「在看」,让更多的人也能看到这篇内容(喜欢不点在看,都是耍流氓 -_-)
- 关注我的 GitHub:github.com/yygmind,让我们成为长期关系
- 关注公众号「高级前端进阶」,每周重点攻克一个前端面试重难点,公众号后台回复「面试题」 送你高级前端面试题。
|
|