d3.js一个面积图的案例(包含brush与zoom)

d3.js 一个面积图的案例(包含brush与zoom)

参考链接:http://www.a4z.cn/pui/ant-admin.html#/simple-area-chart
全局图
brush与zoom联动图
演示图

const rawData = [
      { day: '2015-01', quantity: 1240 },
      { day: '2015-02', quantity: 1905 },
      { day: '2015-03', quantity: 6232 },
      { day: '2015-04', quantity: 7545 },
      { day: '2015-05', quantity: 543 },
      { day: '2015-06', quantity: 443 },
      { day: '2015-07', quantity: 246 },
      { day: '2015-08', quantity: 5445 },
      { day: '2015-09', quantity: 1154 },
      { day: '2015-10', quantity: 448 },
      { day: '2015-11', quantity: 1545 },
      { day: '2015-12', quantity: 4585 },
      { day: '2016-01', quantity: 1520 },
      { day: '2016-02', quantity: 9015 },
      { day: '2016-03', quantity: 632 },
      { day: '2016-04', quantity: 745 },
      { day: '2016-05', quantity: 343 },
      { day: '2016-06', quantity: 6443 },
      { day: '2016-07', quantity: 546 },
      { day: '2016-08', quantity: 1545 },
      { day: '2016-09', quantity: 1354 },
      { day: '2016-10', quantity: 848 },
      { day: '2016-11', quantity: 2155 },
      { day: '2016-12', quantity: 4585 },
      { day: '2017-01', quantity: 1540 },
      { day: '2017-02', quantity: 905 },
      { day: '2017-03', quantity: 632 },
      { day: '2017-04', quantity: 745 },
      { day: '2017-05', quantity: 3543 },
      { day: '2017-06', quantity: 4443 },
      { day: '2017-07', quantity: 2546 },
      { day: '2017-08', quantity: 545 },
      { day: '2017-09', quantity: 154 },
      { day: '2017-10', quantity: 4848 },
      { day: '2017-11', quantity: 155 },
      { day: '2017-12', quantity: 4585 }
    ];
    const [svgWidth, svgHeight] = [1000, 500];
    const margin = { top: 80, right: 40, bottom: 130, left: 40 };
    const margin2 = { top: 410, right: 40, bottom: 60, left: 40 };
    const width = svgWidth - margin.left - margin.right;
    const height = svgHeight - margin.top - margin.bottom;
    const height2 = svgHeight - margin2.top - margin2.bottom;

    let chart = d3
      .select('#svg2')
      .attr('width', svgWidth)
      .attr('height', svgHeight) // 设置总宽高
    const parseDate = d3.timeParse('%Y-%m')

    const data = rawData.map(item => {
      // 把原始数据转为d3可接受的数据
      return { ...item, day: parseDate(item.day) }
    })

    let xScale = d3
      .scaleTime()
      .range([0, width])
      .domain(
        d3.extent(data, function(d) {
          return d.day
        })
      );// 设置mainChart x轴
    let x2Scale = d3
      .scaleTime()
      .range([0, width])
      .domain(xScale.domain()); // 设置subChart x轴
    let yScale = d3
      .scaleLinear()
      .rangeRound([height, 0])
      .domain([
        0,
        d3.max(data, function(d) {
          return d.quantity
        })
      ]); // 设置mainChart y轴
    let y2Scale = d3
      .scaleLinear()
      .range([height2, 0])
      .domain(yScale.domain()); // 设置subChart y轴


    // 设mainChart在最外包层在总图上的相对位置
    let mainChart = chart
      .append('g')
      .attr('class', 'main-chart')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')

    //x轴主轴
    let xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat('%Y年%m月'))
    //x轴辅轴
    let x2Axis = d3.axisBottom(x2Scale).tickFormat(d3.timeFormat('%Y年%m月'))
    //y轴主轴
    let yAxis = d3.axisLeft(yScale).ticks(10)

    //添加x轴到页面
    mainChart
      .append('g')
      .attr('class', 'axis axis--x')
      .attr('transform', 'translate(0,' + height + ')')
      .call(xAxis);
    //添加y轴到页面
    mainChart
      .append('g')
      .attr('class', 'axis axis--y')
      .call(yAxis)
      .append('text')
      .attr('y', -16)
      .attr('dy', '.71em')
      .style('text-anchor', 'middle')
      .style('fill', '#000')
      .text('销量 (千克)');
    // 画背景线
    mainChart
      .selectAll('.axis--y .tick')
      .append('line')
      .attr('class', 'bg-line')
      .attr('stroke', '#fff1c9')
      // .attr('shape-rendering', 'crispEdges')
      .attr('x2', width);
    mainChart.select('.axis--y .bg-line:last-of-type').remove()

    mainChart
      .selectAll('.axis--x .tick')
      .append('line')
      .attr('class', 'bg-line')
      .attr('stroke', '#ff0000')
      .attr('y2', -height)

    //面积图
    let mainAreaPath = d3
      .area()
      .curve(d3.curveMonotoneX)
      .x(function(d, i) {
        return xScale(d.day)
      })
      .y0(yScale(0))
      .y1(function(d, i) {
        return yScale(d.quantity)
      });

    //动画clipPath
    mainChart
      .append('defs')
      .append('clipPath')
      .attr('id', 'clip-main')
      .append('rect')
      .attr('height', height + 40)
      .attr('y', '-10')
      .attr('x', '-10')
      .attr('width', 0)
      .transition()
      .duration(2000)
      .attr('width', width + 70)

    mainChart.append('g')
      .append('path')
      .attr('class', 'area')
      .datum(data)
      .attr('d', mainAreaPath)
      .attr('stroke', 'none')
      .attr('stroke-width', 1)
      .attr('fill', 'steelblue')
      .attr('clip-path', 'url(#clip-main)')
    //添加关键点
    let circle = mainChart
      .append('g')
      .selectAll('g')
      .data(data)
      .enter()
      .append('g')
      .attr('clip-path', 'url(#clip-main)')
    circle
      .append('circle')
      .attr('cx', function(d, i) {
        return xScale(d.day)
      })
      .attr('cy', function(d, i) {
        return yScale(d.quantity)
      })
      .attr('r', '5')
      .attr('fill', 'red')

    circle
      .append('text')
      .attr('x', function(d) {
        return xScale(d.day)
      })
      .attr('dx', '1em')
      .attr('y', function(d) {
        return yScale(d.quantity)
      })
      .text(function(d) {
        return d.quantity
      })
      .attr('font-size', '10')

    let subChart = chart
      .append('g')
      // 设subChart的最外包层在总图上的相对位置
      .attr('transform', 'translate(' + margin2.left + ',' + margin2.top + ')')

    //添加x轴到页面
    subChart
      .append('g')
      .attr('transform', 'translate( 0, ' + height2 + ' )')
      .call(x2Axis)

    //subArea 面积path
    let subAreaPath = d3
      .area()
      .curve(d3.curveMonotoneX)
      .x(function(d) {
        return x2Scale(d.day)
      })
      .y0(height2)
      .y1(function(d) {
        return y2Scale(d.quantity)
      })

    //接入数据画面积图
    subChart
      .append('g')
      .append('path')
      .datum(data)
      .attr('d', subAreaPath)
      .attr('stroke', 'none')
      .attr('stroke-width', 2)
      .attr('fill', 'blue')

    /***画刷缩放部分***/
    //画刷函数
    function brushed(a, b, c) {
      if (d3.event.sourceEvent && d3.event.sourceEvent.type === 'zoom') return
      //通过事件对象获取画刷目前的长度以及位置,类似brush.move(selection, [50, 100])
      let s = d3.event.selection || x2Scale.range()
      //通过x2Scale.invert转化为新的xScale的domain
      xScale.domain(s.map(x2Scale.invert, x2Scale))
      //设置完新的xScale 重绘面积图以及x坐标轴
      mainChart.select('.area').attr('d', mainAreaPath)
      mainChart.select('.axis--x').call(xAxis)

      //选取面积图上的所有点与文字,重新赋值位置信息
      circle
        .select('circle')
        .attr('cx', function(d, i) {
          return xScale(d.day)
        })
      circle
        .select('text')
        .attr('x', function(d) {
          return xScale(d.day)
        })
    }

    //缩放函数
    function zoomed() {
      if (d3.event.sourceEvent && d3.event.sourceEvent.type === 'brush') return
      //t为随着滚轮缩放的动态比例值包含缩放信息k以及transform信息x和y
      let t = d3.event.transform
      //通过t上的rescaleX方法重新定义动态的domain且绑定至xScale
      xScale.domain(t.rescaleX(x2Scale).domain())
      //重新绘制面积图与坐标轴
      mainChart.select('.area').attr('d', mainAreaPath)
      mainChart.select('.axis--x').call(xAxis)
      //选取所有面积图上的点和文字动态修改位置信息
      circle
        .select('circle')
        .attr('cx', function(d, i) {
          return xScale(d.day)
        })
      circle
        .select('text')
        .attr('x', function(d) {
          return xScale(d.day)
        })


      //当面积图产生缩放时,让brush跟着变化大小与位置
      //s为获取的当前面积图的domain(是一个时间数组)
      let s = xScale.domain()
      //把当前的domain通过x2Scale转化为range的数字数组(即为brush的位置信息)
      let d = s.map(item => {
        return x2Scale(item)
      })
      //通过brush.move方法动态修改brush的大小与位置
      brush.move(subChart.select('.brush'), d)
    }


    //定义画刷
    let brush = d3
      .brushX()
      .extent([ [0, 0], [width, height2] ])
      .on('brush end', brushed)

    //定义缩放zoom
    let zoom = d3
      .zoom() // 设置zoom
      //设置缩放范围
      .scaleExtent([1, Infinity])
      //设置transform的范围
      .translateExtent([[0, 0], [width, height]])
      //设置缩放的视口的大小; 注:此时视口大小与transform范围一样说明无法拖动只可滚轮缩放
      .extent([[0, 0], [width, height]])
      .on('zoom end', zoomed)

    //子图
    subChart
      .append('g') // 添加画刷
      .attr('class', 'brush')
      .call(brush)
      // .call(brush.move, xScale.range())
      //初始笔刷刷取范围
      .call(brush.move, [50, 200])

    chart
      .append('g')
      .append('rect') // 添加刷放方块
      .attr('class', 'zoom')
      .attr('width', width)
      .attr('height', height)
      .attr('cursor', 'move')
      .attr('pointer-events', 'all')
      .attr('fill', 'none')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
      .call(zoom)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用d3.js生成一个简单的柱状的示例代码: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>D3.js柱状</title> <script src="https://d3js.org/d3.v6.min.js"></script> <style> .bar { fill: steelblue; } </style> </head> <body> <script> // 数据集 var dataset = [5, 10, 13, 19, 21, 25, 22, 18, 15, 13, 11, 12]; // 定义画布大小及边距 var margin = { top: 30, right: 30, bottom: 30, left: 30 }; var width = 600 - margin.left - margin.right; var height = 400 - margin.top - margin.bottom; // 创建svg元素 var svg = d3.select("body") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // 定义x轴比例尺 var xScale = d3.scaleBand() .domain(d3.range(dataset.length)) .rangeRound([0, width]) .paddingInner(0.1); // 定义y轴比例尺 var yScale = d3.scaleLinear() .domain([0, d3.max(dataset)]) .range([height, 0]); // 添加矩形 svg.selectAll(".bar") .data(dataset) .enter() .append("rect") .attr("class", "bar") .attr("x", function(d, i) { return xScale(i); }) .attr("y", function(d) { return yScale(d); }) .attr("width", xScale.bandwidth()) .attr("height", function(d) { return height - yScale(d); }); // 添加x轴 svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(xScale)); // 添加y轴 svg.append("g") .attr("class", "y axis") .call(d3.axisLeft(yScale)); </script> </body> </html> ``` 在这个示例代码,我们使用了d3.js的选择集、比例尺、坐标轴等功能来生成一个简单的柱状。具体实现过程可以参考代码注释。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值