基于canvas的流程编辑器

今年由于项目上需要给客户的流程管理系统进行升级,其中包含流程的可视化。于是在网上找一些可以用的轮子,考察了D3,js、GooFlow.js、G6-Editor等工具后,发现D3,js学习成本太高,G6-Editor功能基本够用,但是不能放大缩小图形和移动连接线是硬伤,而且GooFlow.js和G6-Editor目前已经闭源,于是就决定自己试着写一个流程编辑器。

由于之前画流程图基本使用的都是Visio,所以编辑器的操作风格基本和Visio一致,也吸收了一些G6-Editor的操作风格。

HTML内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Test Page</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="shortcut icon" href="assets/img/favicon.jpg">
        <link rel="stylesheet" href="assets/css/bootstrap.min.css" type="text/css" />
        <link rel="stylesheet" href="assets/css/font-awesome.min.css" type="text/css" />
        <link rel="stylesheet" href="assets/css/editor.css" type="text/css" />
    </head>
    <body>
        <div style="width:99%">
            <div id="toolbar" class="toolbar">
                <i data-command="undo" class="fa fa-mail-reply" title="撤销"></i>
                <i data-command="redo" class="fa fa-mail-forward" title="重做"></i>
                <i data-command="delete" class="fa fa-trash-o" title="删除"></i>
                <i data-command="save" class="fa fa-save" title="保存"></i>
            </div>
            <div class="row" style="width:99%">
                <div class="col-md-2">
                    <div id="itempannel" class="itempannel">
                        <div class="node" data-type="node" data-shape="capsule" data-size="80*40" data-label="开始" data-color="rgba(200,255,200,1)" data-edgecolor="rgb(10,255,10,1)" >
                            <img draggable="false" src="assets/img/start.svg" alt="" scrset="">
                        </div>
                        <div class="node" data-type="node" data-shape="rect" data-size="100*50" data-label="常规节点" data-color="#E6F7FF" data-edgecolor="#1890FF" >
                            <img draggable="false" src="assets/img/normal.svg" alt="" scrset="">
                        </div>
                        <div class="node" data-type="node" data-shape="rhomb" data-size="100*80" data-label="判断" data-color="#E6FFFB" data-edgecolor="#5CDBD3" >
                            <img draggable="false" src="assets/img/judge.svg" alt="" scrset="">
                        </div>
                        <div class="node" data-type="node" data-shape="capsule" data-size="80*40" data-label="结束" data-color="rgba(255,200,200,1)" data-edgecolor="rgb(255,50,50,1)" >
                            <img draggable="false" src="assets/img/end.svg" alt="" scrset="">
                        </div>
                    </div>
                </div>
                <div class="col-md-7">
                    <div id="canvas"></div>
                </div>
                <div class="col-md-3">
                    <div id="detailpannel" class="detailpannel">
                        <div><b>属性详情</b></div>
                        <div id="nodedetail" style="display:none">
                            <div class="row">
                                <label class="col-sm-4 control-label">
                                    节点名称
                                </label>
                                <div class="col-sm-8">
                                    <input id="nodename" type="text" class="form-control" />
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-sm-4 control-label">
                                    字体大小
                                </label>
                                <div class="col-sm-8">
                                    <input id="fontsize_node" type="text" class="form-control" />
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-sm-4 control-label">
                                    自定义属性
                                </label>
                                <div class="col-sm-8">
                                    <input id="nodecustom" type="text" class="form-control" />
                                </div>
                            </div>
                        </div>
                        <div id="linedetail" style="display:none">
                            <div class="row">
                                <label class="col-sm-4 control-label">
                                    线条名称
                                </label>
                                <div class="col-sm-8">
                                    <input id="linename" type="text" class="form-control" />
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-sm-4 control-label">
                                    字体大小
                                </label>
                                <div class="col-sm-8">
                                    <input id="fontsize_line" type="text" class="form-control" />
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-sm-4 control-label">
                                    自定义属性
                                </label>
                                <div class="col-sm-8">
                                    <input id="linecustom" type="text" class="form-control" />
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <script type="text/javascript" src="assets\js\popper.min.js"></script>
        <script type="text/javascript" src="assets\js\jquery.min.js"></script>
        <script type="text/javascript" src="assets\js\bootstrap.min.js"></script>
        <script type="text/javascript" src="assets\js\graphEditor.js"></script>
        <script type="text/javascript" src="assets\js\index.js"></script>
    </body>
