LogicFlow工作流在React和Vue3中的使用

news2024/11/15 12:05:39

LogicFlow 是一款流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和简单灵活的节点自定义、插件等拓展机制,方便我们快速在业务系统内满足类流程图的需求。

核心能力

  • 可视化模型:通过 LogicFlow 提供的直观可视化界面,用户可以轻松创建、编辑和管理复杂的逻辑流程图。
  • 高可定制性:用户可以根据自己的需要定制节点、连接器和样式,创建符合特定用例的定制逻辑流程图。
  • 灵活易拓展: 内置提供丰富的插件,用户也可根据自身需求定制复杂插件实现业务需求。
  • 自执行引擎: 执行引擎支持浏览器端执行流程图逻辑,为无代码执行提供新思路。
  • 数据可转换:支持 LogicFlow 数据与 BPMN、Turbo 等各种后端执行引擎数据结构转换能力。

添加 logic-flow 基础代码

$ npm install @logicflow/core --save

在 App.vue 文件中, 添加 logic-flow 核心代码;

<script setup lang="ts">
import { onMounted, ref } from "vue";
import LogicFlow from "@logicflow/core";
import "@logicflow/core/es/index.css";
 
const container = ref();
 
onMounted(() => {
  const lf = new LogicFlow({
    container: container.value,
    grid: true,
  });
  lf.render();
});
</script>
 
<template>
  <div class="container" ref="container"></div>
</template>
 
<style scoped>
.container {
  width: 100%;
  height: 100%;
}
</style>

使用内置拖拽面板

安装 @logicflow/extension 扩展依赖, 先看一下内置拖拽面板如何使用;

npm install @logicflow/extension --save

再次修改 App.vue 文件内容, 导入 DndPanel 对象及扩展所需要的样式模块;

import { DndPanel } from "@logicflow/extension";
import "@logicflow/extension/lib/style/index.css";

 在实例化 LogicFlow 对象时, 通过选项 plugins 配置 DndPanel 对象;

const lf = new LogicFlow({
   ...
   plugins: [DndPanel],
});

在实例化 LogicFlow 对象后, 通过实例对象 lf.extension.dndPanel 中的 setPatternItems 方法设置拖拽面板的内容:

// icons 是一组图标对象(Base64字符串)
import { icons } from "./icons";
 
lf.extension.dndPanel.setPatternItems([
  {
    label: "选区",
    icon: icons.select,
  },
  {
    type: "circle",
    text: "开始",
    label: "开始节点",
    icon: icons.start,
  },
  {
    type: "rect",
    label: "用户任务",
    icon: icons.task,
  },
  {
    type: "rect",
    label: "系统任务",
    icon: icons.task,
  },
  {
    type: "diamond",
    label: "条件判断",
    icon: icons.condition,
  },
  {
    type: "circle",
    text: "结束",
    label: "结束节点",
    icon: icons.end,
  },
]);

 重新预览效果, 可以看到内置拖拽面板已经生效;

在React中的使用示例(使用CRA搭建开发环境)

package.json

