日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JointJs快速入门

發布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JointJs快速入门 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JointJS速覽

入門
Hello World
下面時官方給出的入門demo例子,可以看到 JointJS 依賴jquery、lodash、backbone,使用 JointJS 只需要引入joint.css和joint.js即可。定義一個div用來盛放繪制的圖形。

<!DOCTYPE html> <html> <head><link rel="stylesheet" type="text/css" href="css/joint.css" /> </head> <body> <!-- content --> <div id="myholder"></div> <!-- dependencies --> <script src="js/jquery.js"></script> <script src="js/lodash.js"></script> <script src="js/backbone.js"></script> <script src="js/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>

代碼解析
在上面的js代碼中,有以下幾類對象:

paper:JointJS中最外層的對象,用來連接內外:內部裝載的是哪個graph,外部是渲染在哪個div中。gridSize屬性是用來指明元素對齊的網格的大小。影響元素移動的粒度。paper在渲染過后,可以使用paper.scale()去實現縮放,使用paper.translate()去實現整體位移。paper的完整屬性可以參看這里。

graph:用來承載各個元素的畫布。

Rectangle:矩形元素。一個元素可以是通過構造器,如new joint.shapes.standard.Rectangle(),來實例化,也可以通過clone方法去得到。shapes.standard下提供了十幾種常見的圖形元素,比如圓形、橢圓、帶標題的矩形等等。官網提到,可以通過繼承Element對象,來自定義自己的元素。Element最常用的幾個方法如下:

element.position() - 設置元素原點(左上角)相對于paper坐標系的位置(考慮paper縮放和其他變換)。
element.resize() - 設置元素的尺寸。
element.clone() - 克隆現有元素,包括其位置,尺寸和屬性。
element.translate() - 沿兩個坐標軸移動元素指定的距離。還有縮放和旋轉元素的方法。
element.addTo() - 將元素添加到graph中以便可以呈現它。
每個元素都可以通過element.attr方法來重寫屬性。這個元素支持哪些屬性,可以通過joint.js中查看代碼來得知,比如Rectangle元素在joint.js中的定義代碼如下:

Element.define('standard.Rectangle', {attrs: {body: {refWidth: '100%',refHeight: '100%',strokeWidth: 2,stroke: '#000000',fill: '#FFFFFF'},label: {textVerticalAnchor: 'middle',textAnchor: 'middle',refX: '50%',refY: '50%',fontSize: 14,fill: '#333333'}} }, {markup: [{tagName: 'rect',selector: 'body',}, {tagName: 'text',selector: 'label'}] });

改變Element的屬性在上例html中演示了兩種寫法rect,rect2,個人感覺第二種更直觀。

Link:線條元素。指明線條的兩個端點即實現了連線。Link和普通的元素沒有很大區別。

中級

特殊屬性
相對維度
使用SVG時最常見的請求之一是相對設置SVGElements的維度。 JointJS允許您使用一組ref屬性來實現。這些屬性允許您將子元素的大小調整為形狀模型的尺寸的百分比。此外,由于所有計算都是程序化的,并且不依賴于瀏覽器的bbox測量,因此使用這些屬性不會影響應用程序的性能。

refWidth和refHeight - 設置子元素相對于模型bbox的寬度。
refX和refY - 設置子元素左上角相對于模型bbox左上角的坐標。百分比是相對于模型bbox的。
refCx和refCy - 設置圓/橢圓中心的坐標。百分比是相對于模型bbox的。可以與refX / refY一起使用。
refRx和refRy - 設置橢圓相對于模型bbox尺寸的半徑。百分比是相對于模型bbox的。
refR - 設置圓的半徑相對于模型bbox的短邊的長度。百分比是相對于模型bbox的。
refRCircumscribed - 設置圓的半徑相對于模型bbox的最長對角線。
基于文本的相對維度
暫不關心細節,略過。

Link箭頭
可以通過SourceMarker和TargetMarker為Link自定義箭頭,如下面的示例代碼為其定義了一個矩形箭頭和圓形箭尾:、

link.attr({line: {sourceMarker: {'type': 'rect','width': 50,'height': 10,'y': -5,'fill': 'rgba(255,0,0,0.3)','stroke': 'black'},targetMarker: {'type': 'circle','r': 10,'cx': 10,'fill': 'rgba(0,255,0,0.3)','stroke': 'black'}} });

事件

paper的內建事件
Paper提供了常見的事件捕捉,如單元格/元素/線條/空白處被點擊,鼠標移動,線條連接元素,線條取消連接元素等等,詳細的可參見。事件的回調寫法如下:

paper.on('blank:pointerdown', function(evt, x, y) {alert('pointerdown on a blank area in the paper.') })

