vue+antv g2+element-ui实现图表的增添拖拽

vue+antv g2+element-ui实现图表的增添拖拽_第1张图片

html

<template>
  <div class="app-container dashboard">
    
    <el-popover placement="left" width="30%" trigger="click" class="btn-add">
      <el-collapse v-model="activeNames">
        <el-collapse-item v-for="item in projectList" :key="item.key" :title="item.title" :name="item.key">
          <div v-for="row in item.list" :key="row.key">
            <el-switch v-model="row.isShow" :active-text="row.name" @change="isShow(row)">el-switch>
          div>
        el-collapse-item>
      el-collapse>
      <el-button type="primary" icon="el-icon-plus" slot="reference" circle>el-button>
    el-popover>
    

    <div id="canvas">
      <div class="item" v-for="(item, index) in divList" :key="index" draggable="true" :id="item.key"
        @dragstart="handleDragStart($event, item)"
        @dragenter="handleDragEnter($event, item)"
        @dragover.prevent="handleDragover($event, item)"
        @drop="handleDrop($event, item)"
        @dragend="handleDragEnd($event, item)">
      div>
    div>
  div>
template>

js

<script>
// 生成图表
import dashboardChart from './chart/dashboardChart'

export default {
  name: 'dashboard',
  data() {
    return {
      divList: [],
      projectList: [],
      activeNames: [],
      dragging: null
    }
  },
  mounted() {
    this.getList()
  },
  methods: {
    // 获取已保存的图表
    getList() {
      this.projectList = [
        {
          title: '申请环节',
          key: '1',
          list: [
            { name: '累计放款VS预估值', key: 'estimate', type: 'dashboard', color: '#1890FF', value: 0.1, isShow: false },
            { name: '累计放款VS余额', key: 'totalBalance', type: 'dashboard', color: '#95DE64', value: 0.2, isShow: false }
          ]
        }
      ]
      for (const i in this.projectList) {
        const project = this.projectList[i]
        this.activeNames.push(project.key)
        // 遍历出已经选择的图表
        for (const j in project.list) {
          const one = project.list[j]
          // 把选择的图表在页面渲染出来
          if (one.isShow === true) {
            this.divList.push(one)
            this.$nextTick(() => {
              this.getChart(one)
            })
          }
        }
      }
    },
    // 在页面新增或删除图表
    isShow(row) {
      // 新增
      if (row.isShow === true) {
        this.divList.push(row)
        this.$nextTick(() => {
          this.getChart(row)
        })
      // 删除
      } else {
        for (const i in this.divList) {
          if (row.key === this.divList[i].key) {
            this.divList.splice(i, 1)
          }
        }
        this.$nextTick(() => {
          for (const j in this.divList) {
            document.getElementById(this.divList[j].key).innerHTML = ''
            this.getChart(this.divList[j])
          }
        })
      }
    },
    // 生成图表
    getChart(row) {
      if (row.type === 'dashboard') {
        const value = [
          { value: row.value }
        ] 
        dashboardChart(row.key, value, row.color, row.name)
      }
    },
    // 当元素被拖动时
    handleDragStart(e, item) {
      this.dragging = item
    },
    // 当被鼠标拖动的对象进入其容器范围内时触发此事件
    handleDragEnter(e) {
      // 为需要移动的元素设置dragstart事件
      e.dataTransfer.effectAllowed = 'move'
    },
    // 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
    handleDragover(e) {
      // 首先把div变成可以放置的元素,即重写dragenter/dragover
      // 在dragenter中针对放置目标来设置!
      e.dataTransfer.dropEffect = 'move'
    },
    // 当放置被拖元素时
    handleDrop(e, item) {
      e.dataTransfer.dropEffect = 'move'
      if(item === this.dragging){
        return
      }
      const newItems = [...this.divList]
      const from = newItems.indexOf(this.dragging)
      const to = newItems.indexOf(item)
      newItems[from] = item
      newItems[to] = this.dragging
      this.divList = newItems
      document.getElementById(this.dragging.key).innerHTML = ''
      document.getElementById(item.key).innerHTML = ''
      this.$nextTick(() => {
        this.getChart(newItems[from])
        this.getChart(newItems[to])
      })
    },
    // 完成元素拖动后触发
    handleDragEnd() {
      this.dragging = null
    }
  }
}
</script>