{
  "name": "logicflow-react",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@logicflow/core": "^2.0.0",
    "@logicflow/extension": "^2.0.0",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "antd": "^5.20.1",
    "insert-css": "^2.0.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <style>
      html, body, #root{
        margin: 0;
        padding: 0;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

src/index.js

import ReactDOM from 'react-dom/client';
import React, { useEffect, useRef } from "react";
import { Button } from "antd";
import LogicFlow from "@logicflow/core";
import {
  BpmnElement,
  BpmnXmlAdapter,
  Control,
  Menu,
  SelectionSelect,
  DndPanel,
} from "@logicflow/extension";
import "@logicflow/core/es/index.css";
import "@logicflow/extension/lib/style/index.css";
import insertCss from 'insert-css';

const root = ReactDOM.createRoot(document.getElementById('root'));

const App = () => {
  const container = useRef(null);
  const lfRef = useRef(null);

  useEffect(() => {
    lfRef.current = new LogicFlow({
      container: container.current,
      stopZoomGraph: true,
      metaKeyMultipleSelected: true,
      grid: true,
      keyboard: {
        enabled: true,
      },
      snapline: true,
      plugins: [
        BpmnElement,
        BpmnXmlAdapter,
        Control,
        Menu,
        SelectionSelect,
        DndPanel,
      ],
    });

    lfRef.current.setPatternItems([
      {
        label: "选区",
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=",
        callback: () => {
          lfRef.current.openSelectionSelect();
          lfRef.current.once("selection:selected", () => {
            lfRef.current.closeSelectionSelect();
          });
        },
      },
      {
        type: "bpmn:startEvent",
        label: "开始",
        text: "开始",
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg==",
      },
      {
        type: "bpmn:userTask",
        label: "用户任务",
        text: "用户任务",
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==",
      },
      {
        type: "bpmn:serviceTask",
        label: "系统任务",
        text: "系统任务",
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==",
      },
      {
        type: "bpmn:exclusiveGateway",
        label: "条件判断",
        text: "条件判断",
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAAHeEJUAAAAABGdBTUEAALGPC/xhBQAAAvVJREFUOBGNVEFrE0EU/mY3bQoiFlOkaUJrQUQoWMGePLX24EH0IIoHKQiCV0G8iE1covgLiqA/QTzVm1JPogc9tIJYFaQtlhQxqYjSpunu+L7JvmUTU3AgmTfvffPNN++9WSA1DO182f6xwILzD5btfAoQmwL5KJEwiQyVbSVZ0IgRyV6PTpIJ81E5ZvqfHQR0HUOBHW4L5Et2kQ6Zf7iAOhTFAA8s0pEP7AXO1uAA52SbqGk6h/6J45LaLhO64ByfcUzM39V7ZiAdS2yCePPEIQYvTUHqM/n7dgQNfBKWPjpF4ISk8q3J4nB11qw6X8l+FsF3EhlkEMfrjIer3wJTLwS2aCNcj4DbGxXTw00JmAuO+Ni6bBxVUCvS5d9aa04+so4pHW5jLTywuXAL7jJ+D06sl82Sgl2JuVBQn498zkc2bGKxULHjCnSMadBKYDYYHAtsby1EQ5lNGrQd4Y3v4Zo0XdGEmDno46yCM9Tk+RiJmUYHS/aXHPNTcjxcbTFna000PFJHIVZ5lFRqRpJWk9/+QtlOUYJj9HG5pVFEU7zqIYDVsw2s+AJaD8wTd2umgSCCyUxgGsS1Y6TBwXQQTFuZaHcd8gAGioE90hlsY+wMcs30RduYtxanjMGal8H5dMW67dmT1JFtYUEe8LiQLRsPZ6IIc7A4J5tqco3T0pnv/4u0kyzrYUq7gASuEyI8VXKvB9Odytv6jS/PNaZBln0nioJG/AVQRZvApOdhjj3Jt8QC8Im09SafwdBdvIpztpxWxpeKCC+EsFdS8DCyuCn2munFpL7ctHKp+Xc5cMybeIyMAN33SPL3ZR9QV1XVwLyzHm6Iv0/yeUuUb7PPlZC4D4HZkeu6dpF4v9j9MreGtMbxMMRLIcjJic9yHi7WQ3yVKzZVWUr5UrViJvn1FfUlwe/KYVfYyWRLSGNu16hR01U9IacajXPei0wx/5BqgInvJN+MMNtNme7ReU9SBbgntovn0kKHpFg7UogZvaZiOue/q1SBo9ktHzQAAAAASUVORK5CYII=",
      },
      {
        type: "bpmn:endEvent",
        label: "结束",
        text: "结束",
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC",
      },
    ]);

    lfRef.current.render({});
  }, []);

  const download = (filename, text) => {
    const element = document.createElement("a");
    element.setAttribute(
      "href",
      "data:text/plain;charset=utf-8," + encodeURIComponent(text)
    );
    element.setAttribute("download", filename);
    element.style.display = "none";
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
  };

  const downloadXml = () => {
    const data = lfRef.current.getGraphData();
    download("logic-flow.xml", data);
  };

  const uploadXml = (ev) => {
    const file = ev.target.files[0];
    const reader = new FileReader();
    reader.onload = (event) => {
      if (event.target) {
        const xml = event.target.result;
        lfRef.current.render(xml);
      }
    };
    reader.readAsText(file);
  };

  return (
    <>
      <div className="explain">
        点击左下角下载 XML,将文件上传到
        <Button type="link" href="https://demo.bpmn.io/" target="_blank">
          BPMN Demo
        </Button>
        即可使用
      </div>
      <div id="graph" ref={container}></div>
      <div className="graph-io">
        <span title="下载 XML" onMouseDown={() => downloadXml()}>
          <img
            src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABqUlEQVQ4T92Uv0tbURTHPyevUwc3qUshU/8DBzOYmwiFDlK6dHKwVHBwUKjUoleS4Ku0UkEHB6HSDp1cpHRwSnKz1KH/QaeAS0txcXDy5ciNL5LEF4k/oOBZHvfdcz/33O/53ivccUgvnrFaBAo95ksuFD9/Kf4LMOdCcb4UY9UAVeBWFd5XoHmnaQIKCOm21nnNko7c1LQZSp2IkvsgdT+86PLYoj6KUvzp8sGvIGCiXJLf/v9YQZ9EEd+A4fa8oMFQeVX+dgD9IG8134CvwGMV1morspDkteyyfhTlLXCYgslKKJVW3iUfxlV46Aiw40KZaocaq5+B18BBEDDZqv4CmLO6pnDS7vzxoj48PuWLwEuU7ymY8QsasIXwXGF34AGvfhTlpAUatfo0BRkxVhVwLpRc9/GM1U/AG4WfsT4ZYN2FMp+Q6w1vrgTGt2MW2IgBcy6UzSRdjdX+gH5xdlGf+W9tVfaTYPHG/QN7QbqadQ7MWj0S5ZiIXMuc/QA6YOeXoqrCgNfwqnfvuuxS04fZJd0W4QUweF1CnP9Plb3ae5nu+cDeEMwZu/TFGsleoRIAAAAASUVORK5CYII="
            alt="下载XML"
          />
        </span>
        <span id="upload-xml" title="上传 XML">
          <input
            type="file"
            className="upload"
            onChange={(ev) => uploadXml(ev)}
          />
          <img
            className="upload-img"
            src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABMUlEQVQ4T+XUsUrEQBCA4X8MCD6Cr6DPIOawFiy8gE9ga62BM7D6Aj6CYOHZnaAg6h62Yqed7dmKnUUYmbARDafZwBWCWyWb2W9nZ3cjzLjJjD2iwZVdXbw7lJe2BKLANNcUSOfg+MbJ82/oN7CX64nCVhjgvZNewG6tT+FhPmH9qpBJmqtanwgTVba9k/Pq/etsdRBQhOCRKvfAI7AcYsckbFCyE94HFu+d7P8EVh/XBrpUllwCb8AZMFAlE+EUYbTwSv/iSN5DEu1gmqvNuJkkZGVJZqB3Iqt72jfU8PGBDKNBS9+yvC7kKeAVaP2GGmbPncC6vk1wSt3bl9wYZMv/zPAfgKH4qXfim7ckZlOG3okdk6gWA0ZBjaDpuxwObX3FusB276tyRP1tush/H/wANP7LFUnxl7EAAAAASUVORK5CYII="
            alt="上传XML"
          />
        </span>
      </div>
    </>
  );
};

root.render(<App></App>);

insertCss(`
  .explain {
    height: 30px;  
  }
  #graph {
    width: 100%;
    height: calc(100% - 30px);
  }
  .graph-io {
    position: absolute;
    left: 10px;
    bottom: 10px;
    z-index: 9999;
    background:rgba(255,255,255,0.8);
    box-shadow: 0 1px 4px rgba(0,0,0,.3);
    padding: 10px;
    display: flex;
  }
  .graph-io > span {
    margin: 0 5px;
    cursor: pointer;
  }
  #upload-xml {
    position: relative;
    overflow: hidden;
    display: inline-block;
    cursor: pointer;
  }
  .upload {
    position: absolute;
    z-index: 99;
    left: 0;
    top: 0;
    opacity: 0;
    cursor: pointer;
  }
  .upload::-webkit-file-upload-button {
    cursor: pointer;
  }
  .upload-img {
    width: 26px;
  }
  `);

在Vue3中使用(使用Vite搭建开发环境)

package.json:

{
  "name": "logicflow",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@logicflow/core": "^2.0.0",
    "@logicflow/extension": "^2.0.0",
    "vue": "^3.4.29"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.5",
    "unplugin-auto-import": "^0.18.2",
    "unplugin-vue-components": "^0.27.3",
    "vite": "^5.3.1"
  }
}