連續的一組事件,可以共享數據,寫法如下:

// Create a new link by dragging paper.on({'blank:pointerdown': function(evt, x, y) {var link = new joint.dia.Link();link.set('source', { x: x, y: y });link.set('target', { x: x, y: y });link.addTo(this.model);evt.data = { link: link, x: x, y: y };},'blank:pointermove': function(evt, x, y) {evt.data.link.set('target', { x: x, y: y });},'blank:pointerup': function(evt) {var target = evt.data.link.get('target');if (evt.data.x === target.x && evt.data.y === target.y) {// remove zero-length linksevt.data.link.remove();}} });

graph的內建事件
graph提供了一些捕捉element位置變化、大小變化的事情,如change:position是監測element的位置發生了變化,change:target是監測link的指向發生了變化,示例代碼如下:

graph.on('change:position', function(cell) {var center = cell.getBBox().center();var label = center.toString();cell.attr('label/text', label); }); graph.on('change:target', function(cell) {var target = new g.Point(cell.target());var label = target.toString();cell.label(0, {attrs: {label: {text: label}}}); });

子元素監聽事件
在下面的代碼中定義了一個新的元素,他由一個矩形+一個按鈕組成。現在我們想監聽按鈕被點擊的事情,該怎么處理?注意97行代碼,我們需要通過子元素的event屬性,告知上層event是需要監聽的。然后通過paper.on來捕捉,并定義響應。

