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

首頁 > 編程 > JavaScript > 正文

JointJS JavaScript流程圖繪制框架解析

2019-11-19 11:02:02
字體:
來源:轉載
供稿:網友

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"  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 實現的手動排版。

前后端分離架構

既然支持 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"  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"  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>

結果:

使用 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();  }});

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产精品女人久久久| 久久免费高清视频| 亚洲人成电影网站色xx| 91精品久久久久久久久| 亚洲第一精品久久忘忧草社区| 欧美精品久久久久久久久| 国产精品视频久久| 色一区av在线| 亚洲丁香婷深爱综合| 国产精品丝袜一区二区三区| 538国产精品一区二区免费视频| 2020国产精品视频| 久久艳片www.17c.com| 欧美激情精品久久久久久大尺度| 久久久久久久久亚洲| 久久躁日日躁aaaaxxxx| 亚洲国产精品字幕| 欧美日韩国产999| 欧美亚洲成人xxx| 久久精品国产久精国产思思| 国产有码在线一区二区视频| 亚洲国产欧美一区| 亚洲欧美日韩视频一区| 亚洲午夜未满十八勿入免费观看全集| 亚洲黄色av网站| 国产亚洲欧洲在线| 91午夜理伦私人影院| 日韩专区在线播放| 成人观看高清在线观看免费| 日韩电影免费在线观看中文字幕| 超薄丝袜一区二区| 国产日韩欧美在线播放| 欧美日韩国产精品专区| 在线观看亚洲视频| 欧美精品免费看| 欧美激情18p| 蜜月aⅴ免费一区二区三区| 97不卡在线视频| 国产精品久久一区| 欧美激情精品久久久久久久变态| 97久久精品在线| 亚洲国产成人久久综合一区| 精品久久久久久中文字幕| 欧美精品18videos性欧美| 欧美性高潮在线| 国产精品91久久久久久| 日韩中文在线观看| 欧美性感美女h网站在线观看免费| 中文字幕亚洲一区| 亚洲午夜未删减在线观看| 精品久久久香蕉免费精品视频| 在线观看中文字幕亚洲| 国产成人精品久久| 日韩av片免费在线观看| 国产精品美女久久久免费| 2021久久精品国产99国产精品| 成人精品福利视频| 亚洲精品视频久久| 久久久久免费精品国产| 久久福利视频网| 亚洲片国产一区一级在线观看| 久久精品电影网站| 日本欧美爱爱爱| 曰本色欧美视频在线| 2019中文在线观看| 91香蕉嫩草影院入口| 精品久久久久久中文字幕大豆网| 日韩在线观看免费全集电视剧网站| 欧美老女人性视频| 91久久久久久久久久久久久| 欧美激情久久久久| 蜜臀久久99精品久久久无需会员| 久久精品视频免费播放| 在线观看欧美日韩| 国产69精品久久久久久| 日本19禁啪啪免费观看www| 亚洲一区二区三区xxx视频| 亚洲国产日韩欧美在线图片| 欧美电影《睫毛膏》| 国内外成人免费激情在线视频| 久久免费精品日本久久中文字幕| 97在线精品视频| www.亚洲一区| 一区二区在线视频播放| 国产精品香蕉国产| 亚洲精品国产综合区久久久久久久| 欧美激情亚洲另类| 久久影视电视剧凤归四时歌| 欧美野外wwwxxx| 国产乱肥老妇国产一区二| 日韩一二三在线视频播| 亚洲精品电影在线观看| 亚洲色无码播放| 日本免费一区二区三区视频观看| 亚洲精品电影在线观看| 一区二区欧美久久| 欧美黄色三级网站| 91中文字幕在线观看| 欧美三级欧美成人高清www| 91精品国产91久久久久久不卡| 成人国产亚洲精品a区天堂华泰| 国产成人jvid在线播放| 日韩视频免费大全中文字幕| 青草热久免费精品视频| 日韩精品免费观看| 亚洲色图第三页| 88国产精品欧美一区二区三区| 欧美制服第一页| 亚洲人成绝费网站色www| 亚洲高清久久久久久| 久久亚洲精品小早川怜子66| 91国产一区在线| 成人欧美一区二区三区黑人孕妇| 最近中文字幕mv在线一区二区三区四区| 2019中文字幕免费视频| 久热精品视频在线观看| 欧美大片网站在线观看| 亚洲综合中文字幕在线观看| 欧美天天综合色影久久精品| 欧美午夜女人视频在线| 久久久国产成人精品| 日韩精品在线免费观看| 亚洲国产成人一区| 欧美福利视频在线观看| 国产综合在线视频| 中文字幕在线看视频国产欧美在线看完整| 青青在线视频一区二区三区| 久久777国产线看观看精品| 色偷偷综合社区| 国产不卡精品视男人的天堂| 国产精品黄页免费高清在线观看| 欧美激情精品久久久久久蜜臀| 成人激情视频免费在线| 亚洲福利在线看| 51午夜精品视频| 国产成人一区二区三区小说| 亚洲国产欧美久久| 久久99精品久久久久久琪琪| 日韩美女写真福利在线观看| 国产性猛交xxxx免费看久久| 欧美成人小视频| www.久久撸.com| 亚洲美女精品成人在线视频| 国产午夜精品视频| 欧美一级淫片aaaaaaa视频| 国产精品va在线播放我和闺蜜| 欧美性猛交xxxx乱大交极品| 日韩av片电影专区| 亚洲自拍欧美色图| 国产女精品视频网站免费| 亚洲最大中文字幕| 亚洲精品国产品国语在线| 欧美电影免费观看电视剧大全| 91在线精品播放| 日韩欧美在线视频观看| 欧美性xxxx| 欧美精品生活片| 欧美激情网友自拍| 国产一区二区视频在线观看| 亚洲激情 国产| 黑人巨大精品欧美一区二区三区| 欧美日韩国内自拍| 91免费版网站入口| 亚洲精品mp4|