美文网首页React
React中d3(v4)的饼状图绘制与数据更新

React中d3(v4)的饼状图绘制与数据更新

作者: 2f1b6dfcc208 | 来源:发表于2018-05-11 12:20 被阅读3次

类似页面如下:


屏幕截图.png

平时在各个页面中可能会遇到类似的饼状图显示,这里采用d3 (v4版) 绘制,就上面的饼状图可以抽象成一个通用的React组件,使用时只需要传入数据源即可,另外,更新操作也已经封装,直接更新传入的数据源即可。

  • 将d3中的饼状图封装成一个ES6的类
//饼状图类
export default class PieChart {
  constructor(
    wrapper,
    dataSource,
    color,
    width = wrapper.offsetWidth,
    height = wrapper.offsetHeight
  ) {
    this.wrapper = wrapper; //容器元素
    this.dataSource = this.handleDataBefore(dataSource);
    this.width = width;
    this.height = height;
    this.radius = Math.min(this.width, this.height) / 2;
    this.color = d3
      .scaleOrdinal()
      .domain(d3.range(this.handleColorBefore(color).length))
      .range(this.handleColorBefore(color)); 

    this.initChart();
  }

  // 添加默认显示
  handleDataBefore(data) {
    const total = data.reduce((total, current) => (total + current.count), 0)
    if (total === 0) {
      data[data.length] = { region: 'default', count: 1 };
    } else {
      data[data.length] = { region: 'default', count: 0 };
    }
    return data;
  }
  // 添加默认颜色显示
  handleColorBefore(color) {
    color[color.length] = '#B6B9C2';
    return color;
  }

  initChart() {
    const pie = d3
      .pie()
      .value(function (d) {
        return d.count;
      })
      .padAngle(0.02)
      .sort(null);
    const arc = d3
      .arc()
      .innerRadius(this.radius * 0.85)
      .outerRadius(this.radius)
      .cornerRadius(5);
    const svg = d3
      .select(this.wrapper)
      .append('svg')
      .attr('width', this.width)
      .attr('height', this.height)
      .attr('viewBox', '0 0 ' + this.width + ' ' + this.height) //当宽高改变时,图表响应式
      .attr('style', 'width:100%')
      .append('g')
      .attr(
        'transform',
        'translate(' + this.width / 2 + ',' + this.height / 2 + ')'
      );
    this.pie = pie;
    this.arc = arc;
    this.svg = svg;
    this.drawChart(this.dataSource);
  }
  drawChart(data) {
    const color = this.color;
    const pie = this.pie;
    const arc = this.arc;
    const svg = this.svg;

    let path = svg.selectAll('path');
    const data0 = path.data();
    const data1 = pie(data);

    path = path.data(data1, key);

    path
      .transition()
      .duration(800)
      .attrTween('d', arcTween);

    path
      .enter()
      .append('path')
      .each(function (d, i) {
        var narc = findNeighborArc(i, data0, data1, key);
        if (narc) {
          this._current = narc;
          this._previous = narc;
        } else {
          this._current = d;
        }
      })
      .attr('fill', (d, i) => {
        return color(i);
      })
      .transition()
      .duration(600)
      .attrTween('d', arcTween);

    path
      .exit()
      .transition()
      .duration(300)
      // .delay(2000)
      .attrTween('d', function (d, index) {
        var currentIndex = this._previous.data.region;
        var i = d3.interpolateObject(d, this._previous);
        return function (t) {
          return arc(i(t));
        };
      })
      .remove();

    function key(d) {
      return d.data.region;
    }

    function findNeighborArc(i, data0, data1, key) {
      var d;
      if ((d = findPreceding(i, data0, data1, key))) {
        const obj = cloneObj(d);
        obj.startAngle = d.endAngle;
        return obj;
      } else if ((d = findFollowing(i, data0, data1, key))) {
        const obj = cloneObj(d);
        obj.endAngle = d.startAngle;
        return obj;
      }
      return null;
    }

    // Find the element in data0 that joins the highest preceding element in data1.
    function findPreceding(i, data0, data1, key) {
      const m = data0.length;
      while (--i >= 0) {
        var k = key(data1[i]);
        for (var j = 0; j < m; ++j) {
          if (key(data0[j]) === k) return data0[j];
        }
      }
    }

    // Find the element in data0 that joins the lowest following element in data1.
    function findFollowing(i, data0, data1, key) {
      const n = data1.length,
        m = data0.length;
      while (++i < n) {
        const k = key(data1[i]);
        for (var j = 0; j < m; ++j) {
          if (key(data0[j]) === k) return data0[j];
        }
      }
    }

    function arcTween(d) {
      const i = d3.interpolate(this._current, d);
      this._current = i(0);
      return function (t) {
        return arc(i(t));
      };
    }

    function cloneObj(obj) {
      const o = {};
      for (var i in obj) {
        o[i] = obj[i];
      }
      return o;
    }
  }
  updateChart(data) {
    this.drawChart(this.handleDataBefore(data));
  }
  destory() {
    d3.select(this.wrapper).remove(); //移除图表元素
  }
}

  • 封装为React通用组件
