Bootstrap

基于乐吾乐meta2d从零实现可视化流程图编辑器(十三)

概要

可视化编辑器已成为前端发展趋势,相关产品层出不穷,但是用户较难根据自身需求去完整实现一个功能较为全面的可视化编辑器,我将采用乐吾乐开源的meta2d.js可视化库来实现一个简单的流程图编辑器,通过这个案例来介绍meta2d的相关功能,并向读者展示如何用meta2d从零出发搭建一个较为完整的项目,让我们在实际项目中来体验meta2d的强大之处吧。

请添加图片描述

什么是乐吾乐meta2d.js

meta2d是乐吾乐开源的2D图元组成的可视化引擎,集实时数据展示、动态交互、数据管理等一体的全功能2D可视化引擎。能够快速实现数字孪生、大屏可视化、Web组态、SCADA等解决方案。具有实时监控、多样、变化、动态交互、高效、可扩展、支持自动算法、跨平台等特点,最大程度减少研发和运维的成本,并致力于普通业务人员 0 代码开发实现物联网、工业互联网、电力能源、水利工程、智慧农业、智慧医疗、智慧城市等可视化解决方案。

乐吾乐已将其meta2d核心库完全免费开源,本系列教程就是基于meta2d从零实现web端可视化流程图编辑器。

乐吾乐 meta2d开源项目地址:https://github.com/le5le-com/meta2d.js

乐吾乐 meta2d官方文档:https://doc.le5le.com/document/119359590

项目地址

此可视化流程图编辑器项目地址:github.com/Grnetsky/me…

在线体验地址: http://editor.xroot.top/

往期教程

  1. 基本环境搭建: juejin.cn/spost/72617…
  2. 主界面布局及其初始化: juejin.cn/post/726219…
  3. Meta2d核心库图元注册流程及相关概念: juejin.cn/spost/72629…
  4. 侧边栏功能开发:https://juejin.cn/post/7264414580776403003
  5. Nav组件功能实现:https://juejin.cn/post/7264951443344916517
  6. Nav组件扩展-添加工具栏:https://juejin.cn/post/7265692989611147283
  7. setting组件框架搭建及其Map组件实现:https://juejin.cn/post/7267418197728116748
  8. 引入自定义图元库详解:https://juejin.cn/post/7267948449966096447
  9. Global全局配置组件实现:https://juejin.cn/post/7269349453588660260
  10. 初识PenProps及其Appearance组件实现: https://juejin.cn/post/7270140695477387319
  11. meta2d事件消息及Event组件实现:https://juejin.cn/post/7271120191005392931
  12. 图元动效与动效组件实现:https://juejin.cn/post/7272569074156273705

13.contextMenu组件实现

contextxMenu用于右键菜单选项,可以为用户定制快捷功能。

api相关

本章我们来实现meta2d的contextMenu的功能,本项目的contextMenu主要是提供一些层级改变的功能和一些个人定制的扩展功能比如复制粘贴等。

对于图元层级的管理,meta2d提供了一系列的图层改变的API:

  • meta2d.top(pen):置顶指定画笔,参数为pen或者pen列表[ pen ]。
  • meta2d.bottom(pen):置底指定画笔,参数同上。
  • meta2d.up(pen):移动画笔到上一层,参数同上。
  • meta2d.down(pen):移动画笔到下一层,参数同上。
  • meta2d.setLayer(pen, index):移动画笔到指定层,第一个参数为pen为被移动的画笔,第二个参数为移动到的层数。

对于复制粘贴功能,meta2d提供了copy方法用于复制指定图元到缓存列表,paste方法用于粘贴复制的图元,我们可以使用ctrl+C和ctrl+V的快捷键方式来调用meta2d封装的复制粘贴功能。

接下来让我们看看contextMenu怎么实现吧

实现contextMenu

先给出总的代码:

<script setup>
import {computed, onMounted, reactive, ref} from "vue";
import {useEventbus} from "../hooks/useEventbus.js";
let isPens = ref(false)
let ctxMenu = ref()
let activePens = []

// 设置contextmenu的初始坐标
let menuPos = reactive({
  top:-9999,
  left:-9999,
  visible:false
})


// contextmenu计算属性,用于将menupos数据加工后传入contextmenu的css样式
const calcMenuPos = computed(()=>{
  return {
    top:menuPos.top+"px",
    left:menuPos.left+"px",
    visible:menuPos.visible?"visible":"hidden"
  }
})

// 全局事件总线
const eventBus = useEventbus()

// 监听meta2d的load事件,等待meta2d初始化完成
eventBus.customOn('load',()=>{

// 阻止系统默认菜单栏,并聚焦到我们的contextmenu组件
  window.addEventListener('contextmenu',(e)=>{
    e.preventDefault()
    ctxMenu.value.focus()
  })

  // 监听meta2d的contextmenu事件,弹出contextmenu组件
  meta2d.on('contextmenu',({e})=>{
    menuPos.top = e.clientY
    menuPos.left = e.clientX
    menuPos.visible = true
    ctxMenu.value.focus()
  })

  // 赋值activepens
  meta2d.on("active",(pens)=>{
    console.log("active",pens)
    if(pens.length>0){
      activePens = reactive(pens)
      console.log("activePEns",activePens)
      isPens.value = true
    }else {
      isPens.value = false
      activePens = []
    }
  })
  meta2d.on('inactive',()=>{
    isPens.value = false
  })
})

// 调用meta2d相关API
function changeCoverage(pos){
  switch (pos){
    case "top":
      meta2d.top(activePens)
      break
    case "bottom":
      meta2d.bottom(activePens)
      break
    case "up":
      meta2d.up(activePens)
      break
    case "down":
      meta2d.down(activePens)
      break
  }
  ctxMenu.value.blur()
}

function lock() {
  meta2d.lock(2)
  meta2d.emit('lock')
  ctxMenu.value.blur()
}

function paste() {
  meta2d.paste()
  ctxMenu.value.blur()
}
function copy() {
  meta2d.copy(activePens)
  ctxMenu.value.blur()
}

function ctxMenuClose() {
  menuPos.visible = false
}

</script>

<template>
  <div class="contextmenu" ref="ctxMenu" tabindex="-1" @blur="ctxMenuClose">
    <div class="ctx_item" v-show="isPens" @click="changeCoverage('top')">置顶</div>
    <div class="ctx_item" v-show="isPens" @click="changeCoverage('bottom')">置底</div>
    <div class="ctx_item" v-show="isPens" @click="changeCoverage('up')">上一图层</div>
    <div class="ctx_item" v-show="isPens" @click="changeCoverage('down')">下一图层</div>
    <div class="ctx_item" @click="lock">锁定</div>
    <div class="ctx_item" v-show="isPens" @click="copy">复制</div>
    <div class="ctx_item" @click="paste">粘贴</div>
  </div>
</template>

<style scoped>

.contextmenu {
  padding: 6px;
  position: absolute;
  top: v-bind("calcMenuPos.top");
  left:v-bind("calcMenuPos.left");
  visibility: v-bind("calcMenuPos.visible");
  background-color: #fff;
  max-height: 5000px;
  width: 180px;
  z-index: 999;
  border-radius: 10px;
}
.ctx_item{
  width: 100%;
  padding: 10px;
  cursor: pointer;
  transition: background-color .5s ease;
}
.ctx_item:hover{
  background-color: #eeeeee;
}
</style>