src/App.vue:

<template>
  <div class="root" ref="rootRef"></div>
  <div class="graph"></div>
  <div class="graph-io">
    <span title="下载 XML" @mousedown="downloadXml">
      <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABqUlEQVQ4T92Uv0tbURTHPyevUwc3qUshU/8DBzOYmwiFDlK6dHKwVHBwUKjUoleS4Ku0UkEHB6HSDp1cpHRwSnKz1KH/QaeAS0txcXDy5ciNL5LEF4k/oOBZHvfdcz/33O/53ivccUgvnrFaBAo95ksuFD9/Kf4LMOdCcb4UY9UAVeBWFd5XoHmnaQIKCOm21nnNko7c1LQZSp2IkvsgdT+86PLYoj6KUvzp8sGvIGCiXJLf/v9YQZ9EEd+A4fa8oMFQeVX+dgD9IG8134CvwGMV1morspDkteyyfhTlLXCYgslKKJVW3iUfxlV46Aiw40KZaocaq5+B18BBEDDZqv4CmLO6pnDS7vzxoj48PuWLwEuU7ymY8QsasIXwXGF34AGvfhTlpAUatfo0BRkxVhVwLpRc9/GM1U/AG4WfsT4ZYN2FMp+Q6w1vrgTGt2MW2IgBcy6UzSRdjdX+gH5xdlGf+W9tVfaTYPHG/QN7QbqadQ7MWj0S5ZiIXMuc/QA6YOeXoqrCgNfwqnfvuuxS04fZJd0W4QUweF1CnP9Plb3ae5nu+cDeEMwZu/TFGsleoRIAAAAASUVORK5CYII="
        alt="下载XML" />
    </span>
    <span id="upload-xml" title="上传 XML">
      <input type="file" class="upload" @change="uploadXml" />
      <img class="upload-img"
        src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABMUlEQVQ4T+XUsUrEQBCA4X8MCD6Cr6DPIOawFiy8gE9ga62BM7D6Aj6CYOHZnaAg6h62Yqed7dmKnUUYmbARDafZwBWCWyWb2W9nZ3cjzLjJjD2iwZVdXbw7lJe2BKLANNcUSOfg+MbJ82/oN7CX64nCVhjgvZNewG6tT+FhPmH9qpBJmqtanwgTVba9k/Pq/etsdRBQhOCRKvfAI7AcYsckbFCyE94HFu+d7P8EVh/XBrpUllwCb8AZMFAlE+EUYbTwSv/iSN5DEu1gmqvNuJkkZGVJZqB3Iqt72jfU8PGBDKNBS9+yvC7kKeAVaP2GGmbPncC6vk1wSt3bl9wYZMv/zPAfgKH4qXfim7ckZlOG3okdk6gWA0ZBjaDpuxwObX3FusB276tyRP1tush/H/wANP7LFUnxl7EAAAAASUVORK5CYII="
        alt="上传XML" />
    </span>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import LogicFlow from "@logicflow/core";
