D3(二)

一、D3的基本使用

柱形图是一种最简单的可视化图标,主要有矩形、文字标签、坐标轴组成。那么如何使用 D3 在 SVG 画布中绘图呢?

画布是什么?

之前处理对象都是 HTML 的文字,没有涉及图形的制作。要绘图,首要需要的是一块绘图的“画布”。HTML 5 提供两种强有力的“画布”:SVG 和 Canvas。

  • SVG 绘制的是矢量图,因此对图像进行放大不会失真,可以为每个元素添加 JavaScript 事件处理器。每个图形均视为对象,更改对象的属性,图形也会改变。要注意的是,在 SVG 中的坐标轴,x 轴的正方向是水平向右,y 轴的正方向是垂直向下的。
  • 在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。

具体使用

添加画布

D3 虽然没有明文规定一定要在 SVG 中绘图,但是 D3 提供了众多的 SVG 图形的生成器,它们都是只支持 SVG 的。因此,建议使用 SVG 画布。

  1. 使用 D3 在 body 元素中添加 svg 的代码如下:
     var width = 300;  //画布的宽度
     var height = 300;   //画布的高度
    
    var svg = d3.select("body")     //选择文档中的body元素
     .append("svg")          //添加一个svg元素
     .attr("width", width)       //设定宽度
     .attr("height", height);    //设定高度
    
  2. 先在html中设置好svg的宽度和高度之后,在使用选择器将画布选中。
    <svg id="chart" class="svgs" width="1000" height="900"></svg>
    
    // 获得画布
     const svg = d3.select('#mainsvg');
    

有了画布,接下来就可以在画布上作图了。

1、柱状图



制作步骤:

  1. 使用html创建一个容器用来存放图表 : <div id="chart"></div>
  2. 使用css的样式调整最后生成的柱形图的样式
#chart div {
   display: inline-block;
   background: #4285F4;
   width: 30px;
   margin-right: 20px;
}
  1. 使用js生成每个柱形图
 d3.select('#chart')
      .selectAll("div")
      .data([100, 80, 150, 160, 230, 120])
      .enter()
      .append("div")
      .style("height", (d) => d + "px")

上述代码中的输入数据是一组数组:[10, 8, 15, 16, 23, 42],对应的输出 HTML 结构是:

所以不需要通过 JS 控制的视觉层内容都写到 CSS 中

2、GitHub 贡献表

在这里插入图片描述
我们只需要更改柱状图代码中的几行,我们就能得到一个 GitHub 贡献表。它和柱状图不同地方在于,图表中根据数据变化的不再是元素的高度,而是元素的背景色。

 var colorMap = d3.interpolateRgb(
      d3.rgb('#d6e685'),
      d3.rgb('#1e6823')
    );

    d3.select('#chart')
      .selectAll("div")
      .data([.2, .4, 0, 0, .13, .92])
      .enter()
      .append("div")
      .style("background-color", (d) => {
        return d == 0 ? '#eee' : colorMap(d);
      })

colorMap 函数接收的输入值要在0到1之间,返回的是一个颜色值,这个值是在以输入值中两两数据为颜色值之间的渐变色值,插值法是图形编程和动画的关键点。

3、圆形



D3 还可以操作更复杂的数据类型。

var data = [{
      label: "one",
      sales: 20
    }, {
      label: "two",
      sales: 12
    }, {
      label: "three",
      sales: 8
    }, {
      label: "four",
      sales: 27
    }]
 var g = d3.select('#chart')
      .selectAll("g")
      .data(data)
      .enter()
      .append('g')
    g.append("circle")
      .attr('cy', 40)
      .attr('cx', (d, i) => (i + 1) * 50)
      .attr('r', (d) => d.sales)
    g.append("text")
      .attr('y', 90)
      .attr('x', (d, i) => (i + 1) * 50)
      .text((d) => d.label)

对每一个数据点,我们都将有一个 g (组)元素在 #chart 中,根据对象的属性,每个组里会有一个 元素和一个 元素。生成的html代码如下:

<svg height="100" width="250" id="chart">
  <g>
    <circle cy="40" cx="50" r="20"/>
    <text y="90" x="50">one</text>
  </g>
  <g>
    <circle cy="40" cx="100" r="12"/>
    <text y="90" x="100">two</text>
  </g>
  <g>
    <circle cy="40" cx="150" r="8"/>
    <text y="90" x="150">three</text>
  </g>
  <g>
    <circle cy="40" cx="200" r="27"/>
    <text y="90" x="200">four</text>
  </g>
</svg>

二、坐标轴与比例尺

坐标轴是可视化图表中经常出现的一种图形,由一些列线段和刻度组成。坐标轴在 SVG 中是没有现成的图形元素的,需要用其他的元素组合构成。D3 提供了坐标轴的组件,这样在 SVG 画布中绘制坐标轴变得像添加一个普通元素一样简单。

比例尺

比例尺很像数学中的函数。D3 中的比例尺,也有定义域和值域,分别被称为 domain 和 range。我们可以指定 domain 和 range 的范围,就可以得到他们直接的关系。

  • range : 定义了可以用来绘图的区域
  • domain : 定义了轴上的最大和最小刻度值。
