天天看點

BPMN.js引入

參考網址:

https://bpmn.io/toolkit/bpmn-js/download/

npm install bpmn-js
           
// npm 安裝
npm install bpmn-js-properties-panel
npm install camunda-bpmn-moddle
           

main.js

import Vue from 'vue'
import App from './App'
import router from './router'

// bpmn.js
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
// 左邊工具欄以及編輯節點的樣式
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
           
<template>
  <div id="app">
    <div class="container bpmn-color">
      <!-- 建立一個canvas畫布 npmn-js是通過canvas實作繪圖的,并設定ref讓vue擷取到element -->
      <div class="bpmn-canvas" ref="canvas"></div>
      <!-- 工具欄顯示的地方 -->
      <div class="bpmn-js-properties-panel" id="js-properties-panel"></div>


      <!-- 把操作按鈕寫在這裡面 -->
      <div class="action">
        <el-upload action class="upload-demo" :before-upload="openBpmn">
          <el-button icon="el-icon-folder-opened"></el-button>
        </el-upload>
        <el-button class="new" icon="el-icon-circle-plus" @click="newDiagram"></el-button>
        <el-button icon="el-icon-download" @click="downloadBpmn"></el-button>
        <el-button icon="el-icon-picture" @click="downloadSvg"></el-button>

        <a hidden ref="downloadLink"></a>
      </div>
    </div>
  </div>
</template>

<script>
import BpmnModeler from "bpmn-js/lib/Modeler";
// 工具欄相關
import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
import propertiesPanelModule from "bpmn-js-properties-panel";
import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";

export default {
  data() {
    return {
      bpmnModeler: null,
      canvas: null,
      bpmnTemplate: `
          <?xml version="1.0" encoding="UTF-8"?>
          <definitions 
              xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
              xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 
              xmlns:camunda="http://camunda.org/schema/1.0/bpmn" 
              xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
              xmlns:activiti="http://activiti.org/bpmn" 
              id="m1577635100724" 
              name="" 
              targetNamespace="http://www.activiti.org/testm1577635100724"
            >
            <process id="process" processType="None" isClosed="false" isExecutable="true">
              <extensionElements>
                <camunda:properties>
                  <camunda:property name="a" value="1" />
                </camunda:properties>
              </extensionElements>
              <startEvent id="_2" name="start" />
            </process>
            <bpmndi:BPMNDiagram id="BPMNDiagram_leave">
              <bpmndi:BPMNPlane id="BPMNPlane_leave" bpmnElement="leave">
                <bpmndi:BPMNShape id="BPMNShape__2" bpmnElement="_2">
                  <omgdc:Bounds x="144" y="368" width="32" height="32" />
                  <bpmndi:BPMNLabel>
                    <omgdc:Bounds x="149" y="400" width="23" height="14" />
                  </bpmndi:BPMNLabel>
                </bpmndi:BPMNShape>
              </bpmndi:BPMNPlane>
            </bpmndi:BPMNDiagram>
          </definitions>
      `
    };
  },
  methods: {
    newDiagram() {
      this.createNewDiagram(this.bpmnTemplate);
    },

    downloadBpmn() {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          console.log(xml);
          // 擷取檔案名
          const name = `${this.getFilename(xml)}.bpmn`;
          // 将檔案名以及資料交給下載下傳方法
          this.download({ name: name, data: xml });
        }
      });
    },
    downloadSvg() {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          // 擷取檔案名
          const name = `${this.getFilename(xml)}.svg`;

          // 從模組化器畫布中提取svg圖形标簽
          let context = "";
          const djsGroupAll = this.$refs.canvas.querySelectorAll(".djs-group");
          for (let item of djsGroupAll) {
            context += item.innerHTML;
          }
          // 擷取svg的基本資料,長寬高
          const viewport = this.$refs.canvas
            .querySelector(".viewport")
            .getBBox();

          // 将标簽和資料拼接成一個完整正常的svg圖形
          const svg = `
            <svg
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="${viewport.width}"
              height="${viewport.height}"
              viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
              version="1.1"
              >
              ${context}
            </svg>
          `;
          // 将檔案名以及資料交給下載下傳方法
          this.download({ name: name, data: svg });
        }
      });
    },

    openBpmn(file) {
      const reader = new FileReader();
      // 讀取File對象中的文本資訊,編碼格式為UTF-8
      reader.readAsText(file, "utf-8");
      reader.onload = () => {
        //讀取完畢後将文本資訊導入到Bpmn模組化器
        this.createNewDiagram(reader.result);
      };
      return false;
    },

    getFilename(xml) {
      let start = xml.indexOf("process");
      let filename = xml.substr(start, xml.indexOf(">"));
      filename = filename.substr(filename.indexOf("id") + 4);
      filename = filename.substr(0, filename.indexOf('"'));
      return filename;
    },

    download({ name = "diagram.bpmn", data }) {
      // 這裡就擷取到了之前設定的隐藏連結
      const downloadLink = this.$refs.downloadLink;
      // 把輸就轉換為URI,下載下傳要用到的
      const encodedData = encodeURIComponent(data);

      if (data) {
        // 将資料給到連結
        downloadLink.href =
          "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
        // 設定檔案名
        downloadLink.download = name;
        // 觸發點選事件開始下載下傳
        downloadLink.click();
      }
    },

    async init() {
      // 擷取畫布 element
      this.canvas = this.$refs.canvas;

      // 建立Bpmn對象
      this.bpmnModeler = new BpmnModeler({
        // 設定bpmn的繪圖容器為上門擷取的畫布 element
        container: this.canvas,

        // 加入工具欄支援
        propertiesPanel: {
          parent: "#js-properties-panel"
        },
        additionalModules: [propertiesProviderModule, propertiesPanelModule],
        moddleExtensions: {
          camunda: camundaModdleDescriptor
        }
      });

      await this.createNewDiagram(this.bpmnTemplate);
    },
    async createNewDiagram(bpmn) {
      // 将字元串轉換成圖顯示出來;
      this.bpmnModeler.importXML(bpmn, err => {
        if (err) {
          this.$Message.error("打開模型出錯,請确認該模型符合Bpmn2.0規範");
        }
      });
    }
  },
  mounted() {
    this.init();
  }
};
</script>

<style>

.bpmn-canvas {
  width: 100%;
  height: 100vh;
}

.action {
  position: fixed;
  bottom: 10px;
  left: 10px;
  display: flex;
}
.upload-demo {
  margin-right: 10px;
}

.bpmn-js-properties-panel {
  position: absolute;
  top: 0;
  right: 0px;
  width: 300px;
}

.bpmn-color .bpmn-icon-start-event-none:before {
  color: #12c2e9;
}
.bpmn-color .bpmn-icon-task:before {
  color: #c471ed;
}
.bpmn-color .bpmn-icon-end-event-none:before {
  color: #f64f59;
}
</style>