import {
  BpmnElement,
  BpmnXmlAdapter,
  Control,
  Menu,
  SelectionSelect,
  DndPanel,
} from "@logicflow/extension";
import "@logicflow/core/es/index.css";
import "@logicflow/extension/lib/style/index.css";

const rootRef = ref(null)
const lfRef = ref(null);

const download = (filename, text) => {
  const element = document.createElement("a");
  element.setAttribute(
    "href",
    "data:text/plain;charset=utf-8," + encodeURIComponent(text)
  );
  element.setAttribute("download", filename);
  element.style.display = "none";
  document.body.appendChild(element);
  element.click();
  document.body.removeChild(element);
};

const downloadXml = () => {
  const data = lfRef.value.getGraphData();
  download("logic-flow.xml", data);
};

const uploadXml = (ev) => {
  const file = ev.target.files[0];
  const reader = new FileReader();
  reader.onload = (event) => {
    if (event.target) {
      const xml = event.target.result;
      lfRef.value.render(xml);
    }
  };
  reader.readAsText(file);
};

onMounted(() => {
  lfRef.value = new LogicFlow({
    container: rootRef.value,
    stopZoomGraph: true,
    metaKeyMultipleSelected: true,
    grid: true,
    keyboard: {
      enabled: true,
    },
    snapline: true,
    plugins: [
      BpmnElement,
      BpmnXmlAdapter,
      Control,
      Menu,
      SelectionSelect,
      DndPanel,
    ],
  });

  lfRef.value.setPatternItems([
    {
      label: "选区",
      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=",
      callback: () => {
        lfRef.current.openSelectionSelect();
        lfRef.current.once("selection:selected", () => {
          lfRef.current.closeSelectionSelect();
        });
      },
    },
    {
      type: "bpmn:startEvent",
      label: "开始",
      text: "开始",
      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg==",
    },
    {
      type: "bpmn:userTask",
      label: "用户任务",
      text: "用户任务",
      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==",
    },
    {
      type: "bpmn:serviceTask",
      label: "系统任务",
      text: "系统任务",
      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==",
    },
    {
      type: "bpmn:exclusiveGateway",
      label: "条件判断",
      text: "条件判断",
      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAAHeEJUAAAAABGdBTUEAALGPC/xhBQAAAvVJREFUOBGNVEFrE0EU/mY3bQoiFlOkaUJrQUQoWMGePLX24EH0IIoHKQiCV0G8iE1covgLiqA/QTzVm1JPogc9tIJYFaQtlhQxqYjSpunu+L7JvmUTU3AgmTfvffPNN++9WSA1DO182f6xwILzD5btfAoQmwL5KJEwiQyVbSVZ0IgRyV6PTpIJ81E5ZvqfHQR0HUOBHW4L5Et2kQ6Zf7iAOhTFAA8s0pEP7AXO1uAA52SbqGk6h/6J45LaLhO64ByfcUzM39V7ZiAdS2yCePPEIQYvTUHqM/n7dgQNfBKWPjpF4ISk8q3J4nB11qw6X8l+FsF3EhlkEMfrjIer3wJTLwS2aCNcj4DbGxXTw00JmAuO+Ni6bBxVUCvS5d9aa04+so4pHW5jLTywuXAL7jJ+D06sl82Sgl2JuVBQn498zkc2bGKxULHjCnSMadBKYDYYHAtsby1EQ5lNGrQd4Y3v4Zo0XdGEmDno46yCM9Tk+RiJmUYHS/aXHPNTcjxcbTFna000PFJHIVZ5lFRqRpJWk9/+QtlOUYJj9HG5pVFEU7zqIYDVsw2s+AJaD8wTd2umgSCCyUxgGsS1Y6TBwXQQTFuZaHcd8gAGioE90hlsY+wMcs30RduYtxanjMGal8H5dMW67dmT1JFtYUEe8LiQLRsPZ6IIc7A4J5tqco3T0pnv/4u0kyzrYUq7gASuEyI8VXKvB9Odytv6jS/PNaZBln0nioJG/AVQRZvApOdhjj3Jt8QC8Im09SafwdBdvIpztpxWxpeKCC+EsFdS8DCyuCn2munFpL7ctHKp+Xc5cMybeIyMAN33SPL3ZR9QV1XVwLyzHm6Iv0/yeUuUb7PPlZC4D4HZkeu6dpF4v9j9MreGtMbxMMRLIcjJic9yHi7WQ3yVKzZVWUr5UrViJvn1FfUlwe/KYVfYyWRLSGNu16hR01U9IacajXPei0wx/5BqgInvJN+MMNtNme7ReU9SBbgntovn0kKHpFg7UogZvaZiOue/q1SBo9ktHzQAAAAASUVORK5CYII=",
    },
    {
      type: "bpmn:endEvent",
      label: "结束",
      text: "结束",
      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC",
    },
  ]);

  lfRef.value.render({});
});
</script>