vue3支持通过v-bind在css中绑定变量了,我们利用这一点就很好实现我们想要的功能了。首先我们的contextMenu肯定要通过一个事件触发出来,meta2d提供了一个“contextmenu”的事件,用于监听在meta2d上触发单击鼠标右键的行为,另外,为了防止系统的contextMenu的弹出影响用户使用,我们需要先在系统的contextmenu事件中将其禁止掉,然后在其中调用我们自己的contextMenu组件出来,像下面这样:

  window.addEventListener('contextmenu',(e)=>{
    e.preventDefault()  // 阻止系统菜单栏
    ctxMenu.value.focus() // 聚焦我们的菜单栏,防止聚焦到了meta2d自身上而导致弹出失败
  })

  // meta2d的contextmen
    meta2d.on('contextmenu',({e})=>{
    // 设定
      menuPos.top = e.clientY
      menuPos.left = e.clientX
      menuPos.visible = true
      ctxMenu.value.focus()
    })

需要注意的是,原生div的focus和blur事件并不生效,我们需要在其身上加入tabindex属性,其作用读者自行查看文档,我们需要给它加上tabindex属性,像这样:

<div class="contextmenu" ref="ctxMenu" tabindex="-1" @blur="ctxMenuClose">
    ...
</div>

然后通过active事件,拿到作用的图元对象,并在点击事件中执行相关API就好了,其他细枝末节相信读者都能很好看懂,直接来看最后效果吧。

contextmenu 000000000030gif

功能实现成功,读者也可以去在线链接中体验。

总结

本章我们较为简单的介绍了meta2d图层相关的API,然后介绍了contextMenu组件的实现,在此基础上定制了
我们自己的右击菜单的功能。读者可根据自己实际需求进行定制化设计,到此我们整个项目的主要功能就已经讲完了。

全文总结

通过这么多章节的学习,我相信各位读者对meta2d有了基本的认识,由于全文篇幅有限,没办法将meta2d所有的功能一一介绍,更多奇妙的探索还需读者自行实践,虽然文章内容不多,但是足够支撑读者进行简单的定制化自己的可视化编辑器了,接下来让我们回顾下这个系列我们学到了些什么吧:

  • 第一章:进行了基本的环境搭建
  • 第二章:界面布局,并引入meta2d
  • 第三章:讲解了meta2d的使用流程,我们了解了如何使用meta2d,并且学会了注册meta2d生态的图元库
  • 第四章:meta2d的侧边栏两个功能开发
  • 第五章:Nav组件实现,讲解了Nav相关的基本功能以及API
  • 第六章:Nav组件扩展,在原有Nav基础上讲解了更多与meta2d原生交互相关的功能与API
  • 第七章:初入setting组件,了解了meta2d更改配置项的相关API以及使用流程
  • 第八章:讲解了如何导入各种各样的自定义图元,我们可以在meta2d里面玩转自主设计的图元了
  • 第九章:Global组件实现,讲解了如何更改meta2d的引擎配置项
  • 第十章:深入setting组件,初识PenProps及其Appearance组件学会了如何为meta2d的图元定制相关属性
  • 第十一章:meta2d的事件消息与图元event事件,能够用其进行简单的事件监听和注册回调了
  • 第十二章:讲解了图元的动画效果,丰富了图元的功能,变得更加酷炫
  • 第十三章:实现了右击菜单,能够做些定制化的快捷操作了

以上就是我们整个系列学习的全部内容了,如果你对meta2d的更多功能感兴趣,可自行前往官网阅读相关文档。如果你在开发中遇到了一些困难发现了一些bug欢迎与我交流,也可以在meta2d github上提出issue会有专业的人员解答,国产开源需要大家的支持。

感谢大家对本系列的关注与认可,我们未来再见。

有问题欢迎在评论区反馈,欢迎持续关注。

Meta2d.js 开源地址

给大家推荐一下 Meta2d.js是一个实时数据响应和交互的2d引擎,可用于Web组态,物联网,数字孪生等场景。

Github:github.com/le5le-com/m…

Gitee: gitee.com/le5le/meta2…

如果本篇文章帮助到了你,欢迎为meta2d项目star点星。

;