当前位置:首页 > 开发教程 > js/jQuery教程 >

在vue中如何封装G2图表

时间:2022-04-28 11:33 来源:未知 作者:不要迷恋爷 收藏

这篇文章主要介绍了在vue中如何封装G2图表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

vue封装G2图表

<template>
  <div id="id"></div>
</template>
<script>
import G2 from '@antv/g2'
import { DataSet } from '@antv/data-set'
export default {
  name: 'pie',
  data () {
    return {
      chart: null
    };
  },
  props:{
    gtwopiedata:{
      type: Array
    },
    // gtwopiecolor:{
    //   type: Array
    // },
  },
  methods:{
    g2pie(){
      if(this.chart){   // 如果存在的话就删除图表再重新生成
        this.chart.destroy()
      }
      var startAngle = - Math.PI / 2 - Math.PI / 4;
      var data = this.gtwopiedata.data;
      var ds = new DataSet();
      var dv = ds.createView().source(data);
      dv.transform({
        type: 'percent',
        field: 'value',
        dimension: 'type',
        as: 'percent'
      });
      this.chart = new G2.Chart({
        container: 'id',
        forceFit: true,
        height: this.gtwopiedata.height,
        padding: 'auto'
      });
      this.chart.source(dv);
      this.chart.legend(false);
      this.chart.coord('theta', {
        radius: 0.75,
        innerRadius: 0.5,
        startAngle: startAngle,
        endAngle: startAngle + Math.PI * 2
      });
      this.chart.intervalStack().position('value').color('type', this.gtwopiedata.color).opacity(1).label('percent', {
        offset: -20,
        textStyle: {
          fill: 'white',
          fontSize: 12,
          shadowBlur: 2,
          shadowColor: 'rgba(0, 0, 0, .45)'
        },
        formatter: function formatter(val) {
          return parseInt(val * 100) + '%';
        }
      });
      this.chart.guide().html({
        position: ['50%', '50%'],
        html: '<div class="g2-guide-html"><p class="title">'+this.gtwopiedata.title+'</p></div>'
      });
      this.chart.render();
      //draw label
      var OFFSET = 20;
      var APPEND_OFFSET = 50;
      var LINEHEIGHT = 60;
      var coord = this.chart.get('coord'); // 获取坐标系对象
      var center = coord.center; // 极坐标圆心坐标
      var r = coord.radius; // 极坐标半径
      var canvas = this.chart.get('canvas');
      var canvasWidth = this.chart.get('width');
      var canvasHeight = this.chart.get('height');
      var labelGroup = canvas.addGroup();
      var labels = [];
      // addPieLabel(this.chart);
      var halves = [[], []];
      var data = dv.rows;
      var angle = startAngle;
   
      for (var i = 0; i < data.length; i++) {
        var percent = data[i].percent;
        var targetAngle = angle + Math.PI * 2 * percent;
        var middleAngle = angle + (targetAngle - angle) / 2;
        angle = targetAngle;
        var edgePoint = this.getEndPoint(center, middleAngle, r);
        var routerPoint = this.getEndPoint(center, middleAngle, r + OFFSET);
        //label
        var label = {
          _anchor: edgePoint,
          _router: routerPoint,
          _data: data[i],
          x: routerPoint.x,
          y: routerPoint.y,
          r: r + OFFSET,
          fill: '#bfbfbf'
        };
        // 判断文本的方向
        if (edgePoint.x < center.x) {
          label._side = 'left';
          halves[0].push(label);
        } else {
          label._side = 'right';
          halves[1].push(label);
        }
      } // end of for
   
      var maxCountForOneSide = parseInt(canvasHeight / LINEHEIGHT, 10);
      halves.forEach(function(half, index) {
        // step 2: reduce labels
        if (half.length > maxCountForOneSide) {
          half.sort(function(a, b) {
          return b._percent - a._percent;
          });
          half.splice(maxCountForOneSide, half.length - maxCountForOneSide);
        }
     
        // step 3: distribute position (x and y)
        half.sort(function(a, b) {
          return a.y - b.y;
        });
        // antiCollision(half, index);
        var startY = center.y - r - OFFSET - LINEHEIGHT;
        var overlapping = true;
        var totalH = canvasHeight;
        var i = void 0;
     
        var maxY = 0;
        var minY = Number.MIN_VALUE;
        var boxes = half.map(function(label) {
          var labelY = label.y;
          if (labelY > maxY) {
          maxY = labelY;
          }
          if (labelY < minY) {
          minY = labelY;
          }
          return {
          size: LINEHEIGHT,
          targets: [labelY - startY]
          };
        });
        if (maxY - startY > totalH) {
          totalH = maxY - startY;
        }
     
        while (overlapping) {
          boxes.forEach(function(box) {
          var target = (Math.min.apply(minY, box.targets) + Math.max.apply(minY, box.targets)) / 2;
          box.pos = Math.min(Math.max(minY, target - box.size / 2), totalH - box.size);
          });
     
          // detect overlapping and join boxes
          overlapping = false;
          i = boxes.length;
          while (i--) {
          if (i > 0) {
            var previousBox = boxes[i - 1];
            var box = boxes[i];
            if (previousBox.pos + previousBox.size > box.pos) {
            // overlapping
            previousBox.size += box.size;
            previousBox.targets = previousBox.targets.concat(box.targets);
     
            // overflow, shift up
            if (previousBox.pos + previousBox.size > totalH) {
              previousBox.pos = totalH - previousBox.size;
            }
            boxes.splice(i, 1); // removing box
            overlapping = true;
            }
          }
          }
        }
     
        // step 4: normalize y and adjust x
        i = 0;
        boxes.forEach(function(b) {
          var posInCompositeBox = startY; // middle of the label
          b.targets.forEach(function() {
          half[i].y = b.pos + posInCompositeBox + LINEHEIGHT / 2;
          posInCompositeBox += LINEHEIGHT;
          i++;
          });
        });
     
        // (x - cx)^2 + (y - cy)^2 = totalR^2
        half.forEach(function(label) {
          var rPow2 = label.r * label.r;
          var dyPow2 = Math.pow(Math.abs(label.y - center.y), 2);
          if (rPow2 < dyPow2) {
            label.x = center.x;
          } else {
            var dx = Math.sqrt(rPow2 - dyPow2);
            if (!index) {
              // left
              label.x = center.x - dx;
            } else {
              // right
              label.x = center.x + dx;
            }
          }
          // drawLabel(label);
          var _anchor = label._anchor,
          _router = label._router,
          fill = label.fill,
          y = label.y;
     
          var labelAttrs = {
            y: y,
            fontSize: 12, // 字体大小
            fill: '#808080',
            text: label._data.type + '\n' + label._data.value,
            textBaseline: 'bottom'
          };
          var lastPoint = {
            y: y
          };
     
          if (label._side === 'left') {
            // 具体文本的位置
            lastPoint.x = APPEND_OFFSET;
            labelAttrs.x = APPEND_OFFSET; // 左侧文本左对齐并贴着画布最左侧边缘
            labelAttrs.textAlign = 'left';
          } else {
            lastPoint.x = canvasWidth - APPEND_OFFSET;
            labelAttrs.x = canvasWidth - APPEND_OFFSET; // 右侧文本右对齐并贴着画布最右侧边缘
            labelAttrs.textAlign = 'right';
          }
     
          // 绘制文本
          var text = labelGroup.addShape('Text', {
            attrs: labelAttrs
          });
          labels.push(text);
          // 绘制连接线
          var points = void 0;
          if (_router.y !== y) {
            // 文本位置做过调整
            points = [[_anchor.x, _anchor.y], [_router.x, y], [lastPoint.x, lastPoint.y]];
          } else {
            points = [[_anchor.x, _anchor.y], [_router.x, _router.y], [lastPoint.x, lastPoint.y]];
          }
     
          labelGroup.addShape('polyline', {
            attrs: {
              points: points,
              lineWidth: 1,
              stroke: fill
            }
          });
        });
      });
      canvas.draw();
      // this.chart.on('afterpaint', function() {
      //  addPieLabel(this.chart);
      // });
    },
    // g2获取饼图点位置
    getEndPoint(center, angle, r) {
      return {
        x: center.x + r * Math.cos(angle),
        y: center.y + r * Math.sin(angle)
      };
    }
  },
  watch: {
    gtwopiedata: function (val, oldVal) {  // 监听数据,当发生变化时,触发回调函数绘制图表,使用mounted无法正常绘制
      // if(this.dothisfun){
        this.g2pie(val);
      //   this.dothisfun = false
      // }
    }
  },
  // mounted(){
  //   this.g2pie();
  // }
}
</script>
<style scoped>
  #id{
    width: 100%;
    height: 100%;
  }
