D3快速入门

D3安装
<script src="https://d3js.org/d3.v5.min.js"></script>
选择器
在 D3 中,用于选择元素的函数有两个,这两个函数返回的结果称为选择集。
d3.select():选择所有指定元素的第一个
d3.selectAll():选择指定全部元素
例如,选择集的常见用法如下。
var body = d3.select("body"); //选择文档中的body元素
var p1 = body.select("p");      //选择body中的第一个p元素
var p = body.selectAll("p");    //选择body中的所有p元素
var svg = body.select("svg");   //选择body中的svg元素
var rects = svg.selectAll("rect");  //选择svg中所有的rect元素
var id = body.select("#id"); //选择body中id元素
var class = body.select(".class");//选择body中class类元素

链式操作:

d3.select("#container").text("1000phone").attr("font-size","12px");

绑定数据 选择集和绑定数据通常是一起使用的,D3 中是通过以下两个函数来绑定数据的:

  1. datum():绑定一个数据到选择集上
  2. data():绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定

假设现在有三个段落元素如下:

<p></p>
<p></p>
<p></p>

对于datum(): 假设有一字符串 逆战2020,要将此字符串分别与三个段落元素绑定,代码如下:

var data = '逆战2020';
var container = d3.select("#app");
container.selectAll('p')
  .datum(data)
  .text(function (d, i) {
    return "第 " + i + " 个元素绑定的数据是: " + d;
  })

绑定数据后,使用此数据来修改三个段落元素的内容,其结果如下:

第 0 个元素绑定的数据是: 逆战2020

第 1 个元素绑定的数据是: 逆战2020

第 2 个元素绑定的数据是: 逆战2020

对于data():

有一个数组,接下来要分别将数组的各元素绑定到三个段落元素上。

var datalist = [10, 20, 30];

调用 data() 绑定数据,并替换三个段落元素的字符串为被绑定的字符串,代码如下:

var datalist = [10, 20, 30];
var container = d3.select("#app");
//更新数据
container.selectAll('p')
  //绑定数据源
  .data(datalist)
  .text(function (data, index) {
    return data;
})

结果自然是三个段落的文字分别变成了数组的三个字符串。

10
20
30

前面代码也用到了一个无名函数 function(d, i),其对应的情况如下:

d ------- data    数据
i ------- index   索引

当 i == 0 时, d 为 10。 当 i == 1 时, d 为 20。 当 i == 2 时, d 为 30。 此时,三个段落元素与数组 dataset 的三个字符串是一一对应的,在函数 function(d, i) 直接 return d 即可。

选择、插入、删除元素

1.选择元素

<p>10</p>
<p>20</p>
<p>30</p>

选择第一个元素

d3.select("body").select("p").style("color","red");

选择第所有元素

d3.select("body").selectAll("p").style("color","red");

选择第二个元素

<p id="second">20</p>
d3.select("#second").style("color","red");

选择后两个元素,给后两个元素添加 class,

<p class="myclass">Moon</p>
<p class="myclass">You</p>

由于需要选择多个元素,要用 selectAll。

d3.selectAll(".myclass").style("color","red")

插入元素 插入元素涉及的函数有两个:

append():在选择集末尾插入元素 insert():在选择集前面插入元素 假设有三个段落元素,与上文相同。

append()

d3.select("body").append("p").text("Star");

insert

d3.select("body").insert("p","#second").text("20");

删除元素

d3.select("#second").remove();

理解 update()、enter()、exit()

数据绑定的时候可能出现 DOM 元素与数据元素个数不匹配的问题,那么 enter 和 exit 就是用来处理这个问题的。enter 操作用来添加新的 DOM 元素,exit 操作用来移除多余的 DOM 元素

Update、Enter、Exit 是 D3 中三个非常重要的概念,它处理的是当选择集和数据的数量关系不确定的情况。

  1. update(), 当对应的元素正好满足时 ( 绑定数据数量 = 对应元素 ),实际上并不存在这样一个函数,只是为了要与之后的 enter 和 exit 一起说明才想象有这样一个函数。但对应元素正好满足时,直接操作即可,后面直接跟 text ,style 等操作即可。
  2. enter(), 当对应的元素不足时 ( 绑定数据数量 > 对应元素 ),当对应的元素不足时,通常要添加元素,使之与绑定数据的数量相等。后面通常先跟 append 操作。
  3. exit(), 当对应的元素过多时 ( 绑定数据数量 < 对应元素 ),当对应的元素过多时,通常要删除元素,使之与绑定数据的数量相等。后面通常要跟 remove 操作。

