D3 简单入门

484 阅读3分钟

现在,市面上各种操作图形的,例如hightchart、echarts等,虽然能做很多效果,但是局限性就是很难去定制。

D3.js不是通过json配置的方式来制作图表,而是通过提供一些简化操作的api来操作svg,canvas等。可以把D3形象理解为:SVG中的jQuery。

select:选择符合条件的第一个元素

selectAll:选择符合条件的全部元素集

data():用来绑定数据

d3.select("body").style("background-color", "black");  // 直接选择 ->并设置属性
d3.selectAll("p").style("color", function() { // 选择 -> 动态设置属性
  return "hsl(" + Math.random() * 360 + ", 100%, 50%)";
});
d3.selectAll("p") // 选择 -> 绑定数据 -> 动态设置属性
  .data([4, 8, 15, 16, 23, 42])
  .style("font-size", function(d) { return d + "px"; }); // function(d)为遍历data的数据

上面的例子,通过data()绑定数据后,就可以通过function(d) { return ...}来遍历data中的数据,使数据表现到样式上

操作svg:

// 把所有圆圈改变半径
d3.selectAll(".circle").transition() // 定义动画
  .duration(750) // 动画持续时间
  .delay(function(d, i) { return i * 10; }) // 元素动画要延时多少时间开始
  .attr("r", "6"}); // 设置半径

上面的例子,通过attr给圆形加半径,通过 transition加动画效果

一个简单的图像生成器: 引入d3.js,选择

下的div集合,然后绑定数据data[]后,根据data改变他们的样式width,并通过.text()在div中插入文字

情况一(data=dom): 当dom上的

下已经放好了6个div标签,而data数组也刚好是6个时,符合data=dom

<html>
<head>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div id="dashboard">
    <p>Earnings</p>
    <div class="chart">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>
<script>
var data = [30, 86, 168, 281, 303, 565];
var chartData = d3.select(".chart")
  .selectAll("div")
  .data(data)  // 可以抽出一个变量chartData
 
chartData
  .style("width", function(d) { return d + 'px' })
  .text(function(d) { return '$ ' + d; });
</script>
</body>
</html>

情况二(data>dom): 如果data数据是异步的,我们就没办法事先知道data数组的具体个数,这时我们需要enter(),enter特指 数据已经存在但是当前DOM元素中还不存在的每个数据元素的占位符节点。文字描述不好理解,可以看下面例子来结合理解

<html>
<head>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div id="dashboard">
    <p>Earnings</p>
    <div class="chart">
      <!-- <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div> -->
    </div>
  </div>
<script>
var data = [30, 86, 168, 281, 303, 565];
 
var chartData = d3.select(".chart")
.selectAll("div")
.data(data)  // 可以抽出一个变量chartData
 
chartData
  .enter()
  .append("div")
  .style("width", function(d) { return d + 'px' })
  .text(function(d) { return '$ ' + d; });
</script>
</body>
</html>

<div class="chart">下已经没有div标签,这时我们用了enter(),就可以指代data存在但是dom上不存在的数据,所以页面能达到相同的效果。需要注意的是,如果<div class="chart">下已经有6个div了,那enter()就会不起效果,所以这个例子chart下6个div必须注销掉,enter()才能执行

情况三(data<dom):

如果<div class="chart">下的div太多了,这时需要exit来选中多余的dom,并通过remove去除掉。

<html>
<head>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div id="dashboard">
  <p>Earnings</p>
    <div class="chart">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>
<script>
var data = [30, 86, 168, 281, 303, 565];

var chartData = d3.select(".chart")
  .selectAll("div")
  .data(data)  // 可以抽出一个变量chartData

chartData
  .style("width", function(d) { return d + 'px' })
  .text(function(d) { return '$ ' + d; });

chartData.exit().remove() //去除多余的div
</script>
</body>
</html>

以下就是这个图形生成器的基本行为,如果data>dom,就要用enter来增加dom元素;如果data<dom,就要用exit来减少多余元素,最终保持每次更新视图都保证data和dom的同步。

所以图形生成器的最终代码为:

var data = [30, 86, 168, 281, 303, 565];
var chartData = d3.select(".chart")
 .selectAll("div")
 .data(data)
 
// 图形生成器
function update(){
  chartData      // 随着data数据变化更新视图元素
   .style("width", function(d) { return scale(d) + 'px' })
   .text(function(d) { return '$ ' + d; });
 
  chartData
   .enter()      // 当data数据增加后添加视图元素
   .append("div")
   .style("width", function(d) { return scale(d) + 'px' })
   .text(function(d) { return '$ ' + d; });
 
  chartData.exit().remove()   // 当data数据减少后移除视图元素
}
update()

图形生成器完成后,接下来我们只要更新数据,再执行生成器,页面上的视图就会跟着变化。