Bootstrap

vue+vuex实现2D可视化图形编辑器

随着物联网的快速发展,人们对物联网设备的数据监控可视化的需求越来越强烈,为了解决企业设备数据监控可视化痛点,深圳当康科技经过不断的努力,研发了一套基于物联网的可视化图形编辑器,用户编辑器可以通过该编辑器实现自定义上传图片,和自己所需的组件图标,通过拖拽,移动等方式编辑对应的可视化图形界面,动态绑定设备数据,实现系统组态数据显示。

部分项目源码

/* eslint-disable*/
import {$Dragble} from './Dragble.js';
import store from '@/vuex/index.js';

export const Rotate = (domId) => {
  const $ = (str) => {
    return document.querySelector(str);
  };
  const setRotate = (dom, rotate) => {
    store.commit('zeditor/setDataItemById', {
      id: dom.id,
      styleName: 'rotate',
      value: rotate,
    });
  };
  let roateBox = $(domId);

  // 旋转按钮代码
  // 获取方形中心坐标点即坐标轴原点
  // 鼠标移动事件
  const moveEvent = (e) => {
    // if (e.target.className !== 'point') {
    //   return;
    // }

    const dom = e.target.parentNode;
    let centerPointX =
      dom.getBoundingClientRect().left + dom.getBoundingClientRect().width / 2;
    let centerPointY =
      dom.getBoundingClientRect().top + dom.getBoundingClientRect().height / 2;
    let X = e.clientX;
    let Y = e.clientY;
    e.stopPropagation();
    let oY = Math.abs(Y - centerPointY);
    let oX = Math.abs(X - centerPointX);
    // 避免水平和垂直位置的就相当于和坐标轴相交的时候设置除数为0或者不知道为360度还是180度
    oY === 0 && (oY = 0.01);
    oX === 0 && (oX = 0.01);
    let degEnd = (Math.atan(oX / oY) / (2 * Math.PI)) * 360;

    // 第一象限
    if (X > centerPointX && Y < centerPointY) {
      // console.log('第一象限');
      setRotate(roateBox, degEnd);
    }
    // 第二象限
    if (X > centerPointX && Y > centerPointY) {
      // console.log('第二象限');
      setRotate(roateBox, 180 - degEnd);
    }
    // 第三象限
    if (X < centerPointX && Y > centerPointY) {
      // console.log('第三象限');
      setRotate(roateBox, degEnd + 180);
    }
    // 第四象限
    if (X < centerPointX && Y < centerPointY) {
      // console.log('第四象限');
      setRotate(roateBox, 360 - degEnd);
    }
  };

  function pointEvent (e) {
    e.stopPropagation();
    document.addEventListener('mousemove', moveEvent, false);
  }

  roateBox.querySelector('.point').addEventListener(
    'mousedown',
    pointEvent,
    false
  );
  
  function docEvent() {
    document.removeEventListener('mousemove', moveEvent);
  }

  document.addEventListener(
    'mouseup',
    docEvent,
    false
  );

  // 释放文档按下事件
  document.onmouseup = function() {
    document.onmousemove = null;
  };

  document.oncontextmenu = function() {
    document.onmousemove = null;
  };

  // 右下角拉伸点
  let startX, startY, owidth, oheight, oleft, otop;
  const MAXWIDTH = 10; // 限制最大宽度
  const MAXHEIGHT = 10; // 限制最大高度
  function rbPointEvent (e) {
    let that = this;
    startX = e.clientX;
    startY = e.clientY;
    oleft = parseFloat(this.parentNode.style.left);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveX = e.clientX;
      let moveY = e.clientY;
      let mWidth = moveX - startX;
      let mHeight = moveY - startY;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'left',
        value: oleft,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'width',
        value: (owidth + mWidth > MAXWIDTH ? owidth + mWidth : MAXWIDTH),
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'height',
        value: (oheight + mHeight > MAXHEIGHT ? oheight + mHeight : MAXHEIGHT),
      });
    };
  }
  roateBox.querySelector('.rb-point').addEventListener(
    'mousedown',
    rbPointEvent,
    false
  );

  // 左下角拉伸点
  function lbPointEvent (e) {
    let that = this;
    const mleft = that.parentNode.parentNode.getBoundingClientRect().left;
    const mtop = that.parentNode.parentNode.getBoundingClientRect().top;
    startX = e.clientX - mleft;
    startY = e.clientY - mtop;
    oleft = parseFloat(this.parentNode.style.left);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveX = e.clientX - mleft;
      let moveY = e.clientY - mtop;
      let mWidth = startX - moveX;
      let mHeight = moveY - startY;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'left',
        value: moveX,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'width',
        value: (owidth + mWidth > MAXWIDTH ? owidth + mWidth : MAXWIDTH),
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'height',
        value: (oheight + mHeight > MAXHEIGHT ? oheight + mHeight : MAXHEIGHT),
      });
    };
  }
  roateBox.querySelector('.lb-point').addEventListener(
    'mousedown',
    lbPointEvent,
    false
  );

  // 左上角拉伸点
  function ltPointEvent (e) {
    let that = this;
    const mleft = that.parentNode.parentNode.getBoundingClientRect().left;
    const mtop = that.parentNode.parentNode.getBoundingClientRect().top;
    startX = e.clientX - mleft;
    startY = e.clientY - mtop;
    oleft = parseFloat(this.parentNode.style.left);
    otop = parseFloat(this.parentNode.style.top);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveX = e.clientX - mleft;
      let moveY = e.clientY - mtop;
      let mWidth = startX - moveX;
      let mHeight = startY - moveY;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'left',
        value: moveX,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'top',
        value: moveY,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'width',
        value: owidth + mWidth > MAXWIDTH ? owidth + mWidth : MAXWIDTH,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'height',
        value: oheight + mHeight > MAXHEIGHT ? oheight + mHeight : MAXHEIGHT,
      });
    };
  }
  roateBox.querySelector('.lt-point').addEventListener(
    'mousedown',
    ltPointEvent,
    false
  );

  // 右上角拉伸点
  function rtPointEvent(e) {
    let that = this;
    startX = e.clientX;
    startY = e.clientY - that.parentNode.parentNode.getBoundingClientRect().top;
    oleft = parseFloat(this.parentNode.style.left);
    otop = parseFloat(this.parentNode.style.top);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveX = e.clientX;
      let moveY = e.clientY - that.parentNode.parentNode.getBoundingClientRect().top;
      let mWidth = moveX - startX;
      let mHeight = startY - moveY;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'left',
        value: oleft,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'top',
        value: moveY,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'width',
        value: owidth + mWidth > MAXWIDTH ? owidth + mWidth : MAXWIDTH,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'height',
        value: oheight + mHeight > MAXHEIGHT ? oheight + mHeight : MAXHEIGHT,
      });
    };
  }
  roateBox.querySelector('.rt-point').addEventListener(
    'mousedown',
    rtPointEvent,
    false
  );

  // 中上拉伸点
  function ctPointEvent(e) {
    let that = this;
    const mtop = that.parentNode.parentNode.getBoundingClientRect().top;
    startX = e.clientX;
    startY = e.clientY - mtop;
    oleft = parseFloat(this.parentNode.style.left);
    otop = parseFloat(this.parentNode.style.top);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveY = e.clientY - mtop;
      let mHeight = startY - moveY;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'top',
        value: moveY,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'height',
        value: oheight + mHeight > MAXHEIGHT ? oheight + mHeight : MAXHEIGHT,
      });
    };
  }
  roateBox.querySelector('.ct-point').addEventListener(
    'mousedown',
    ctPointEvent,
    false
  );

  // 中下拉伸点
  function cbPointEvent(e) {
    let that = this;
    startX = e.clientX;
    startY = e.clientY;
    oleft = parseFloat(this.parentNode.style.left);
    otop = parseFloat(this.parentNode.style.top);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveY = e.clientY;
      let mHeight = moveY - startY;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'height',
        value: oheight + mHeight > MAXHEIGHT ? oheight + mHeight : MAXHEIGHT,
      });
    };
  }
  roateBox.querySelector('.cb-point').addEventListener(
    'mousedown',
    cbPointEvent,
    false
  );

  // 左中拉伸点
  function clPointEvent(e) {
    let that = this;
    const mleft = that.parentNode.parentNode.getBoundingClientRect().left;
    const mtop = that.parentNode.parentNode.getBoundingClientRect().top;
    startX = e.clientX - mleft;
    startY = e.clientY - mtop;
    oleft = parseFloat(this.parentNode.style.left);
    otop = parseFloat(this.parentNode.style.top);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveX = e.clientX - mleft;
      let mWidth = startX - moveX;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'left',
        value: moveX,
      });
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'width',
        value: owidth + mWidth > MAXWIDTH ? owidth + mWidth : MAXWIDTH,
      });
    };
  }
  roateBox.querySelector('.cl-point').addEventListener(
    'mousedown',
    clPointEvent,
    false
  );

  // 右中拉伸点
  function crPointEvent(e) {
    let that = this;
    startX = e.clientX;
    startY = e.clientY;
    oleft = parseFloat(this.parentNode.style.left);
    otop = parseFloat(this.parentNode.style.top);
    owidth = this.parentNode.getBoundingClientRect().width;
    oheight = this.parentNode.getBoundingClientRect().height;
    e.stopPropagation();
    document.onmousemove = function(e) {
      let moveX = e.clientX;
      let mWidth = moveX - startX;
      const id = that.parentNode.id;
      store.commit('zeditor/setDataItemById', {
        id,
        styleName: 'width',
        value: owidth + mWidth > MAXWIDTH ? owidth + mWidth : MAXWIDTH,
      });
    };
  }
  roateBox.querySelector('.cr-point').addEventListener(
    'mousedown',
    crPointEvent,
    false
  );

  // 6个点按下后移除鼠标按起事件
  const pointDom = roateBox.querySelectorAll('div[class*="-point"]');
  for (let i = 0; i < pointDom.length; i++) {
    pointDom[i].addEventListener('mouseup', () => {
      document.onmousemove = null;
    }, false);
  }

  // 清空事件方法,统一释放内存
  function clearBindEvent () {
    document.removeEventListener('mousemove', moveEvent);
    document.removeEventListener('mousemove', pointEvent);
    document.removeEventListener('mousemove', docEvent);

    // 八个点的事件释放
    roateBox.querySelector('.rb-point').removeEventListener('mousedown', rbPointEvent);
    roateBox.querySelector('.lb-point').removeEventListener('mousedown', lbPointEvent);
    roateBox.querySelector('.lt-point').removeEventListener('mousedown', ltPointEvent);
    roateBox.querySelector('.rt-point').removeEventListener('mousedown', rtPointEvent);
    roateBox.querySelector('.ct-point').removeEventListener('mousedown', ctPointEvent);
    roateBox.querySelector('.cb-point').removeEventListener('mousedown', cbPointEvent);
    roateBox.querySelector('.cl-point').removeEventListener('mousedown', clPointEvent);
    roateBox.querySelector('.cr-point').removeEventListener('mousedown', crPointEvent);
    // console.log('---------移除事件绑定-------');
  };

  return clearBindEvent;
};
/* eslint-disable*/
import store from '@/vuex/index.js';
export const $Dragble = {
  centerPointX: '',
  centerPointY: '',
  dom: '',
  id: '',
  isMove: false,  // 是否可以移动开关标识
  left: '',
  top: '',
  mouseStartX: '',
  mouseStartY: '',
  positionType: '',
  mousemove: function(maxleft, maxtop) {
    if (!$Dragble.isMove) {
      return;
    }

    const top = (window.event.pageY - $Dragble.mouseStartY);
    const left = (window.event.pageX - $Dragble.mouseStartX);
    store.commit('zeditor/setDataItemById', {
      id: $Dragble.id,
      styleName: 'top',
      value: $Dragble.top + top,
    });
    store.commit('zeditor/setDataItemById', {
      id: $Dragble.id,
      styleName: 'left',
      value: $Dragble.left + left,
    });
    // 这两行必须要有,为了移动的时候重置中心点的坐标
    this.centerPointX =
      $Dragble.dom.getBoundingClientRect().left +
      $Dragble.dom.getBoundingClientRect().width / 2;
    this.centerPointY =
      $Dragble.dom.getBoundingClientRect().top +
      $Dragble.dom.getBoundingClientRect().height / 2;
  },
  mouseup: function() {
    document.removeEventListener('mousemove', this.mousemove);
  },
  // 初始化数据
  intData: function(id, dom, type, maxLeft, maxTop) {
    this.dom = dom;
    this.id = id;
    this.isMove = true;
    this.positionType = type;
    this.dom.style.position = type;
    this.mouseStartX = window.event.pageX;
    this.mouseStartY = window.event.pageY;
    this.left = Number.parseFloat(this.dom.style.left);
    this.top = Number.parseFloat(this.dom.style.top);
    this.dom.style.left ? this.dom.style.left : (this.dom.style.left = 0);
    this.dom.style.top ? this.dom.style.top : (this.dom.style.top = 0);
    this.centerPointX = dom.getBoundingClientRect().left + dom.getBoundingClientRect().width / 2;
    this.centerPointY = dom.getBoundingClientRect().top + dom.getBoundingClientRect().height / 2;
    // 按下右键的时候不能移动组件
    const that = this;
    const vdom = document.querySelector('.editor-panel');
    if (vdom) {
      vdom.oncontextmenu = function() {
        that.isMove = false;
      };
    }
  },
  mousedown: function(id, dom, type, maxLeft, maxTop) {
    this.intData(id, dom, type, maxLeft, maxTop);
    document.addEventListener('mousemove', this.mousemove, false);
    document.removeEventListener('mouseup', this.mousemove);
  },
};

点击进入演示环境

1、编辑器可视化主界面

2、支持置顶、置底、删除、复制、粘贴、数据绑定等功能

3、拥有丰富图标组件库,支持自定义上传素材

4、支持多种类型字体输出绑定

5、动态水流方向和动态GIF图标

6、针对不同的设备类型不同的数据绑定

 

部分项目案例:

水厂可视化

  • 供水系统图可视化

 

  • 供暖锅炉房可视化

  • 实验室风机可视化

  • 煤矿可视化项目

  • 物联网智能网关

  • PLC可编程控制器

;