<style scoped>
.root {
  width: 100%;
  height: 100%;
}

.explain {
  height: 30px;
}

.graph {
  width: 100%;
  height: calc(100% - 30px);
}

.graph-io {
  position: absolute;
  left: 10px;
  bottom: 10px;
  z-index: 9999;
  background: rgba(255, 255, 255, 0.8);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  padding: 10px;
  display: flex;
}

.graph-io>span {
  margin: 0 5px;
  cursor: pointer;
}

#upload-xml {
  position: relative;
  overflow: hidden;
  display: inline-block;
  cursor: pointer;
}

.upload {
  position: absolute;
  z-index: 99;
  left: 0;
  top: 0;
  opacity: 0;
  cursor: pointer;
}

.upload::-webkit-file-upload-button {
  cursor: pointer;
}

.upload-img {
  width: 26px;
}
</style>

效果:

官网:https://site.logic-flow.cn/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2033180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

gRPC golang开发实践

gRPC golang开发实践 Protobuf定义消息类型标量类型复合类型引用其它消息类型 Protoc使用安装使用语言插件 Buf使用配置和构建buf模块代码生成 实现gRPC API初始化go.mod文件实现服务端代码实现客户端代码 测试gRPC API使用bloomRPC客户端工具使用grpcurl命令行工具使用buf cur…

