D3.js 与 React.js

Posted web开发技术杂谈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D3.js 与 React.js相关的知识,希望对你有一定的参考价值。

本文简单总结一下 d3(v4) 在 react 中如何使用,如果你还不知道 d3.js 是什么,请移步 d3.js。 d3.js 官方样例中的用法都是类似

 
   
   
 
  1. d3.select("body")

  2.  .selectAll("p")

  3.  .data([4, 8, 15, 16, 23, 42])

  4.  .enter().append("p")

  5.    .text(function(d) { return "I’m number " + d + "!"; });

确实很简明,但是在 react 中却没法下手,所以在 react 中,只需将 d3.js 视为提供图形算法的库即可,不需要掌握如何使用 d3.js 操作 dom。

使用 svg 画一个 bar 图

我们先使用 svg 来画一个最简单的没有坐标轴的 bar 图,理解一下 d3 与 react 的分工。

首先假设我们的 bar 图大小为 1280(px) * 800(px),数据是

 
   
   
 
  1. const data = [

  2.  { city: '北京', amount: 1000, },

  3.  { city: '上海', amount: 803, },

  4.  { city: '广州', amount: 440, },

  5.  { city: '深圳', amount: 780, },

  6. ];

然后我们需要理解 bar 图是如何构成(画)的,bar 图有两个坐标轴:

  • 横轴为分组,对应 city ,决定每根柱子的 x 位置

  • 竖轴为数值,对应 amount,决定每根柱子的高度即 y 的位置

d3 处理图形的算法和坐标计算很方便,使用 d3.scaleBand 将 city 与图的宽度(1280px) 做出映射关系:

 
   
   
 
  1. const xAxis = d3.scaleBand()

  2.  .range([0, 1280])

  3.  .domain(['北京', '上海', '广州', '深圳'])

就可以用 xAxis('上海') 得到 上海这根柱子的 x 位置。每根柱子的宽度使用 xAxis.bandwidth() 获得。

使用 d3.scaleLinear 将 amount 与图的高度(800px) 做出映射关系:

 
   
   
 
  1. const yAxis = d3.scaleLinear()

  2.  .range([800, 0])

  3.  .domain([0, 1000])

就可以用 yAxis(803) 得到 上海这根柱子的高度 y 位置。请注意 range([800,0]),之所以是反向的,是因为 svg 的纵坐标系是反向的,而且 canvas 的纵坐标系也是反向的。

接下来创建我们的组件

 
   
   
 
  1. import * as d3 from 'd3';

  2. import React, { PureComponent } from 'react';

  3. const width = 1280;

  4. const height = 800;

  5. const data = [

  6.  { city: '北京', amount: 1000, },

  7.  { city: '上海', amount: 803, },

  8.  { city: '广州', amount: 440, },

  9.  { city: '深圳', amount: 780, },

  10. ];

  11. const xAxis = d3.scaleBand()

  12.  .range([0, 1280])

  13.  .domain(['北京', '上海', '广州', '深圳']);

  14. const yAxis = d3.scaleLinear()

  15.  .range([800, 0])

  16.  .domain([0, 1000]);

  17. const barWidth = xAxis.bandwidth();

  18. class Bar extends PureComponent {

  19.  render() {

  20.    return <svg width={width} height={height}>

  21.      {data.map(({ city, amount }, index) => {

  22.        const x = xAxis(city);

  23.        const y = yAxis(amount);

  24.        const barHeight = height - y;

  25.        return <rect

  26.          key={index}

  27.          x={x}

  28.          y={y}

  29.          width={barWidth}

  30.          height={barHeight}

  31.          fill={'#bada55'} />;

  32.      })}

  33.    </svg>;

  34.  }

  35. }

这样就完成了一个最简单的(正数) bar 图,需要注意的是其中计算 barHeight 的时候并没有判断 amount 为负数的情况,且没有处理各种边界错误。

性能

上边的例子中我们是直接 map 数据,创建了 n 个 rect 元素,当数据量上千后,性能会下降,不如改为 canvas 画法,使用 canvas 画的逻辑也是一样的,d3.js 只负责图形算法和坐标计算。

不同的是 canvas 无法像 svg 一样直接在 render 函数中画,需要在 componentDidMount 之后执行画图的逻辑。

 
   
   
 
  1. class Bar extends PureComponent {

  2.  render() {

  3.    return <canvas

  4.      width={width}

  5.      height={height}

  6.      ref={r => this.canvas = r} />;

  7.  }

  8.  componentDidMount() {

  9.    const ctx = this.canvas.getContext('2d');

  10.    ctx.fillStyle = '#bada55';

  11.    data.map(({ city, amount }, index) => {

  12.      const x = xAxis(city);

  13.      const y = yAxis(amount);

  14.      const barHeight = height - y;

  15.      ctx.beginPath();

  16.      ctx.fillRect(x, y, barWidth, barHeight);

  17.      ctx.closePath();

  18.    });

  19.  }

  20. }

总结

通过上边两个例子,相信你已经可以使用 svgcanvas 通过 d3.jsreact 中画出常用的基本可视化图形了。

在项目中,无论是你是要用 d3 自己画图,还是用 echarts/g2/highcharts,重要的是理解图形是如何组成的,如何画出来的,方法有很多。


以上是关于D3.js 与 React.js的主要内容,如果未能解决你的问题,请参考以下文章

在我的 React.js 应用程序中导入 D3.js 库时出错

html D3byEX 9.6:甜甜圈片段(改编自D3.js v4)

将 d3.js 与 Apache Zeppelin 一起使用

如何在 d3.js 中同时自动移动节点和链接

D3.js 力导向图的拖拽(drag)与缩放(zoom)

使d3.js与ie兼容