</html>

其中graphEditor.js就是编辑器的js文件,编辑器的画布加载在id为canvas的容器中。

index.js文件内容如下:

const data = {};
//节点格式
data.nodes = [
    {
        color:"rgba(200,200,255,1)",
        customProperties: {
            nodestyle: "11"
        },
        edgeColor:"#1890FF",
        id: "9471a484-7a2e-4ca9-949d-6ec4b495a1a2",
        index: 1,
        label: "测试加载节点",
        shape: "rect",
        size: "100*50",
        type: "node",
        x: 282,
        y: 222
    },
    {
        color:"rgba(200,200,255,1)",
        customProperties: {
            nodestyle: "22"
        },
        edgeColor:"#1890FF",
        id: "9471a484-7a2e-4ca9-949d-6ec4b495a1a3",
        index: 2,
        label: "测试加载判断",
        shape: "rhomb",
        size: "100*80",
        type: "node",
        x: 282,
        y: 422,
        fontSize: "12px"
    }
]
//线条格式
data.lines = [
    {
        color:"rgba(0,0,0,1)",
        customProperties: {
            btnstyle: "test"
        },
        index: 3,
        label: "测试线条1",
        fontSize: "12px",
        fromConOrder: 3,
        source: "9471a484-7a2e-4ca9-949d-6ec4b495a1a2",
        type: "line",
        endPoint: { x: 81, y: 210 },
        inflexionPoint: [
            { x: 282, y: 272 },
            { x: 81, y: 272 }
        ]
    },
    {
        color:"rgba(0,0,0,1)",
        customProperties: {
            btnstyle: "test"
        },
        index: 4,
        label: "测试线条2",
        fontSize: "14px",
        toConOrder: 1,
        startPoint: { x: 555, y: 447 },
        target: "9471a484-7a2e-4ca9-949d-6ec4b495a1a3",
        type: "line",
        inflexionPoint: [
            { x: 555, y: 357 },
            { x: 282, y: 357 }
        ]
    }
]
//创建编辑器
const editor = new GraphEditor();
//编辑器加载数据
//editor.load(data);

