美文网首页
技术分享——用D3.js框架V5版本入门基础

技术分享——用D3.js框架V5版本入门基础

作者: DemoGan | 来源:发表于2019-03-28 21:10 被阅读0次

技术分享——用D3.js框架V5版本入门基础

一、前言

​ 在最近公司项目中,因为需求原因需要使用D3.js实现力导向图。所以花了一些时间对D3.js这个绘制图表的框架进行了研究。

  • 和Echarts相比D3的优势在于:

    1. 使用svg绘制图形,不依赖分辨率;
    2. 支持事件处理器,能满足交互较复杂的需求;
    3. 基于xml绘制图形,可以操作dom
  • 缺点在于:

    1. 支持IE9以上的主流浏览器,不兼容IE6 ;
    2. 复杂度高,会减慢页面的渲染速度;
    3. 学习成本大

所以对于客户需求要求的图表拥有大量的用户交互场景,可以选择用D3实现。

​ 因为项目使用的是React框架进行前端页面的开发,本编文章主要是D3在React上的实现。

二、安装和导入

  • 安装:

    npm install -save d3

  • 前段项目中导入:

    import * as d3 from 'd3';

三、Hello World

​ 老套路,第一段代码永远是伟大的hello world;

class App extends Component {

  componentDidMount() {
    let div = d3.select(this.chartRef);
    div.append("p").text("Hello World");
  }

  render() {
    return (
      <div className="App">
        <div ref={r => this.chartRef = r}></div>
      </div>
    );
  }
}

​ 可以看到d3.select()是d3的选择元素的方法,从字面意思上理解,它是选择某个dom标签然后在对这个标签进行操作。append()是d3的添加元素的方法,如上代码,意思是添加一个<p>标签然后在<p>标签里显示"Hello World"。

​ 运行效果如下:

image-20190327193727961

现力导向图-图1.png)

四、元素选择和数据绑定

4.1、元素选择

​ d3所有的操作基本都是基于dom标签进行的,所以选择元素是d3里最基本也是最重要的功能;如果没有这一步,下面的操作也进行不下去。

​ 在上一节中,我们可以看到d3.select()方法,这个方法就是d3提供的一个选择元素的方法。在d3中一共提供了连个选择元素的方法:

  1. select(selector) :选中与指定选择器字符串匹配的第一个元素,返回单元素选择结果。如果当前文档中没有匹配的元素则返回空的选择。如果有多个元素被选中,只有第一个匹配的元素(在文档遍历次序中)被选中。

  2. selectAll(selector) :选中匹配指定选择器的所有的元素。这些元素会按照文档的遍历顺序(从上到下)选择。如果当前文档中没有匹配的元素则返回空的选择。

    代码演示:

let body = d3.select("body")  //选中文档中body标签
let test1 = d3.select("#test1")  //选中id为test1的标签
let test1 = d3.select(".test1")  //选中class为test1的标签
let p = d3.select("p")  //选中文档中第一个<p>标签
let ps = d3.selectAll("p") //选中文档中所有的<p>标签

4.2、数据绑定

​ 获得选择的元素后,下一步就是要将元素绑定数据,才能绘制出相应的图表。所以数据绑定对于d3来说意识一个重要的功能。

​ d3提供了两个方法绑定数据:

  1. data() :将元素与数据绑定;

  2. datum():设置或获取元素绑定的数据集(不进行数据与元素个数的对比)。

    我们可以通过下面两个例子直观的观察他们的区别;

class App extends Component {

  componentDidMount() {
    let datas = ["a", "b", "c"]

    let div = d3.select("#secondDiv");
    let ps = div.selectAll("p").datum(datas).text(function (d, i) {
      return "第" + i + "个<p>显示" + d;
    })
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
          <p>cc</p>
        </div>
      </div>
    );
  }
}

​ 运行效果如下:


image-20190328170551010.png

​ 接下来我们再看看data()方法的效果:

class App extends Component {

  componentDidMount() {
    let datas = ["a", "b", "c"]

    let div = d3.select("#secondDiv");
    let ps = div.selectAll("p").data(datas).text(function (d, i) {
      return "第" + i + "个<p>显示" + d;
    })
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
          <p>cc</p>
        </div>
      </div>
    );
  }
}

​ 运行效果如下:


image-20190328171040167.png