RCE之突破长度限制

我们在写webshell时通常会遇到过滤&#xff0c;但除了过滤之外还可能会有长度限制&#xff0c;这里就简单说一下关于RCE突破长度限制的技巧 突破16位 例如&#xff1a;PHP Eval函数参数限制在16个字符的情况下 &#xff0c;如何拿到Webshell&#xff1f; <?php $param …

jenkins 安装以及自动构建maven项目并且运行

在这里找到你对应jdk的版本的jenkins包 War Jenkins Packages 我这里用的使java8,所以下载 https://mirrors.jenkins.io/war-stable/2.60.1/jenkins.war 然后jenkins可以安装到centos系统 在本地windows系统运行命令行 scp C:\Users\98090\Downloads\jenkins.war root@192…

在Oxygen中插入图形的三种方法

在Oxygen中有以下几种在内容中插入图形的方法&#xff1a; 方法一 1. 将光标放在想要插入图形的地方&#xff0c;并点击插入图形工具栏 2. 在弹出窗口选择需要插入的图形路径&#xff0c;并做相关的设置 注&#xff1a;图形最好是使用相对路径&#xff0c;这样不依赖于本地路…

NVIDIA H100 GPU,它将如何改变AI和计算领域的游戏规则?

大语言模型 (LLM) 的兴起标志着人工智能 (AI) 时代的重大进步。在这一背景下&#xff0c;Paperspace DigitalOcean 提供的云图形处理单元 (GPU) 已成为高质量 NVIDIA GPU 云服务的领先者&#xff0c;推动了计算技术的前沿发展。 NVIDIA 成立于 1993 年&#xff0c;由三位有远见…

软件测试需要具备的基础知识【功能测试】---后端知识(三)

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 为了更好的学习软件测试的相关技能&#xff0c;需要具备一定的基础知识。需要学习的基础知识包括&#xff1a; 1、计算机基础 2、前端知识 3、后端知识 4、软件测试理论 后期分四篇文章进行编写&#xff0c;这是第三篇 …

Cycript安装报错 Library not loaded终极解决方案

一、下载安装 Cycript 官方完整 资源下载完成后&#xff0c;解压。目录如下&#xff1a; 二、执行 打开命令终端,cd到对应目录&#xff0c;然后执行./cycript #第一步&#xff1a;cd到解压的目录 cd /xx/cycrpt_0#执行&#xff1a; ./cycript 2.1、报错Library not Loaded …

oled使用 f4软件iic 数字 汉字 小图片 HAL库

基于江科大的oled标准库进行移植 到Hal库上 本人参考了许多大佬的源码 进行更改 由于F4和F1主频不一样 由于F4主频太高 在进行软件iic时需要延时一下 才可驱动oled 本人在网上找了一个开源的us延时函数 已经添加进入 文件分享 通过百度网盘分享的文件&#xff1a;delay&#…

如何自动抓取岗位数据?五种采集技巧

摘要&#xff1a; 本文将深入探讨如何从前程无忧网站自动抓取岗位信息&#xff0c;通过分享五大实用的采集技巧&#xff0c;助您轻松掌握大数据时代的招聘情报。无需编程基础&#xff0c;也能高效获取目标职位详情&#xff0c;优化人力资源管理与市场分析。 正文&#xff1a;…

电脑图片损坏打不开怎么办?能修复吗?