//绑定元素容器
editor.itemPannel = ‘itempannel‘;
//绑定详细属性栏
editor.detailPannel = ‘detailpannel‘;
//绑定工具栏
editor.toolbar = ‘toolbar‘;
const nodeDetail = $(‘#nodedetail‘);
const lineDetail = $(‘#linedetail‘);
const nodeName = $(‘#nodename‘);
const lineName = $(‘#linename‘);
const nodeCustom = $(‘#nodecustom‘);
const lineCustom = $(‘#linecustom‘);
const nodeFontSize = $(‘#fontsize_node‘);
const lineFontSize = $(‘#fontsize_line‘);

//选择元素事件
editor.on(‘selectedElement‘, function(e) {
    if(e.element.isNode){
        lineDetail.hide();
        nodeDetail.show();
        nodeName.val(e.element.label);
        nodeFontSize.val(e.element.fontSize);
        nodeCustom.val(e.element.customProperties.nodestyle);
    } else if (e.element.isLine){
        nodeDetail.hide();
        lineDetail.show();
        lineName.val(e.element.label);
        lineFontSize.val(e.element.fontSize);
        lineCustom.val(e.element.customProperties.btnstyle);
    }
});
//点击画布事件
editor.on(‘click‘, function(e) {
    if(!e.element){
        nodeDetail.hide();
        lineDetail.hide();
    }
});
//撤销事件
editor.on(‘undo‘, function(e) {
    nodeDetail.hide();
    lineDetail.hide();
    //console.log(e.data);
});
//重做事件
editor.on(‘redo‘, function(e) {
    nodeDetail.hide();
    lineDetail.hide();
    //console.log(e.data);
});
//保存事件
editor.on(‘save‘, function(e) {console.log(e.data)});

nodeName.change(function(e){
    updateEditor(e, ‘label‘);
});

lineName.change(function(e){
    updateEditor(e, ‘label‘);
});

nodeFontSize.change(function(e){
    updateEditor(e, ‘fontSize‘);
});

lineFontSize.change(function(e){
    updateEditor(e, ‘fontSize‘);
});

nodeCustom.change(function(e){
    updateEditor(e, ‘nodestyle‘);
});

lineCustom.change(function(e){
    updateEditor(e, ‘btnstyle‘);
});

function updateEditor(e, name){
    const property = {};
    property.name = name;
    property.value = $(‘#‘ +e.target.id).val();
    if (editor.selectedElement){
        editor.update(editor.selectedElement.id, property);
    };
}

GraphEditor方法列表:

  • load(data):用于加载数据,data的结构参考index.js。

node节点的属性如下:

color:节点填充颜色

edgeColor:节点边框颜色

shape:“rect”为矩形,“rhomb”为菱形,“capsule”为胶囊

id:节点编号

index:节点层级

label:文字内容

fontSize:文字大小

size:节点的长和宽,例如“100*50”

type:“node”

x:节点x轴坐标

y:节点y轴坐标

customProperties:自定义属性,用于保存业务相关数据

line线条的属性如下:

color:线条颜色

id:线条编号

index:线条层级

label:文字内容

fontSize:文字大小

type:“line”

source:线条起始节点的编号

target:线条结束节点的编号

fromConOrder:起始节点对应的锚点编号

toConOrder:结束节点对应的锚点编号

startPoint:起始点坐标,用于无起始节点情况

endPoint:结束点坐标,用于无结束节点情况

inflexionPoint:线条拐点集合

  • update(id,property)

id:元素的编号

property:{ name: 要更新的属性名称, value:更新的值 }

GraphEditor事件列表:

  • selectedElement:选中任何canvas元素触发,事件对象的element属性存放选中的元素
  • click:点击canvas容器触发
  • undo:撤销操作触发
  • redo:重做操作触发
  • save:保存操作触发,事件对象的data属性存放画布中所有的元素,编辑器对象的data属性也包含画布所有元素

GraphEditor快捷键列表:

  • Delete:删除画布上的元素
  • Ctrl+z:撤销
  • Ctrl+y:重做
  • Ctrl+s:保存

Demo下载地址:https://files.cnblogs.com/files/lixincloud/GraphEditorDemo.rar

原文地址:https://www.cnblogs.com/lixincloud/p/11831095.html

时间: 2024-10-02 19:21:42

基于canvas的流程编辑器的相关文章

CodeMirror:基于JavaScript的代码编辑器

官方网站定义: http://codemirror.net/ CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for editing code, and comes with a number of language modes and addons that implement more advanced editing functionalit

基于Qt的流程设计器(一)

一: 先来看一下界面的截图: 说明: 拖动节点的时候,与该节点相关的箭头连线也会跟着调整: 用户可以使用鼠标从一个节点拖出一个箭头到另一个节点(鼠标在空白区域点击一下,拖出的箭头消失) 这三个图标,手型图标处于选中状态的时候,节点可以拖动, 箭头图标处于选中状态的时候,可以使用鼠标绘制连线箭头 最后一个图标,用于在画布上创建一个节点方框 二: 关键代码文件如下图(用红框框住的为关键代码文件) 其他文件均为辅助代码文件(有些文件中的代码没有用到) 三: CustomView类是我们的绘图面板,这个

Particles.js基于Canvas画布创建粒子原子颗粒效果

文章目录 使用方法 自定义参数 相关链接 Particles.js是一款基于HTML5 Canvas画布的轻量级粒子动画插件,可以设置粒子的形状.旋转.分布.颜色等属性,还可以动态添加粒子,效果非常炫酷,能和鼠标互动吸附或者是躲避鼠标指针. 使用方法 1.该粒子动画库插件使用方法非常简单,首先要在页面中引入particles.js文件. <script src="js/particles.js"></script> 2.在页面中使用一个div来作为放置粒子的容器

7个华丽的基于Canvas的HTML5动画

说起HTML5,可能让你印象更深的是其基于Canvas的动画特效,虽然Canvas在HTML5中的应用并不全都是动画制作,但其动画效果确实让人震惊.本文收集了7个最让人难忘的HTML5 Canvas动画,包括画板.文字.图表等,希望你会喜欢. 1.HTML5 Canvas画板画图工具 可定义笔刷和画布 HTML5 Canvas还有一个比较实用的应用,那就是网络画板,这样我们就可以在网页上直接进行画图操作.今天要分享的这款HTML5 Canvas画图工具就可以简单实现网络画图的功能,我们可以自定义

N个富文本编辑器/基于Web的HTML编辑器

转自:http://www.cnblogs.com/lingyuan/archive/2010/11/15/1877447.html 基于WEB的HTML 编辑器,WYSIWYG所见即所得的编辑器,或是一个富文本的编辑器,是我们在开发WEB应用时接收用户输入时必需要考虑的问题.下面是一些开源的WEB在线的WYSWIG编辑器. 1.FCKeditorFCKeditor 这些在线编辑器中最著名的一个,其功能相当的强大,很像一个Web的Word软件.它可以方便地和ASP, ASP.NET, PHP,

Tiny流程编辑器

流程编辑器是Tiny框架提供了编辑流程的图形化工具.目前支持的流程有逻辑流程和页面流程,未来也许会扩展其他的流程.         流程编辑器简介 后缀是*.flow或者*.pageflow的流程文件可以直接在Eclipse里面双击,调用相关编辑器打开:新建流程则按“New”-“Other”-“Tiny框架”的顺序,从向导界面选择适当的流程. 逻辑流程.处理具体业务组件的流程,包含的组件是逻辑组件(*.fc.xml),生成的逻辑流程文件(*.flow). 页面流程.处理控制层的流程,包含的组件是

基于canvas的仪表盘效果

概述 基于Canvas实现的仪表盘及效果.通过配置参数,可以任意修改仪表盘颜色,刻度,动画过渡时间等,满足不同场景下的使用.同时使用原生的Canvas,也是学习Canvas的很好的例子. 详细 代码下载:http://www.demodashi.com/demo/13031.html 一.演示效果 仪表盘效果如下: 二.项目结构截图 gauge.js文件是canvas仪表盘的主逻辑,demo.html中是使用的方法. 注:本例子只有2个文件,如上图所示. 三.使用方法 在html中,加入一个ca

Vue基于vue-quill-editor富文本编辑器

1.Vue基于vue-quill-editor富文本编辑器使用心得:https://www.cnblogs.com/ZaraNet/p/10209226.html 2.使用vue-quill-editor,获得到输入内容的html,怎样才能在外部的div中有跟编辑器里: 用v-html绑定一下就行了,加上class="ql-editor"的话,样式就和富文本录入的一样了,建议自己写样式,美观一点. 原文地址:https://www.cnblogs.com/zhengzemin/p/vu

基于Canvas的Char.js库使用

Chart.js是基于Html5 Canvas的图表库. 官网:http://www.chartjs.org/ 參考文档:http://www.chartjs.org/docs/ 支持六种图表,相应源代码相对文件夹例如以下. bar doughnut line pie polar-area radar