亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JointJS JavaScript流程圖繪制框架解析

2024-05-06 16:54:15
字體:
來源:轉載
供稿:網友

JointJS:JavaScript 流程圖繪制框架

最近調研了js畫流程圖的框架,最后選擇了Joint。配合上 dagre 可以畫出像模像樣的流程圖。

JointJS 簡介

JointJS 是一個開源前端框架,支持繪制各種各樣的流程圖、工作流圖等。Rappid 是 Joint 的商業版,提供了一些更強的插件。JointJS 的特點有下面幾條,摘自官網:

  • 能夠實時地渲染上百(或者上千)個元素和連接
  • 支持多種形狀(矩形、圓、文本、圖像、路徑等)
  • 高度事件驅動,用戶可自定義任何發生在 paper 下的事件響應
  • 元素間連接簡單
  • 可定制的連接和關系圖
  • 連接平滑(基于貝塞爾插值 bezier interpolation)& 智能路徑選擇
  • 基于 SVG 的可定制、可編程的圖形渲染
  • NodeJS 支持
  • 通過 JSON 進行序列化和反序列化

總之 JoingJS 是一款很強的流程圖制作框架,開源版本已經足夠日常使用了。

一些常用地址:

API: https://resources.jointjs.com/docs/jointjs/v1.1/joint.html

Tutorials: https://resources.jointjs.com/tutorial

JointJS Hello world

 

<!DOCTYPE html><html><head>  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" /></head><body>  <!-- content -->  <div id="myholder"></div>  <!-- dependencies 通過CDN加載依賴-->  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script>  <!-- code -->  <script type="text/javascript">    var graph = new joint.dia.Graph;    var paper = new joint.dia.Paper({      el: document.getElementById('myholder'),      model: graph,      width: 600,      height: 100,      gridSize: 1    });    var rect = new joint.shapes.standard.Rectangle();    rect.position(100, 30);    rect.resize(100, 40);    rect.attr({      body: {        fill: 'blue'      },      label: {        text: 'Hello',        fill: 'white'      }    });    rect.addTo(graph);    var rect2 = rect.clone();    rect2.translate(300, 0);    rect2.attr('label/text', 'World!');    rect2.addTo(graph);    var link = new joint.shapes.standard.Link();    link.source(rect);    link.target(rect2);    link.addTo(graph);  </script></body></html>

hello world 代碼沒什么好說的。要注意這里的圖形并沒有自動排版,而是通過移動第二個 rect 實現的手動排版。

JointJS,JavaScript,流程圖

前后端分離架構

既然支持 NodeJs,那就可以把繁重的圖形繪制任務交給服務器,再通過 JSON 序列化在 HTTP 上傳輸對象,這樣減輕客戶端的壓力。

NodeJS 后端

var express = require('express');var joint = require('jointjs');var app = express();function get_graph(){  var graph = new joint.dia.Graph();  var rect = new joint.shapes.standard.Rectangle();  rect.position(100, 30);  rect.resize(100, 40);  rect.attr({    body: {      fill: 'blue'    },    label: {      text: 'Hello',      fill: 'white'    }  });  rect.addTo(graph);  var rect2 = rect.clone();  rect2.translate(300, 0);  rect2.attr('label/text', 'World!');  rect2.addTo(graph);  var link = new joint.shapes.standard.Link();  link.source(rect);  link.target(rect2);  link.addTo(graph);  return graph.toJSON();}app.all('*', function(req, res, next) {  res.header("Access-Control-Allow-Origin", "*");  res.header("Access-Control-Allow-Headers", "X-Requested-With");  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  next();});app.get('/graph', function(req, res){  console.log('[+] send graph json to client')  res.send(get_graph());});app.listen(8071);

HTML 前端

 

<!DOCTYPE html><html><head>  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" /></head><body>  <!-- content -->  <div id="myholder"></div>  <!-- dependencies 通過CDN加載依賴-->  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script>  <!-- code -->  <script type="text/javascript">    var graph = new joint.dia.Graph;    var paper = new joint.dia.Paper({      el: document.getElementById('myholder'),      model: graph,      width: 600,      height: 100,      gridSize: 1    });    $.get('http://192.168.237.128:8071/graph', function(data, statue){      graph.fromJSON(data);    });  </script></body></html>