线性比例尺

线性比例尺,能将一个连续的区间,映射到另一区间。要解决柱形图宽度的问题,就需要线性比例尺。

例子 : 有以下数组,要求:将 dataset 中最小的值,映射成 0;将最大的值,映射成 300。代码如下:

var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];
var min = d3.min(dataset);  //0.9
var max = d3.max(dataset);  //3.3
var linear = d3.scale.linear()  //绘制X,Y 轴的刻度,可以当做函数来使用,返回一个线性比例尺
        .domain([min, max])
        .range([0, 300]);

linear(0.9);    //返回 0
linear(2.3);    //返回 175
linear(3.3);    //返回 300

由此可以看出:比例尺的定义域 domain 为:[0.9, 3.3],值域 range 为:[0, 300]。
因此,当输入 0.9 时,返回 0;当输入 3.3 时,返回 300。当输入 2.3 时呢?返回 175,这是按照线性函数的规则计算的。

绘制带坐标轴的柱形图



  1. 首先,我们使用一个svg元素来绘制我们的柱形图,这个元素在 html中。给他定义长和宽等一些常量。
 <svg id="mainsvg" class="svgs" width="1100" height="600"></svg>
  1. 这些是我们将要描述的简单的数据
 var data = [{
      name: "wen-yan",
      value: 20
    }, {
      name: "anww-ji",
      value: 6
    }, {
      name: "dre-er",
      value: 20
    }, {
      name: "drf-ff",
      value: 27
    }, {
      name: "der-ff",
      value: 30
    }];
  1. 我们用d3.select 来选择index.html 中的svg 元素。
   // 获得画布
   const svg = d3.select('#mainsvg');
   // 定义比例尺
   const width = +svg.attr('width');
   const height = +svg.attr('height');
  1. 建立X轴和Y轴要用到的数据。SVG对于D3.js来说就是一个“画布”,在SVG范围外的任何内容都属于画布之外,浏览器就不会显示。


    // 用来控制表格边框线的位置
    const margin = {
      top: 60,
      right: 30,
      bottom: 60,
      left: 80
    };
    // 计算实际操作的inner长/宽
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
  1. 基于上面这些数据,我们要建立X轴和Y轴的刻度,我们需要获取到定义这两个轴的最大和最小值。我们使用d3.scaleLinear的方法来绘制X,Y 轴的刻度,这个方法使用 rangedomain 属性来创建刻度。

    range 的值已经在上面被定义出来了,能够使图像不会在边缘过于拥挤。最大和最小值则基于之前的数据。

    // 横轴纵轴的比例尺
    const xScale = d3.scaleLinear()
      .domain([0, d3.max(data, d => d.value)]) //数据的最大值和最小值的设置
      .range([0, innerWidth]) //映射的部分
    const yScale = d3.scaleBand()
      .domain(data.map(d => d.name)) //取到data数据中的人名
      .range([0, innerHeight])
      // 设置柱状图之间的间隔
      .padding(0.1)
  1. 虽然已经定义好了刻度,但是还没有把他显示出来。D3为画轴提供了一个叫做d3.svg.axis 的API。我们就可以使用用上面定义好的刻度来绘制X,Y轴。
 const g = svg.append('g').attr('id', 'maingroup')
      .attr('transform', `translate(${margin.left},${margin.top})`) //根据上左边距离把maingroup移动到对应的位置
    // 定义坐标轴
    // 告诉坐标轴你的取值范围是如何映射
    const yAxis = d3.axisLeft(yScale)
    g.append('g').call(yAxis)

    // 横轴默认情况下会在上面展示,使用transform来把它移动到下面
    const xAxis = d3.axisBottom(xScale)
    g.append('g').call(xAxis).attr('transform', `translate(0,${innerHeight})`)



此时,就可以看到带有刻度的X轴和Y轴已经被绘制出来了,但是我们会发现X轴默认的会显示在最上面。想让它显示在最下面,可以在渲染X轴的时候添加translate属性。
7. 绘制柱状图片

// 画柱状图
    data.forEach(d => {
      g.append('rect')
        .attr("width", xScale(d.value))
        //在d3中,可以返回两个带之间的宽度 band.bandwidth() 
        .attr("height", yScale.bandwidth())
        .attr("fill", 'green')
        .attr("opacity", '.8')
        .attr("y", yScale(d.name))
    })



  1. 坐标轴上面显示的字体很小,下面就是修改坐标轴上面的字体的大小。先看看html中的文本是处在.tick 下的text中,因此使用selectAll来选中它,然后修改它的字体大小即可。
 // 修改柱状头的文字
 d3.selectAll('.tick text').attr('font-size', '1.5em')



  1. 为图表添加标题
// 添加标题
    g.append('text').text('Member of class')
      .attr('font-size', '3em')
      .attr('transform', `translate(${innerWidth/2},0)`) //文字向中间移动
      .attr("text-anchor", 'middle') //使文字居中显示
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值