如果数组为 [3, 6, 9, 12, 15],将此数组绑定到三个 p 元素的选择集上。可以想象,会有两个数据没有元素与之对应,这时候 D3 会建立两个空的元素与数据对应,这一部分就称为 Enter。而有元素与数据对应的部分称为 Update。如果数组为 [3],则会有两个元素没有数据绑定,那么没有数据绑定的部分被称为 Exit。示意图如下所示。

img

而如下代码的意思是:此时 SVG 里没有 rect 元素,即元素数量为 0。有一数组 dataset,将数组与元素数量为 0 的选择集绑定后,选择其 Enter 部分(请仔细看上图),然后添加(append)元素,也就是添加足够的元素,使得每一个数据都有元素与之对应。

svg.selectAll("rect")   //选择svg内所有的矩形
    .data(dataset)      //绑定数组
    .enter()            //指定选择集的enter部分
    .append("rect")     //添加足够数量的矩形元素
1. Update和Enter的使用

当对应的元素不足时 ( 绑定数据数量 > 对应元素 ),需要添加元素(append)。 现在 body 中有三个 p 元素,要绑定一个长度大于 3 的数组到 p 的选择集上,然后分别处理 update 和 enter 两部分。

var dataset = [ 3 , 6 , 9 , 12 , 15 ];

//选择body中的p元素
var p = d3.select("body").selectAll("p");

//获取update部分
var update = p.data(dataset);

//获取enter部分
var enter = update.enter();

//update部分的处理:更新属性值
update.text(function(d){
  return "update " + d;
});

//enter部分的处理:添加元素后赋予属性值
enter.append("p")
  .text(function(d){
      return "enter " + d;
  });

页面效果:

enter 3
enter 6
enter 9
enter 12
enter 15

需要注意的是:

update 部分的处理办法一般是:更新属性值 enter 部分的处理办法一般是:添加元素后,赋予属性值

2. Update和Exit的使用

当对应的元素过多时 ( 绑定数据数量 < 对应元素 ),需要删掉多余的元素。 现在 body 中有三个 p 元素,要绑定一个长度小于 3 的数组到 p 的选择集上,然后分别处理 update 和 exit 两部分。

var dataset = [ 3 ];

//选择body中的p元素
var p = d3.select("body").selectAll("p");

//获取update部分
var update = p.data(dataset);

//获取exit部分
var exit = update.exit();

//update部分的处理:更新属性值
update.text(function(d){
    return "update " + d;
});

//exit部分的处理:修改p元素的属性
exit.text(function(d){
    return "exit";
});

//exit部分的处理通常是删除元素
// exit.remove();

需要注意的是: exit 部分的处理办法一般是:删除元素(remove)

过渡

D3 支持动画效果,这种动画效果可以通过对样式属性的过渡实现。其补间插值支持多种方式,比如线性、弹性等。此外 D3 内置了多种插值方式,比如对数值类型、字符类型路径数据以及颜色等。

启动过渡效果,与以下四个方法相关:

//创建一个过渡对象。但是由于每个选择集中都有transition()方法,可用d3.select("rect").transition()的方式来创建过渡,因此一般不直接用d3.transition()。 d3.transition([selection],[name])

//设定延迟的时间。过渡会经过一定时间后才开始发生。单位是毫秒。 transition.delay([delay])

//设定过渡的持续时间(不包括延迟时间),单位是毫秒。如:duration(2000),是持续2000ms。 transition.duration([duration])

//设定过渡样式,例如线性过渡、在目标处弹跳几次等方式。 transition.ease(vlaue[,arguments])

接下来制作一个过渡效果:

var width = 600;
var height = 400;

var svg = d3.select("#body")
            .append("svg")
            .attr("width",width)
            .attr("height",height)

svg.append("rect")
    .attr("fill","yellow")
    .attr("x",100)
    .attr("y",100)
    .attr("width",100)
    .attr("height",30)
    .transition()
    .duration(750)
    .delay(function(d, i) { return i * 10; })
    .attr("width",300)
    .attr("height",300)

除了 D3 提供的过渡之外,你也可以通过 CSS 动画来实现对元素的过渡效果。

做一个简单的图表

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./d3.v5.min.js"></script>
  <style>
    #app {
      margin: 0 auto;
      width: 500px;
      height: 400px;
      background: #efefef;
      position: relative;
    }

    .bar {
      width: 30px;
      /* height: 50px; */
      background: green;
      position: absolute;
      bottom: 100px;
    }

    .bar span {
      display: block;
      text-align: center;
    }
  </style>