其他

自動布局 Automatic layout

JointJS 內置了插件進行自動排版,原理是調用 Dagre 庫。官方 api 中有樣例。

使用方法:

var graphBBox = joint.layout.DirectedGraph.layout(graph, {nodeSep: 50,edgeSep: 80,rankDir: "TB"});

 

配置參數 注釋
nodeSep 相同rank的鄰接節點的距離
edgeSep 相同rank的鄰接邊的距離
rankSep 不同 rank 元素之間的距離
rankDir 布局方向 ( "TB" (top-to-bottom) / "BT" (bottom-to-top) / "LR" (left-to-right) / "RL"(right-to-left))
marginX number of pixels to use as a margin around the left and right of the graph.
marginY number of pixels to use as a margin around the top and bottom of the graph.
ranker 排序算法。 Possible values: 'network-simplex' (default), 'tight-tree' or 'longest-path'.
resizeClusters set to false if you don't want parent elements to stretch in order to fit all their embedded children. Default is true.
clusterPadding A gap between the parent element and the boundary of its embedded children. It could be a number or an object e.g. { left: 10, right: 10, top: 30, bottom: 10 }. It defaults to 10.
setPosition(element, position) a function that will be used to set the position of elements at the end of the layout. This is useful if you don't want to use the default element.set('position', position) but want to set the position in an animated fashion via transitions.
setVertices(link, vertices) If set to true the layout will adjust the links by setting their vertices. It defaults to false. If the option is defined as a function it will be used to set the vertices of links at the end of the layout. This is useful if you don't want to use the default link.set('vertices', vertices) but want to set the vertices in an animated fashion via transitions.
setLabels(link, labelPosition, points) If set to true the layout will adjust the labels by setting their position. It defaults to false. If the option is defined as a function it will be used to set the labels of links at the end of the layout. Note: Only the first label (link.label(0);) is positioned by the layout.
dagre 默認情況下,dagre 應該在全局命名空間當中,不過你也可以當作參數傳進去
graphlib 默認情況下,graphlib 應該在全局命名空間當中,不過你也可以當作參數傳進去

 

我們來試一下。NodeJS 后端

