学习D3.js(二)基础柱状图

808 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

开始绘制

引入D3模块,创建目标节点

  <!-- 选择器模块 -->
  <script src="https://cdn.jsdelivr.net/npm/d3-selection@3"></script>

  <!-- 比例尺模块 和 依赖 -->
  <script src="https://cdn.jsdelivr.net/npm/d3-array@3"></script>
  <script src="https://cdn.jsdelivr.net/npm/d3-color@3"></script>
  <script src="https://cdn.jsdelivr.net/npm/d3-format@3"></script>
  <script src="https://cdn.jsdelivr.net/npm/d3-interpolate@3"></script>
  <script src="https://cdn.jsdelivr.net/npm/d3-time@3"></script>
  <script src="https://cdn.jsdelivr.net/npm/d3-time-format@4"></script>
  <script src="https://cdn.jsdelivr.net/npm/d3-scale@4"></script>

  <!-- 坐标轴 -->
  <script src="https://cdn.jsdelivr.net/npm/d3-axis@3"></script>
  
  <body>
    <div class="d3Chart"></div>
  </body>

创建数据

var bColor = ['#4385F4', '#34A853', '#FBBC05', '#E94335', '#01ACC2', '#AAACC2']
var dataArr = [
  {
    label: '1月',
    value: 10.5
  },
  {
    label: '2月',
    value: 70.5
  },
  {
    label: '3月',
    value: 60.5
  },
  {
    label: '4月',
    value: 10.5
  },
  {
    label: '5月',
    value: 20.5
  },
  {
    label: '6月',
    value: 30.5
  }
]

创建画布

var svg = d3
  .select('.d3Chart')
  .append('svg')
  .attr('width', 450)
  .attr('height', 440)
  .style('background-color', '#1a3055')

image.png

  1. .select() 选中与指定选择器字符串匹配的第一个元素,返回当前选中的元素结果。注意它返回的不只是这个元素节点对象,是D3封装后的选择集对象(selection)。

image.png

  1. selection.append()selection对象中的方法。用于创建html节点,返回包含追加元素的新选择对象。

image.png

  1. selection.attr(name[,value]) 获取或则设置元素的属性。
  2. selection.attr(name[,value]) 获取或则设置元素的样式属性。

绘制坐标轴

    // 创建 一个组 移动位置
    var chart = svg.append('g').attr('transform', 'translate(20, 10)')

    // 创建 序数分段比例尺 
    // 设置输出值0~400,输入为X轴的分段标题
    var xScale = d3
      .scaleBand()
      .range([0, 400])
      .domain(dataArr.map((s) => s.label))
      .padding(0.4)
    // 绘制X轴
    chart.append('g').attr('transform', 'translate(15, 400)').call(d3.axisBottom(xScale))

    // 创建 定量的线性比例尺
    var yScale = d3.scaleLinear().range([400, 0]).domain([0, 100])
    var makeYlines = () =>
      d3
        .axisLeft()
        .scale(yScale)
        .tickSize(-400)
        .tickFormat((d) => {
          return d + '%'
        })
    // 绘制Y轴
    chart.append('g').attr('transform', 'translate(15, 0)').call(makeYlines())
    // 修改颜色
    d3.selectAll('text').style('fill', '#fff')
    d3.selectAll('.d3Chart text').style('fill', '#fff')
    d3.selectAll('.d3Chart line').style('stroke', '#fff')
    d3.selectAll('.d3Chart path').style('stroke', '#fff')

image.png

  • 使用比例尺模块,对数据进行转换。然后使用坐标轴模块绘制坐标轴。最后修改坐标轴样式。
  1. d3.scaleBand() 分段比例尺。简单理解就是通过.range([0, 400])方法设置输出值域范围,通过.domain([])设置输入的分段数组。在使用时根据值域范围中的值,计算出输入为那个分段。
  2. selection.call() 调用指定的函数一次。被调用函数的this上下文也是当前的选择。简单理解就是把选择对象的this传入调用指定的函数。
  3. d3.axisBottom() 根据比例尺创建一个刻度在下的坐标轴。
  4. d3.scaleLinear() 线性比例尺。和分段比例尺不同的是,.domain([])设置的是输入值域范围。
  5. d3.axisLeft() 根据比例尺创建一个刻度在左的坐标轴。
  6. axis.tickSize() 设置刻度的长度。
  7. axis.tickFormat() 自定义标签的刻度。

绘制柱状

// 选中当前组子节点 绑定数据 创建元素占位符 对占位符创建元素
var barG = chart.selectAll().data(dataArr).enter().append('g')
barG
  .append('rect')
  .style('fill', (d, i) => bColor[i])
  .attr('x', (g, i) => xScale(g.label) + xScale.bandwidth() / 2)
  .attr('y', (g) => yScale(g.value))
  .attr('width', xScale.bandwidth())
  .attr('height', (g) => 400 - yScale(g.value))

image.png

  • 创建元素和数据绑定。
  • barG为一组选择对象,使用的方法会对每一个元素对象使用。
  • 当绑定了数据后,attr()的第二个参数可以传入一个函数,接受绑定数据。然后使用比例尺计算出柱状的位置和高度。
  1. .data() 设置一组元素的数据。
  2. .enter() 当数据和元素比匹配时,生成站位符。使用.append('g')为占位符创建元素。
  3. .bandwidth() 每一个分段的宽度。

绘制标题

barG
  .append('text')
  .style('font-size', '14px')
  .style('fill', '#fff')
  .attr('x', (g, i) => xScale(g.label) + xScale.bandwidth() / 2 + 2)
  .attr('y', (g) => yScale(g.value) - 10)
  .text((g) => `${g.value}%`)

image.png

  • 在每一个绑定了数据的元素中创建文本。使用比例尺计算文本位置。
  1. selection.text()取得或设置文本内容

创建提示框

    var tooltips = d3
      .select('body')
      .append('div')
      .style('width', '100px')
      .style('height', '40px')
      .style('background-color', '#fff')
      .style('dispaly', 'flex')
      .style('justify-content', 'center')
      .style('padding', '10px')
      .style('border-radius', '5px')
      .style('opacity', 0)
    // 对每个柱状添加交互
    barG
      .append('rect')
      ...
      .on('mouseenter', (e, g) => {
        tooltips
          .html(`月份:${g.label}<br /> 数据:${g.value}%`)
          .style('position', 'absolute')
          .style('left', `${e.clientX}px`)
          .style('top', `${e.clientY}px`)
          .style('opacity', 1)
      })
      .on('mouseleave', (e, g) => {
        tooltips.style('opacity', 0).style('left', `0px`).style('top', `0px`)
      })

4.gif

  • 在每个柱状上添加鼠标监听事件,修改提示框的位置和内容,形成交货。
  1. .html() 设置一个html文档片段。
  • 一个基础的柱状图就完成绘制了。
  • 代码地址