<!DOCTYPE html> <html> <head><link rel="stylesheet" type="text/css" href="css/joint.css" /> </head> <body> <!-- content --> <div id="paper"></div> <!-- dependencies --> <script src="js/jquery.js"></script> <script src="js/lodash.js"></script> <script src="js/backbone.js"></script> <script src="js/joint.js"></script> <!-- code --> <script type="text/javascript">var graph = new joint.dia.Graph;var paper = new joint.dia.Paper({el: document.getElementById('paper'),model: graph,width: 600,height: 100,gridSize: 10,drawGrid: true,background: {color: 'rgba(0, 255, 0, 0.3)'}});var CustomElement = joint.dia.Element.define('examples.CustomElement', {attrs: {body: {refWidth: '100%',refHeight: '100%',strokeWidth: 2,stroke: 'black',fill: 'white'},label: {textVerticalAnchor: 'middle',textAnchor: 'middle',refX: '50%',refY: '50%',fontSize: 14,fill: 'black'},button: {cursor: 'pointer',ref: 'buttonLabel',refWidth: '150%',refHeight: '150%',refX: '-25%',refY: '-25%'},buttonLabel: {pointerEvents: 'none',refX: '100%',refY: 0,textAnchor: 'middle',textVerticalAnchor: 'middle'}}}, {markup: [{tagName: 'rect',selector: 'body',}, {tagName: 'text',selector: 'label'}, {tagName: 'rect',selector: 'button'}, {tagName: 'text',selector: 'buttonLabel'}]});var element = new CustomElement();element.position(250, 30);element.resize(100, 40);element.attr({label: {pointerEvents: 'none',visibility: 'visible',text: 'Element'},body: {cursor: 'default',visibility: 'visible'},button: {event: 'element:button:pointerdown',fill: 'orange',stroke: 'black',strokeWidth: 2},buttonLabel: {text: '_', // fullwidth underscorefill: 'black',fontSize: 8,fontWeight: 'bold'}});element.addTo(graph);paper.on('element:button:pointerdown', function(elementView, evt) {evt.stopPropagation(); // stop any further actions with the element view (e.g. dragging)var model = elementView.model;if (model.attr('body/visibility') === 'visible') {model.attr('body/visibility', 'hidden');model.attr('label/visibility', 'hidden');model.attr('buttonLabel/text', '+'); // fullwidth plus} else {model.attr('body/visibility', 'visible');model.attr('label/visibility', 'visible');model.attr('buttonLabel/text', '_'); // fullwidth underscore}}); </script> </body> </html>

自定義視圖事件
對于更高級的事件自定義,我們可以通過重寫paper的默認view來實現,下面是示例代碼。在下面的例子中,我們禁用了默認的視圖,通過elementview和linkview重寫了事件。新的效果是,當某個元素或者線條被雙擊時會刪除它本身。

var paper = new joint.dia.Paper({el: document.getElementById('paper-custom-view-events'),model: graph,width: 600,height: 100,gridSize: 1,background: {color: 'white'},interactive: false, // disable default interaction (e.g. dragging)elementView: joint.dia.ElementView.extend({pointerdblclick: function(evt, x, y) {this.model.remove();}}),linkView: joint.dia.LinkView.extend({pointerdblclick: function(evt, x, y) {this.model.remove();}}) });

自定義元素
可以先看一下源碼中是如何定義一個Rectangle Element的,代碼如下:

joint.dia.Element.define('standard.Rectangle', {attrs: {body: {refWidth: '100%',refHeight: '100%',strokeWidth: 2,stroke: '#000000',fill: '#FFFFFF'},label: {textVerticalAnchor: 'middle',textAnchor: 'middle',refX: '50%',refY: '50%',fontSize: 14,fill: '#333333'}} }, {markup: [{tagName: 'rect',selector: 'body',}, {tagName: 'text',selector: 'label'}] });
  • 通過Element.define函數去聲明這是一個Element的定義。

  • standard.Rectangle是所定義Element的名稱,應是唯一的。這里隱藏了joint.shapes,所以實際上的全名是joint.shapes.standard.Rectangle。

  • markup是定義子元素的地方。tagName指明了子元素的名字rect->SVGRectElement,text->SVGTextElement。selector給出了兩個子元素的在本元素類的名稱。可以看出joint.js最底層是svg對象。

  • attrs設置默認屬性。使用在markup中定義的selector標識符,為各個子元素指定屬性。可以看到這里子元素的大小都是通過相對維度去設定的。

這里還沒有提到的是構造函數。在上面的元素定義中,還可以增加一個構造函數段,如下:

{createRandom: function() {var rectangle = new this();var fill = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);var stroke = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);var strokeWidth = Math.floor(Math.random() * 6);var strokeDasharray = Math.floor(Math.random() * 6) + ' ' + Math.floor(Math.random() * 6);var radius = Math.floor(Math.random() * 21);rectangle.attr({body: {fill: fill,stroke: stroke,strokeWidth: strokeWidth,strokeDasharray: strokeDasharray,rx: radius,ry: radius},label: { // ensure visibility on dark backgroundsfill: 'black',stroke: 'white',strokeWidth: 1,fontWeight: 'bold'}});return rectangle;}

這樣,使用的時候,就可以通過joint.shapes.standard.Rectangle.createRandom();來調用構造函數去創建元素對象。

自定義屬性
自定義屬性需要在使用時通過以下方法進行:

var rect3 = new joint.shapes.lefer.Rectangle() rect3.attr('bussiness/title', 'lefer');

需要注意的是,自定義的業務屬性需要在自定義元素時沒有出現過才能成功。

使用port
前面的示例中是在渲染時就指明了圖形的連接關系,還有一種很常見的情況是由用戶來拖拽連線。這個時候需要用到joint.shapes.devs.js。下面是示例代碼

WORKING WITH PORTS Many diagramming applications deal with elements with ports. Ports are usually displayed as circles inside diagram elements and are used not only as "sticky" points for connected links but they also further structure the linking information. It is common that certain elements have lists of input and output ports. A link might then point not to the element as a whole but to a certain port instead. JointJS has a built-in support for elements with ports, linking between ports and a facility for defining what connections are allowed and what not. This is useful if you, for example, want to restrict linking in between input ports, or output ports or between a certain port of an element A and a certain port of an element B. This tutorial shows you how you can do all that. Creating elements with ports The easiest way to start with elements with ports is using the joint.shapes.devs plugin. Search for joint.shapes.devs.js file. This plugin defines one important shape, the joint.shapes.devs.Model*. You can just instantiate that shape and pass the inPorts and outPorts arrays as parameters. You can further set the coloring of the ports and label for your element as you can see in the example below. Moreover, JointJS takes care of preparing the view and the magnets** for UI interaction. That's why you can already click and drag a port and JointJS automatically creates a link coming out of that port. JointJS and the joint.shapes.devs.Model also makes it easy to change ports. Simply set the inPorts/outPorts arrays of your element: element.set('inPorts', ['newIn1', 'newIn2', 'newIn3']); element.set('outPorts', ['newOut1', 'newOut2']); *DEVS is an abbreviation for Discrete EVent System specification and is a formalism for modeling and analyzing general systems. This formalism uses two types of models (Atomic and Coupled) both having a set of input and output ports. **Magnets in JointJS are SVG sub-elements that serve as sticky points for links. If you use the joint.shapes.devs plugin, you don't have to define your magnets yourself, instead the joint.shapes.devs.Model shape does it for you.(function() { var graph = new joint.dia.Graph; var paper = new joint.dia.Paper({ el: $('#paper-create'), width: 650, height: 200, gridSize: 1, model: graph }); var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }} }); graph.addCell(m1); }()); Linking elements with ports Now when you have your elements with ports created, you can start observing what port is connected with a link to what other port. This is easy to do thanks to JointJS storing the information about ports in the link models themselves once the links are created via the UI. The following example shows you how you can get the linking information. Try to connect a port of one element to another port of another element.(function() { var graph = new joint.dia.Graph; var paper = new joint.dia.Paper({ el: $('#paper-link'), width: 650, height: 200, gridSize: 1, model: graph }); var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }} }); graph.addCell(m1); var m2 = m1.clone().translate(300, 0).attr('.label/text', 'Model 2'); graph.addCell(m2); graph.on('change:source change:target', function(link) {var sourcePort = link.get('source').port;var sourceId = link.get('source').id;var targetPort = link.get('target').port;var targetId = link.get('target').id;var m = ['The port <b>' + sourcePort,'</b> of element with ID <b>' + sourceId,'</b> is connected to port <b>' + targetPort,'</b> of elemnt with ID <b>' + targetId + '</b>'].join('');out(m); }); function out(m) {$('#paper-link-out').html(m); } }()); Linking restrictions Now you know how to create elements with ports and how to get the linking information. Another practical functionality related to elements with ports and their links is restricting certain connections. Say you want links to never start in input ports and never end in output ports. This is the most usual case. However, all kinds of restrictions are possible and application specific. JointJS doesn't limit you. Instead, it allows you to define a function that simply returns true if a connection between a source magnet of a source element and a target magnet of a target element is allowed, and false otherwise. If the connection is not allowed JointJS does not connect the magnets (and associated ports). Furthermore, you can mark certain magnets as "passive" in which case JointJS treats these magnets in a way that they can never become a source of a link. For further information, please see the list of options that you can pass to the joint.dia.Paper in the API reference page, especially the two related functions: validateConnection() and validateMagnet().(function() { var graph = new joint.dia.Graph; var paper = new joint.dia.Paper({el: $('#paper-restrict'),width: 650, height: 200, gridSize: 1,model: graph,defaultLink: new joint.dia.Link({attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' } }}),validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {// Prevent linking from input ports.if (magnetS && magnetS.getAttribute('port-group') === 'in') return false;// Prevent linking from output ports to input ports within one element.if (cellViewS === cellViewT) return false;// Prevent linking to input ports.return magnetT && magnetT.getAttribute('port-group') === 'in';},validateMagnet: function(cellView, magnet) {// Note that this is the default behaviour. Just showing it here for reference.// Disable linking interaction for magnets marked as passive (see below `.inPorts circle`).return magnet.getAttribute('magnet') !== 'passive';} }); var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085',magnet: 'passive'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }} }); graph.addCell(m1); var m2 = m1.clone(); m2.translate(300, 0); graph.addCell(m2); m2.attr('.label/text', 'Model 2'); }()); Link snapping To improve user experience little bit you might want to enable the link snapping. While the user is dragging a link, it searches for the closest port in the given radius. Once a suitable port is found (it meets requirements specified in validateConnection()) the link automatically connects to it. You can try this functionality in the example below.(function() { var graph = new joint.dia.Graph; var paper = new joint.dia.Paper({el: $('#paper-link-snapping'),width: 650, height: 200, gridSize: 1,model: graph,defaultLink: new joint.dia.Link({attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' } }}),validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {// Prevent loop linkingreturn (magnetS !== magnetT);},// Enable link snapping within 75px lookup radiussnapLinks: { radius: 75 } }); var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085',magnet: 'passive'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }} }); graph.addCell(m1); var m2 = m1.clone(); m2.translate(300, 0); graph.addCell(m2); m2.attr('.label/text', 'Model 2'); })(); Marking available magnets Another way how to make user's life easier can be to offer him all magnets he can connect to while he is dragging a link. To achieve this you have to enable markAvailable option on the paper and add some css rules into your stylesheet like in the example bellow./* port styling */ .available-magnet {fill: yellow; } /* element styling */ .available-cell rect {stroke-dasharray: 5, 2; } (function() {var graph = new joint.dia.Graph;var paper = new joint.dia.Paper({el: $('#paper-mark-available'),width: 650, height: 200, gridSize: 1,model: graph,defaultLink: new joint.dia.Link({attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' } }}),validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {// Prevent linking from input ports.if (magnetS && magnetS.getAttribute('port-group') === 'in') return false;// Prevent linking from output ports to input ports within one element.if (cellViewS === cellViewT) return false;// Prevent linking to input ports.return magnetT && magnetT.getAttribute('port-group') === 'in';},// Enable marking available cells & magnetsmarkAvailable: true});var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085',magnet: 'passive'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }}}).addTo(graph);var m2 = m1.clone().translate(300, 0).attr('.label/text', 'Model 2').addTo(graph); })();

文章轉自;https://www.lefer.cn/posts/8954/

總結

以上是生活随笔為你收集整理的JointJs快速入门的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。