import React from 'react';
import Chart from './pie.js';

import PropTypes from 'prop-types';

export default class PieChart extends React.PureComponent {
  static propTypes = {
    id: PropTypes.string.isRequired,
    dataSource: PropTypes.array.isRequired,
    color: PropTypes.array.isRequired,
    width: PropTypes.number,
    height: PropTypes.number
  }
  constructor(props) {
    super(props);
    this.chartRef = true;
  }
  componentWillUnmount() {
    this.destoryChart();
    this.chartRef = false;
  }
  componentWillReceiveProps(nextProps) {
    if (nextProps.dataSource !== this.props.dataSource) {
      this.updateChart(nextProps);
    }
  }
  drawChart = node => {
    if (this.chartRef) {
      const { dataSource, color } = this.props;
      this.chart = new Chart(node, dataSource, color);
    }
  };
  updateChart = props => {
    this.chart.updateChart(props.dataSource);
  };
  destoryChart = () => {
    this.chart.destory();
    this.chart = null;
  };
  render() {
    const { id, width = 135, height = 120 } = this.props;
    return <div id={id} style={{ width, height }} ref={this.drawChart} />;
  }
}

  • 使用
import React from 'react';
import PieChart from 'components/PieChart'

export default class Demo extends React.Component{
    state={
        inline:380,
        outline:120
    }
    render(){ 
        const {inline,outline}=this.state;
        const dataSource = [
                { region: 'inline', count: inline },
                { region: 'outline', count: outline }
            ]
        const color=['#fa919c', '#f83d59'];
        return(
            <div>
                <PieChart id='device' dataSource={dataSource} color={color} />
            </div>
        )
    }
}

github地址:https://github.com/Hfimy/component/tree/master/components/PieChart

相关文章

  • React中d3(v4)的饼状图绘制与数据更新

    类似页面如下: 平时在各个页面中可能会遇到类似的饼状图显示,这里采用d3 (v4版) 绘制,就上面的饼状图可以抽象...

  • charts3

    先进行charts饼状图的小测,如下,结果为正常饼状图 绘制前面数据库中的数据来找某一天交易的各类目物品的饼状图 ...

  • iOS CGContextRef

    一、绘制饼状图 饼状图的简单实现代码:

  • 数据可视化D3js 之饼状图与交互

    今天是关于一个d3画饼状图的一个简单剖析和讲解。(本次用例是基于Vue和D3 v4)在画图之前,首先,我们来了解...

  • 手把手教你Tableau绘制饼图(五)

    手把手教你 Tableau 绘制饼图 饼图常用于显示数据中个体相对于整体的比例。 绘制酒店价格等级饼图 数据展示 ...

  • Fig1-b 绘制环形图和饼图并拼接在一起 2021-01-03

    1. 绘制环形图: 安装需要的包: 数据准备与作图: 绘制环形图: 得到: 2. 绘制饼图: 数据准备: 绘制柱状...

  • D3.js ------ Layout

    D3 总共提供了 12 个布局:饼状图(Pie)、力导向图(Force)、弦图(Chord)、树状图(Tree)、...

  • matplotlib绘制图表

    python中使用matplotlib库可以快速画简单的图表下面介绍下柱状图和饼图绘制1 柱状图绘制 2 饼状图绘...

  • 学习笔记----python绘图pie

    # python 绘制饼状图 #-*- coding:utf-8 –*- import matplotlib.py...

  • ggplot2优雅的绘制饼状热图

    欢迎关注R语言数据分析指南 最近看到一张非常有意思的图,暂且称之为饼状热图,与corrplot所绘制的有所不同此图...

网友评论

    本文标题:React中d3(v4)的饼状图绘制与数据更新

    本文链接:https://www.haomeiwen.com/subject/cpfnzxtx.html