</style>

本来是想将生成的方法封装到js文件中的,但是不知道为什么,import G2 进入js文件之后,vue便会卡在92%无法继续热更新,node的cpu占用率也会饱满,所以只好封装在.vue文件中,以子组件的形式被父组件调用。

本处需要注意的第一个问题,即为data中定义的chart,如果不定义,直接用let chart = new G2.chart(),也确实能够正常生成图表,但是当数据更新的时候,便会重新渲染生成新的图表,此时页面上会同时存在多个图表,所以需要提前定义chart,并使用this.chart = new G2.chart()。

本处需要注意的第二个问题,即为使用mounted钩子函数运行此函数时,因为并未检测到数据变化,所以不会生成有效图表,所以需要使用watch监听数据变化,当发生变化的时候,执行方法渲染图表。

vue引入G2图表

G2 是一套基于图形语法理论的可视化底层引擎,以数据驱动,提供图形语法与交互语法,具有高度的易用性和扩展性。使用 G2,你可以无需关注图表各种繁琐的实现细节,一条语句即可使用 Canvas 或 SVG 构建出各种各样的可交互的统计图表;

官网地址:https://antv.gitee.io/zh

线上示例

在vue中如何封装G2图表

特性

  • 完善的图形语法:数据到图形的映射,能够绘制出所有的图表;
  • 全新的交互语法:通过触发和反馈机制可以组合出各种交互行为,对数据进行探索;
  • 强大的 View 模块:可支持开发个性化的数据多维分析图形;
  • 双引擎渲染:Canvas 或 SVG 任意切换;
  • 可视化组件体系:面向交互、体验优雅;
  • 全面拥抱 TypeScript:提供完整的类型定义文件;

介绍一下在vue中使用G2

安装G2依赖:

npm instal @antv/g2

在绘图前我们需要为 G2 准备一个 DOM 容器:

<div id="c1"></div>

执行代码:

  
  import * as G2 from '@antv/g2';  
  
  export default {
    mounted() {
           const data = [
                { genre: 'Sports', sold: 275 },
                { genre: 'Strategy', sold: 115 },
                { genre: 'Action', sold: 120 },
                { genre: 'Shooter', sold: 350 },
                { genre: 'Other', sold: 150 },
            ];
            // Step 1: 创建 Chart 对象
            const chart = new G2.Chart({
                container: 'c1', // 指定图表容器 ID
                width: 600, // 指定图表宽度
                height: 300, // 指定图表高度
            });
            // Step 2: 载入数据源
            chart.data(data);
            // Step 3:创建图形语法,绘制柱状图
            chart.interval().position('genre*sold');
            // Step 4: 渲染图表
            chart.render();
    }
  }

效果展示:

在vue中如何封装G2图表

以上为个人经验,希望能给大家一个参考,也希望大家多多支持源码搜藏网。


下一篇:没有了

js/jQuery教程阅读排行

最新文章