​ 可以看出data()datum()的区别在于data()会将数据的个数和元素的个数进行一一对应,而datum()并不会做这种对应,它直接就将所有数据绑定在每个元素上;data()使用较多。

五、数据和元素的关系

​ 在上一节我们讲到元素的选择和数据绑定,data()方法会将数据和元素一一对应上,同时也举出了一个代码示例;但是上一节的事例,我们可以看到数据的长度和元素的个数正好是相等的,所以数据和元素是可以一一对应上的,如果情况是数据比元素多或者元素比数据多呢?不说废话,我们代码伺侯:

  1. 第一种情况,数据比元素多;
class App extends Component {

  componentDidMount() {
    let datas = ["a", "b", "c", "d"];

    let div = d3.select("#secondDiv");
    let ps = div.selectAll("p").data(datas).text(function (d, i) {
      return "第" + i + "个<p>显示" + d;
    })
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
          <p>cc</p>
        </div>
      </div>
    );
  }
}

​ 运行效果:

image-20190328171040167.png

​ 可以看到如果数据的个数比元素的个数多,那么只会展示前三个数据,而第四个数据将不展示出来。

  1. 第二种情况,元素比数据多:
class App extends Component {

  componentDidMount() {
    let datas = ["a", "b", "c"]

    let div = d3.select("#secondDiv");
    let ps = div.selectAll("p").data(datas).text(function (d, i) {
      return "第" + i + "个<p>显示" + d;
    })
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
          <p>cc</p>
          <p>dd</p>
        </div>
      </div>
    );
  }
}

​ 运行效果:


image-20190328172952264.png

​ 可以看出元素比数据多时,多出的元素会显示本身的内容,毕竟没有数据展示。

​ 我们在项目中,肯定不会去手动的修改元素的个数使元素和数据个数相等。我们肯定希望元素的个数可以根据数据的个数自动的添加和删除。为此,d3提供了三个概念:update、enter和exit;

5.1、基本概念

​ update、enter和exit的概念非常简单,要理解它们下面的一张图(非原创)就够了:

image-20190328181125747.png

​ 可以看出update就是元素和数据能够对应上的部分,而enter就是多出的数据部分,exit就是多出的元素部分。

5.2、update和enter的使用

​ 现在有个需求,是元素比数据少时,动态添加元素,并且显示多出的数据内容。

​ 代码如下:

class App extends Component {

  componentDidMount() {
    let datas = ["a", "b", "c", "d", "e"];

    let div = d3.select("#secondDiv");
    let update = div.selectAll("p").data(datas);
    let enter = update.enter().append("p");
    update.text(function (d, i) {
      return "第" + i + "个update<p>显示" + d;
    });
    enter.text(function (d, i) {
      return "第" + i + "个enter<p>显示" + d;
    })
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
          <p>cc</p>
        </div>
      </div>
    );
  }
}

​ 运行结果:

image-20190328181846279.png

let update = div.selectAll("p").data(datas);:表示获得update部分的元素;

let enter = update.enter().append("p");:表示获得enter部分,并且添加<p>标签;

5.2、update和exit的使用

​ 现在有个需求,是元素比数据多时,动态删除元素。

​ 代码如下:

class App extends Component {

  componentDidMount() {
    let datas = ["a", "b", "c"];

    let div = d3.select("#secondDiv");
    let update = div.selectAll("p").data(datas);
    let exit = update.exit();
    update.text(function (d, i) {
      return "第" + i + "个update<p>显示" + d;
    });
    exit.remove();
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
          <p>cc</p>
          <p>dd</p>
          <p>ee</p>
        </div>
      </div>
    );
  }
}

​ 运行效果:

image-20190328182513201.png

let exit = update.exit();:表示获得exit部分;

exit.remove();:删除exit部分的元素;

六、元素的添加和删除

​ 上一节我们简单的接触到了添加和删除元素的方法:append()remove()。这一节我们

将详细的了解d3中元素的添加和删除。

6.1、元素添加

​ d3提供的添加元素的方法有两个:

  1. append():在选择集的尾部添加元素;
  2. insert():在选择集的头部添加元素;

append()

class App extends Component {