dashboardChart

import G2 from '@antv/g2'

/**
 * 仪表盘
 * @param {*} id 容器
 * @param {*} data 数据
 * [{ value: 0.5 }]
 * @param {*} color 颜色
 * @param {*} title 标题
 */
function draw(id, data, color, title) {
  var Shape = G2.Shape;
  // 自定义Shape 部分
  Shape.registerShape('point', 'pointer', {
    drawShape: function drawShape(cfg, group) {
      var center = this.parsePoint({ // 获取极坐标系下画布中心点
        x: 0,
        y: 0
      });
      // 绘制指针
      group.addShape('line', {
        attrs: {
          x1: center.x,
          y1: center.y,
          x2: cfg.x,
          y2: cfg.y,
          stroke: cfg.color,
          lineWidth: 3,
          lineCap: 'round'
        }
      });
      return group.addShape('circle', {
        attrs: {
          x: center.x,
          y: center.y,
          r: 8,
          stroke: cfg.color,
          lineWidth: 2.5,
          fill: '#fff'
        }
      });
    }
  });

  var chart = new G2.Chart({
    container: id,
    forceFit: true,
    height: 250,
    padding: 'auto'
  });
  chart.source(data);

  chart.coord('polar', {
    startAngle: -10 / 8 * Math.PI,
    endAngle: 2 / 8 * Math.PI,
    radius: 0.75
  });
  chart.scale('value', {
    min: 0,
    max: 1,
    nice: false,
    ticks: [0.1, 0.3, 0.5, 0.7, 0.9]
  });

  chart.axis('1', false);
  chart.axis('value', {
    zIndex: 2,
    line: null,
    label: {
      offset: -15,
      formatter: function formatter(val) {
        if (val === '0.1') {
          return '10%';
        } else if (val === '0.3') {
          return '30%';
        } else if (val === '0.5') {
          return '50%';
        } else if (val === '0.7') {
          return '70%';
        } else if (val === '0.9') {
          return '90%';
        }
      },
      textStyle: {
        fontSize: 14,
        textAlign: 'center'
      }
    },
    tickLine: null,
    grid: null
  });
  chart.legend(false);
  chart.point().position('value*1').shape('pointer').color(color).active(false);

  // 绘制仪表盘刻度线
  chart.guide().line({
    start: [0.1, 0.95],
    end: [0.1, 0.85],
    lineStyle: {
      stroke: color, // 线的颜色
      lineDash: null, // 虚线的设置
      lineWidth: 2
    }
  });

  chart.guide().line({
    start: [0.3, 0.95],
    end: [0.3, 0.85],
    lineStyle: {
      stroke: color, // 线的颜色
      lineDash: null, // 虚线的设置
      lineWidth: 2
    }
  });

  chart.guide().line({
    start: [0.5, 0.95],
    end: [0.5, 0.85],
    lineStyle: {
      stroke: color, // 线的颜色
      lineDash: null, // 虚线的设置
      lineWidth: 2
    }
  });

  chart.guide().line({
    start: [0.7, 0.95],
    end: [0.7, 0.85],
    lineStyle: {
      stroke: color, // 线的颜色
      lineDash: null, // 虚线的设置
      lineWidth: 2
    }
  });

  chart.guide().line({
    start: [0.9, 0.95],
    end: [0.9, 0.85],
    lineStyle: {
      stroke: color, // 线的颜色
      lineDash: null, // 虚线的设置
      lineWidth: 2
    }
  });

  // 绘制仪表盘背景
  chart.guide().arc({
    zIndex: 0,
    top: false,
    start: [0, 0.965],
    end: [1, 0.965],
    style: { // 底灰色
      stroke: '#F5F5F5',
      lineWidth: 10
    }
  });
  // 绘制指标
  chart.guide().arc({
    zIndex: 1,
    start: [0, 0.965],
    end: [data[0].value, 0.965],
    style: {
      stroke: color,
      lineWidth: 10
    }
  });
  // 绘制指标数字
  chart.guide().html({
    position: ['50%', '95%'],
    html: '
' + '

' + title + '

'
+ '

' + ((data[0].value) * 100).toFixed(2) + '%

'
+ '
'
}); chart.render(); return chart } export default draw

css