</head>

<body>
  <div id="app">
    <!-- <div class="bar"></div> -->
  </div>

  <script>

    var datalist = [10, 20, 30, 40, 50];
    var container = d3.select("#app");

    container.selectAll('div')
      .data(datalist)
      .enter()
      .append('div')
      .classed('bar', true)
      .style('height', function (d, i) {
        return d * 5 + 'px';
      })
      .style('left', function (d, i) {
        return i * 35 + 'px';
      })
      .append('span')
      .text(function (d) {
        return d;
      })
      .style('color', function (d) {
        if (d > 30) {
          return 'red';
        }
      })
  </script>

</body>

</html>

svg基础

https://developer.mozilla.org/zh-CN/docs/Web/SVG https://www.d3js.org.cn/svg/get_start/

常用标签

Rect Ellipse     Line     Circle   polygon  polyline  
path Text    defs    g    use  Animate
<svg width="500" height="500" style="background: #efefef;">

    <!-- <rect x="50" y="100" width="100" height="50" fill="red" style="" stroke="blue" stroke-width="5" /> -->

    <!-- <ellipse cx="200" cy="200" rx="50" ry="100" style="fill:orange; stroke: orangered; stroke-width: 5px;" /> -->

    <!-- <line x1="50" y1="50" x2="450" y2="450" stroke="red" stroke-width="3" /> -->


    <!-- <circle cx="225" cy="225" r="100" style="fill:peru;" /> -->

    <!-- <polygon points="50,20 150,60  120,200  100,200" style="fill:pink;" fill="none" stroke="red" stroke-width="5" /> -->

    <!-- <!-- <polyline points="10,20 50,60  120,200  200,300" fill="blue" stroke="red" stroke-width="5"></polyline> -->
    -->

    <!-- <path d="M30,30 L200,200  L230,260" fill="none" stroke="green" stroke-width="5" />

   -->

    <!-- <defs>

      <g id="group">
        <rect x="50" y="100" width="100" height="50" style="fill:green;" stroke="blue" stroke-width="5">

          <animate attributeName="opacity" from="1" to="0" dur="5s" repeatCount="indefinite" />
        </rect>
        <circle cx="225" cy="225" r="100" style="fill:peru;">

          <animate attributeName="cx" from="225" to="100" dur="5s" repeatCount="indefinite" />
        </circle>
      </g>

    </defs> -->

    <!-- <use xlink:href="#group" x="30" y="30" />
    <use xlink:href="#group" x="130" y="130" /> -->

    <!-- <text x="200" y="200" style="fill: none; stroke: red; stroke-width: 1; font-size: 45px;">NZGP1916</text> -->


    <clipPath id="myClipPath">
      <rect width="200" height="100" x="200" y="200"></rect>
    </clipPath>

    <circle cx="260" clip-path="url(#myClipPath)" cy="260" r="100" style="" />

  </svg>

将图表标签更换成svg

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./d3.v5.min.js"></script>
  <style>
    #app {
      margin: 0 auto;
      width: 500px;
      height: 400px;
      background: #efefef;
      position: relative;
    }

    .bar {
      width: 30px;
      /* height: 50px; */
      fill: green;
      position: absolute;
      bottom: 100px;
    }

    .bar span {
      display: block;
      text-align: center;
    }
  </style>
</head>

<body>
  <svg id="app" style="width: 500px; height:400;">
    <!-- <div class="bar"></div> -->
  </svg>

  <script>

    var datalist = [10, 20, 30, 40, 50];
    var container = d3.select("#app");

    container.selectAll('rect')
      .data(datalist)
      .enter()
      .append('rect')
      .classed('bar', true)
      .style('height', function (d, i) {
        return d * 5 + 'px';
      })
      .attr('x', function (d, i) {
        return i * 35 + 'px';
      })
      .attr('y', function (d, i) {
        return 400 - d * 5 - 20 + 'px';
      })
      .style('color', function (d) {
        if (d > 30) {
          return 'red';
        }
      })



    container.selectAll('text')
      .data(datalist)
      .enter()
      .append('text')
      .attr('text-anchor', 'middle')
      .text(function (d) {
        return d;
      })
      .attr('x', function (d, i) {
        return i * 35 + 15 + 'px';
      })
      .attr('y', function (d, i) {
        return 400 - d * 5 - 20 + 'px';
      })
      .style('color', function (d) {
        if (d > 30) {
          return 'red';
        }
      })

  </script>

</body>

</html>

results matching ""

    No results matching ""