照片和视频是记录和保存现实生活中的事件的最好方式。由于手机储存空间有限&#xff0c;一般我们会把有纪念意义的照片放到电脑上进行保存&#xff0c;但有时难免会遇到照片被损坏打不开的情况&#xff0c;一旦遇到这种情况&#xff0c;先不要急&#xff0c;也不要因为照片打不…

【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境

【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境 文章目录 【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境1.简介2.验证顶层3.顶层代码4.模型结构4.1 地址映射4.2 特殊功能寄存器 5.模型代码6.运行脚本7.总结 1.简介 在前几篇文章中&#xff0c;分别介绍了各个模块的设…

订单增长40%,磁性元件下半年还有哪些挑战?

导语 2024即将过半&#xff0c;哪些终端市场发展势头更好?海运价格上涨又会对磁性元件企业造成哪些影响? 2024年开春以来&#xff0c;比亚迪发起了新一轮价格战&#xff0c;让持续一年的新能源汽车价格战再度升级&#xff0c;也让2024年的市场走势更加扑朔迷离。 第二十二届(…

PMTiles介绍与MapboxGL中使用

概述 本文介绍PMTiles以及PMTiles在MapboxGL中的使用。 PMTiles简介 PMTiles 是一种对瓦片数据的单文件压缩格式。PMTiles 压缩包可以托管在如 S3 这样的商品级存储平台上&#xff0c;并允许创建低成本、零维护的“无服务器”地图应用程序——这些应用程序无需自定义瓦片后端…

手机误操作导致永久删除照片的恢复方法有哪些?

随着手机功能的不断增强和应用程序的不断丰富&#xff0c;人们越来越依赖手机&#xff0c;离不开手机。但有时因为我们自己的失误操作&#xff0c;导致我们手机上重要的照片素材被永久删除&#xff0c;这时我们需要怎么做&#xff0c;才能找回我们被永久删除的照片素材呢&#…

LeetCode.676.实现一个魔法字典

题目描述&#xff1a; 设计一个使用单词列表进行初始化的数据结构&#xff0c;单词列表中的单词 互不相同 。 如果给出一个单词&#xff0c;请判定能否只将这个单词中一个字母换成另一个字母&#xff0c;使得所形成的新单词存在于你构建的字典中。 实现 MagicDictionary 类&a…

前端工程化项目 用npm拉git项目的时候是在是太慢了怎么办

最近在家拉git项目发现npm i之后,开始下得挺快&#xff0c;过会就卡着不动了&#xff0c;大概几分钟后才下好。这对一个有强迫症的码农来说是不能容忍的。 只能退出去 重新下载 其实我们只要换一下国内的下载镜像源就好了 npm config set registry https://registry.npmmirror…

[C++][opencv]基于opencv实现photoshop算法灰度化图像

测试环境】 vs2019 opencv4.8.0 【效果演示】 【核心实现代码】 BlackWhite.hpp #ifndef OPENCV2_PS_BLACKWHITE_HPP_ #define OPENCV2_PS_BLACKWHITE_HPP_#include "opencv2/core.hpp"namespace cv {class BlackWhite { public:float red; //红色的灰度系…

vs code编辑区域右键菜单突然变短

今天打开vs code发现鼠标在编辑区域按右键&#xff0c;出来的菜单只显示一小段 显示不全&#xff0c;而之前的样子是 显示很多项&#xff0c;怎么设置回到显示很多项呢&#xff1f;

自动驾驶TPM技术杂谈 ———— 可行驶区域

文章目录 介绍基于传统计算机视觉的方法基于直接特征的可行驶区域检测基于颜色的可行驶区域检测基于纹理的可行驶区域检测基于边缘的可行驶区域检测 基于间接特征的可行驶区域检测 基于深度学习的方法语义分割基于FCN的可行驶区域分割 介绍 可行驶区域检测主要是为了自动驾驶提…

数据科学的定义,如果做数据科学,非计算机的你,一般来说最好还是选择R语言,图像挖掘除外

一、数据科学&#xff08;Data Science&#xff09; 数据科学的起源可以追溯到1962年&#xff0c;当时统计学家John W. Tukey在他的文章《数据分析的未来》中首次提出了数据分析作为一门独立的科学方法。1974年&#xff0c;计算机学家Peter Naur在《计算机方法的简明调研》中明…