在vue中如何封装G2图表

目录
  • vue封装G2图表
  • vue引入G2图表
    • 线上示例
    • 特性
    • 介绍一下在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

线上示例

特性

  • 完善的图形语法:数据到图形的映射,能够绘制出所有的图表;
(0)

相关推荐

  • 在vue项目中引用Antv G2,以饼图为例讲解

    我就废话不多说了,大家还是直接看代码吧~ npm install @antv/g2 --save template内容: <template> <div id="pieChart"></div> </template> js部分: ​//引入G2组件 import G2 from "@antv/g2"; ​ export default { name:"", //数据部分 data(){ retur

  • VUE引入使用G2图表的实现

    目录 关于G2图表介绍 使用 模板中使用完整代码(柱状图) 在补充一下世界地图 关于G2图表介绍 G2 是一套基于图形语法理论的可视化底层引擎,以数据驱动,提供图形语法与交互语法,具有高度的易用性和扩展性 使用 G2,可以无需关注图表各种繁琐的实现细节,一条语句即可使用 Canvas 或 SVG 构建出各种各样的可交互的统计图表 G2图表官网地址 https://antv.gitee.io/zh G2图标详细开发手册 https://antv-g2.gitee.io/zh/docs/api/ge

  • 在vue中使用G2图表的示例代码

    G2笔记 G2是蚂蚁金服的一套开源图表插件,因项目需要研究了一下,相比Echarts来说,G2文档比较难懂,网上也没有太多示例,所以在这里记录一些使用G2遇到的问题. 官方推荐在vue项目中使用Viser,它对G2进行了封装,使用起来可能更方便,又研究了一个Viser,结果Viser整个只对viser-react如何使用进行了介绍,对viser-vue一笔带过,官网是这么介绍的: 我们以 viser-react 举例写一个 chore 图为例,viser-vue 和 viser-ng 的用法类似

  • 在vue中如何封装G2图表

    目录 vue封装G2图表 vue引入G2图表 线上示例 特性 介绍一下在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',    

  • 完美解决vue 中多个echarts图表自适应的问题

    看代码吧~ <div class="echarts"> <IEcharts :option="bar" ref="echarts"></IEcharts> </div> mounted () { this.selfAdaption () }, methods: { //echarts自适应 selfAdaption () { const self = this: setTimeout(() =>

  • 详解Vue中Axios封装API接口的思路及方法

    一.axios的封装 在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中.他有很多优秀的特性,例如拦截请求和响应.取消请求.转换json.客户端防御XSRF等. 在一个项目中我们如果要使用很多接口的话,总不能在每个页面都写满了.get()或者.post()吧?所以我们就要自己手动封装一个全局的Axios网络模块,这样的话就既方便也会使代码量不那么冗余. 安装 > npm install axios //这个

  • vue中axios封装使用的完整教程

    前言 如今,在项目中,普遍采用Axios库进行Http接口请求.它是基于promise的http库,可运行在浏览器端和node.js中.此外还有拦截请求和响应.转换JSON数据.客户端防御XSRF等优秀的特性. 考虑到各个项目实际使用时写法混乱,不统一.对Axios进行一下通用化的封装,目的是帮助简化代码和利于后期的更新维护,尽量通用化. 方法如下 1. vue安装axios npm install axios -S 或者 npm i axios -S 2. 在main.js进行全局引入 imp

  • Vue中使用Echarts可视化图表宽度自适应的完美解决方案

    目录 一.问题阐述: 二.解决思路: 三.最终效果: 一.问题阐述: 开发H5项目中应用到Echarts数据可视化,由于H5主要使用在手机,屏幕宽度大大限制了图表的展现,问题如下. 上图中x轴的数据是动态的,从2022年切换到2021年数据变化,此时如果x轴的数据过多就会显得格外拥挤. 二.解决思路: 我的解决方案是,在放置Echarts的容器(div)外层再套一层容器(div),外层容器宽度固定设置手机屏幕宽,并设置溢出显示滚动条(width: 100%;overflow: auto),内层E

  • vue中手动封装iconfont组件解析(三种引用方式的封装和使用)

    目录 准备 封装 unicode引用封装 font-class引用封装 symbol引用封装 引入 全局引入 局部引入 使用 在线使用 有时候会因网络问题影响用户体验:直接放在 本地使用 ,如果过多使用也会显得繁琐,所以就可以将其封装成一个组件,也方便维护.​ 封装基于阿里巴巴图标库的项目图标. 准备 将项目内的图标下载至本地 在了路径 src/assets 下新建文件夹 iconfont ,用来存放字体图标的本地文件 解压下载到本地的字体图标文件,放到 iconfont 文件夹下 如过项目中没

  • Vue中封装input组件的实例详解

    Vue中封装input组件 最近有点忙不过来 脱了很久,没有更新 抱歉.今天要将的时如何自定义封装input组件 ,博主知识发个简单的模板 码友们可以更具自己的实际项目添加需要的参数 我的项目中的UI图是这样的 代码如下 子组件的模板设置 <template> <div class="completion-input-box"> <span class="input-box-name">{{text}}</span>

随机推荐