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

90 篇文章 1 订阅
21 篇文章 0 订阅

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

部分项目源码

/* 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可编程控制器

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
VueVuex和TypeScript中使用modules进行模块化的方式如下: 首先,我们需要安装好VueVuex,并使用TypeScript构建Vue项目。可以通过以下命令进行安装: ``` npm install vue vuex --save npm install typescript ts-loader --save-dev ``` 接下来,在根目录下创建`store`目录,并在该目录下创建`index.ts`文件。在`store`目录下再创建`modules`目录,并在该目录下创建对应的模块文件,例如`user.ts`和`product.ts`。 在`user.ts`模块中,定义用户相关的状态、mutations、actions和getters。例如: ```javascript // user.ts const user = { state: { userInfo: null }, mutations: { SET_USER_INFO(state, userInfo) { state.userInfo = userInfo; } }, actions: { setUserInfo({ commit }, userInfo) { commit('SET_USER_INFO', userInfo); } }, getters: { getUserInfo: state => state.userInfo } }; export default user; ``` 在`product.ts`模块中,同样定义商品相关的状态、mutations、actions和getters。 在`index.ts`文件中,引入VueVuex,并创建一个Vuex Store对象,使用`module`方法将模块添加到Store中。例如: ```javascript // index.ts import Vue from 'vue'; import Vuex from 'vuex'; import user from './modules/user'; import product from './modules/product'; Vue.use(Vuex); const store = new Vuex.Store({ modules: { user, product } }); export default store; ``` 最后,在Vue的入口文件(如`main.ts`)中,引入创建的Vuex Store,并将其挂载到Vue实例上。例如: ```javascript // main.ts import Vue from 'vue'; import App from './App.vue'; import store from './store/index'; Vue.config.productionTip = false; new Vue({ store, render: h => h(App) }).$mount('#app'); ``` 现在,我们就可以在组件中使用`this.$store`来访问Vuex的状态、提交mutations、触发actions等。在模块化的情况下,可以使用`this.$store.state.user.userInfo`来访问`user`模块中的`userInfo`状态,使用`this.$store.commit('user/SET_USER_INFO', userInfo)`来提交`user`模块中的`SET_USER_INFO`mutation,使用`this.$store.dispatch('user/setUserInfo', userInfo)`来触发`user`模块中的`setUserInfo`action,以此类推。 通过以上的步骤,我们就可以在VueVuex和TypeScript中使用modules进行模块化管理应用的状态。这样可以使得代码结构更清晰,易于维护和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值