var express = require('express');var joint = require('jointjs');var dagre = require('dagre')var graphlib = require('graphlib');var app = express();function get_graph(){  var graph = new joint.dia.Graph();  var rect = new joint.shapes.standard.Rectangle();  rect.position(100, 30);  rect.resize(100, 40);  rect.attr({    body: {      fill: 'blue'    },    label: {      text: 'Hello',      fill: 'white'    }  });  rect.addTo(graph);  var rect2 = rect.clone();  rect2.translate(300, 0);  rect2.attr('label/text', 'World!');  rect2.addTo(graph);  for(var i=0; i<10; i++){    var cir = new joint.shapes.standard.Circle();    cir.resize(100, 100);    cir.position(10, 10);    cir.attr('root/title', 'joint.shapes.standard.Circle');    cir.attr('label/text', 'Circle' + i);    cir.attr('body/fill', 'lightblue');    cir.addTo(graph);    var ln = new joint.shapes.standard.Link();    ln.source(cir);    ln.target(rect2);    ln.addTo(graph);  }  var link = new joint.shapes.standard.Link();  link.source(rect);  link.target(rect2);  link.addTo(graph);  //auto layout  joint.layout.DirectedGraph.layout(graph, {    nodeSep: 50,    edgeSep: 50,    rankDir: "TB",    dagre: dagre,    graphlib: graphlib  });  return graph.toJSON();}app.all('*', function(req, res, next) {  res.header("Access-Control-Allow-Origin", "*");  res.header("Access-Control-Allow-Headers", "X-Requested-With");  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  next();});app.get('/graph', function(req, res){  console.log('[+] send graph json to client')  res.send(get_graph());});app.listen(8071);

HTML 前端

<!DOCTYPE html><html><head>  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" /></head><body>  <!-- content -->  <div id="myholder"></div>  <!-- dependencies 通過CDN加載依賴-->  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script>  <!-- code -->  <script type="text/javascript">    var graph = new joint.dia.Graph;    var paper = new joint.dia.Paper({      el: document.getElementById('myholder'),      model: graph,      width: 2000,      height: 2000,      gridSize: 1    });    $.get('http://192.168.237.128:8071/graph', function(data, statue){      graph.fromJSON(data);    });  </script></body></html>

結果:

JointJS,JavaScript,流程圖

使用 HTML 定制元素

流程圖中的每個點,也就是是元素,都可以自定義,直接編寫 html 代碼能添加按鈕、輸入框、代碼塊等。

我的一個代碼塊 demo,搭配 highlight.js 可以達到類似 IDA 控制流圖的效果。這個 feature 可玩度很高。

joint.shapes.BBL = {};joint.shapes.BBL.Element = joint.shapes.basic.Rect.extend({  defaults: joint.util.deepSupplement({    type: 'BBL.Element',    attrs: {      rect: { stroke: 'none', 'fill-opacity': 0 }    }  }, joint.shapes.basic.Rect.prototype.defaults)});// Create a custom view for that element that displays an HTML div above it.// -------------------------------------------------------------------------joint.shapes.BBL.ElementView = joint.dia.ElementView.extend({  template: [    '<div class="html-element" data-collapse>',    '<label></label><br/>',    '<div class="hljs"><pre><code></code></pre></span></div>',    '</div>'  ].join(''),  initialize: function() {    _.bindAll(this, 'updateBox');    joint.dia.ElementView.prototype.initialize.apply(this, arguments);    this.$box = $(_.template(this.template)());    // Prevent paper from handling pointerdown.    this.$box.find('h3').on('mousedown click', function(evt) {      evt.stopPropagation();    });    // Update the box position whenever the underlying model changes.    this.model.on('change', this.updateBox, this);    // Remove the box when the model gets removed from the graph.    this.model.on('remove', this.removeBox, this);    this.updateBox();  },  render: function() {    joint.dia.ElementView.prototype.render.apply(this, arguments);    this.paper.$el.prepend(this.$box);    this.updateBox();    return this;  },  updateBox: function() {  // Set the position and dimension of the box so that it covers the JointJS element.    var bbox = this.model.getBBox();    // Example of updating the HTML with a data stored in the cell model.    this.$box.find('label').text(this.model.get('label'));    this.$box.find('code').html(this.model.get('code'));    var color = this.model.get('color');    this.$box.css({      width: bbox.width,      height: bbox.height,      left: bbox.x,      top: bbox.y,      background: color,      "border-color": color    });  },  removeBox: function(evt) {    this.$box.remove();  }});

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品国内自产拍在线观看| 欧美大人香蕉在线| www.xxxx精品| 在线观看国产欧美| 亚洲欧美日韩国产中文| 久久99视频免费| 精品偷拍各种wc美女嘘嘘| 欧美亚洲激情在线| 亚洲国产精品久久久久久| 国产丝袜精品第一页| 日韩在线观看免费高清完整版| 精品亚洲精品福利线在观看| 免费成人高清视频| 国产一区二区欧美日韩| 九九久久久久久久久激情| 日本不卡高字幕在线2019| 久久久久久香蕉网| 伊人伊成久久人综合网小说| 一个色综合导航| 欧美综合一区第一页| 国产精品欧美一区二区| 国产精品黄视频| 一区二区三区四区在线观看视频| 久久久久久久久久久91| 久久久久久久久久久人体| 日韩欧美在线观看| 久久精品免费播放| 国产91精品高潮白浆喷水| 亚洲欧美激情精品一区二区| 亚洲国产精品yw在线观看| 久久国产精品视频| 国外成人免费在线播放| 国内精久久久久久久久久人| 久久久国产精品亚洲一区| 亚洲欧美中文日韩在线| 欧美夫妻性生活视频| 日韩av在线免播放器| 国产成人一区二区三区小说| 精品精品国产国产自在线| 永久免费看mv网站入口亚洲| 欧美激情videos| 日韩欧美国产成人| 日韩在线视频线视频免费网站| 日本亚洲欧美成人| 欧美精品免费看| 亚洲国产精品久久精品怡红院| 亚洲国产精品小视频| 成人免费网站在线| 亚洲国产精品热久久| 国产精品三级美女白浆呻吟| 中文字幕亚洲一区在线观看| 欧美俄罗斯性视频| 日韩av电影中文字幕| 国产精品精品视频一区二区三区| 欧美专区在线播放| www.日韩视频| 亚洲视频一区二区三区| 国产精品欧美日韩久久| 欧洲s码亚洲m码精品一区| 日韩第一页在线| 日韩av网站导航| 久久69精品久久久久久久电影好| 亚洲欧洲免费视频| 俺去了亚洲欧美日韩| 国产精品视频白浆免费视频| 日韩中文字幕在线| 久久露脸国产精品| 久热国产精品视频| 日韩欧美在线网址| 国产亚洲精品久久久优势| 久久视频这里只有精品| 亚洲精品美女视频| 久久久之久亚州精品露出| 欧美大尺度激情区在线播放| 日本精品一区二区三区在线| 亚洲xxx视频| 91在线精品视频| 欧美国产日韩一区二区在线观看| 亚洲最大中文字幕| 亚洲成人av片| 国产精品aaa| 久久久久久69| 国产欧美一区二区三区视频| 久久国产精品影片| 亚洲电影免费观看高清完整版在线| 久久久999精品| 亚洲日本成人女熟在线观看| 91免费看视频.| 午夜精品一区二区三区在线| 国模吧一区二区| 亚洲美女动态图120秒| 欧美电影《睫毛膏》| 国产日韩欧美综合| 91久久久久久| 久久成人精品一区二区三区| 国产精品成人国产乱一区| 亚洲开心激情网| 久久久精品国产亚洲| 91久久精品日日躁夜夜躁国产| 欧洲永久精品大片ww免费漫画| xxxx欧美18另类的高清| 精品久久久精品| 久久精品久久精品亚洲人| 亚洲欧美国产视频| 亚洲大胆美女视频| 国产欧美 在线欧美| 日本成人精品在线| 欧美久久精品一级黑人c片| 日韩视频永久免费观看| 久久久www成人免费精品张筱雨| 国产精品视频公开费视频| 亚洲一级免费视频| 国产+成+人+亚洲欧洲| 久久久www成人免费精品| 国产精品高清在线| 成人在线中文字幕| 成人午夜小视频| 精品国产成人av| 国模私拍视频一区| 亚洲一区二区久久| 日韩一二三在线视频播| 热99精品只有里视频精品| 欧美第一黄网免费网站| 亚洲精品国精品久久99热| 日本人成精品视频在线| 高清日韩电视剧大全免费播放在线观看| 欧美尤物巨大精品爽| 午夜精品福利视频| 亚洲国产成人久久综合| 国产亚洲精品久久久| 亚洲欧美变态国产另类| 国产mv免费观看入口亚洲| 国产婷婷成人久久av免费高清| 国产玖玖精品视频| 日本亚洲欧美成人| 国产精品美腿一区在线看| 狠狠色狠狠色综合日日小说| 亚洲国产精品福利| 97在线视频免费观看| 国产啪精品视频网站| 亚洲欧美国产一区二区三区| 日韩视频免费观看| 成人福利在线观看| 国产精品电影在线观看| 久久精品久久久久久国产 免费| 亚洲国产精品字幕| 亚洲大胆美女视频| 91九色在线视频| 欧美巨大黑人极品精男| 欧美一级淫片videoshd| 日韩经典第一页| 日韩最新av在线| 亚洲精品成人久久久| 日韩av男人的天堂| 成人在线视频网| 日韩电影中文字幕在线| 欧美—级a级欧美特级ar全黄| 人九九综合九九宗合| 成人h片在线播放免费网站| 一区二区三区高清国产| 国产精品男女猛烈高潮激情| 26uuu另类亚洲欧美日本一| 美日韩丰满少妇在线观看| 欧美专区在线观看|