  componentDidMount() {
    let div = d3.select("#secondDiv");
    let ps = div.selectAll("p");
    let newPs = ps.append("p");
    newPs.text(function (d, i) {
      return i + "";
    })
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p>aa</p>
          <p>bb</p>
        </div>
      </div>
    );
  }
}

​ 运行效果:

image-20190328192149567.png

insert()

class App extends Component {

  componentDidMount() {
    let div = d3.select("#secondDiv");
    let newP = div.insert("p", "#aa");
    newP.text("insert a new dom")
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p id="aa">aa</p>
          <p>bb</p>
        </div>
      </div>
    );
  }
}

​ 运行效果:

image-20190328195251151.png

let newP = div.insert("p", "#aa");表示在id为"aa"的元素前,添加一个<p>元素

6.2、删除元素

​ 删除元素很简单,只需要remove()方法即可。

class App extends Component {

  componentDidMount() {
    let div = d3.select("#secondDiv");
    let aa = d3.select("#aa");
    aa.remove();
  }

  render() {
    return (
      <div className="App">
        <div id="secondDiv">
          <p id="aa">aa</p>
          <p>bb</p>
        </div>
      </div>
    );
  }
}

​ 运行效果:

image-20190328200236393.png

七、画一个矩形图

​ 这一节通过之前学习的基础知识,画出一个矩形图。先不说废话,先贴出实现代码,之后最讲解:

class App extends Component {

  componentDidMount() {
    let datas = [100, 85, 30, 56, 96, 50, 66, 123, 150, 133];  //数据集,控制矩阵的高度
    let bottomMarge = 200;  //固定底部的位置
    let leftMarge = 200;  //固定最左边的位置
    let rectWidth = 30;   //矩形的宽度
    let rectMargin = 10;  //矩形之间的间距

    let svg = d3.select("svg").attr("width", "100%").attr("height", 1000); //获得svg的画布
    svg.selectAll("rect")
        .data(datas)
        .enter()
        .append("rect")     //插入矩形
        .attr("x", function (d, i) {
          return leftMarge + (i * (rectWidth + rectMargin))   //计算矩形的x坐标
        })
        .attr("y", function (d) {
          return bottomMarge - d;   //计算矩形的y坐标,保证矩形底部的位置是200
        })
        .attr("width", rectWidth)  //矩形的宽度固定为30
        .attr("height", function (d) {
          return d;    //数据对应每个矩形的高度
        })
        .attr("fill", "#f00");  //用红色填充矩形

  }

  render() {
    return (
      <div className="App">
        <svg/>
      </div>
    );
  }
}

​ 首先准备绘制需要使用的数据let datas = [100, 85, 30, 56, 96, 50, 66, 123, 150, 133];,之后在准备一些绘制所需要的必要参数:

let bottomMarge = 200;  //固定底部的位置
let leftMarge = 200;  //固定最左边的位置
let rectWidth = 30;   //矩形的宽度
let rectMargin = 10;  //矩形之间的间距

​ 数据和参数准备好后,就需要获取画布元素,这里我们使用的是svg画布:

let svg = d3.select("svg").attr("width", "100%").attr("height", 1000);

attr()方法是给元素添加一个属性,比如上面代码是给svg添加width和height属性,值分别是"100%"和1000。

​ 获得画布之后就要开始绘画矩形图,绘画时最主要的是确定绘制的位置和矩形的宽高和颜色,如下:

svg.selectAll("rect")
        .data(datas)
        .enter()
        .append("rect")     //插入矩形
        .attr("x", function (d, i) {
          return leftMarge + (i * (rectWidth + rectMargin))   //计算矩形的x坐标
        })
        .attr("y", function (d) {
          return bottomMarge - d;   //计算矩形的y坐标,保证矩形底部的位置是200
        })
        .attr("width", rectWidth)  //矩形的宽度固定为30
        .attr("height", function (d) {
          return d;    //数据对应每个矩形的高度
        })
        .attr("fill", "#f00");  //用红色填充矩形

​ 运行效果:

image-20190328203352650.png

总结

​ 以上只是d3最基本的使用方法,但是也是最重要的部分,后面的复杂的功能都是基于以上基础功能拓展的,所以一定要熟练掌握。后面还会和大家继续分享进阶部分。

相关文章

网友评论

      本文标题:技术分享——用D3.js框架V5版本入门基础

      本文链接:https://www.haomeiwen.com/subject/keqhbqtx.html