From 5de769918293a85f8d4969419f9798f46236debf Mon Sep 17 00:00:00 2001 From: STEINNI Date: Sun, 15 Mar 2026 16:48:37 +0000 Subject: [PATCH] graflow: tempwire on creating new wire --- bzGraflow.js | 94 +++++++++++++++++---- graflow_examples/flows/testFlowEvent1.json | 98 ++++++++++++++++++++++ graflow_examples/test3.1.html | 98 ++++++++++++++++++++++ graflow_examples/test4.html | 1 + 4 files changed, 275 insertions(+), 16 deletions(-) create mode 100644 graflow_examples/flows/testFlowEvent1.json create mode 100644 graflow_examples/test3.1.html diff --git a/bzGraflow.js b/bzGraflow.js index 616af67..7f5b05b 100644 --- a/bzGraflow.js +++ b/bzGraflow.js @@ -644,11 +644,11 @@ class BZgraflow extends Buildoz{ return(path) } - autoPlace(orientation = 'horizontal', gapx = null, gapy = null, tween = null, align = null){ - if(gapx == null) gapx = parseInt(this.getBZAttribute('gapx')) || 80 - if(gapy == null) gapy = parseInt(this.getBZAttribute('gapy')) || 80 - if(tween == null) tween = parseInt(this.getBZAttribute('tween')) || 500 - if(align == null) align = this.getBZAttribute('align') || 'center' + autoPlace(orientation = 'horizontal', gapx = null, gapy = null, tween = null, align = null){ + if(gapx == null) gapx = parseInt(this.getBZAttribute('gapx')) || 80 + if(gapy == null) gapy = parseInt(this.getBZAttribute('gapy')) || 80 + if(tween == null) tween = parseInt(this.getBZAttribute('tween')) || 500 + if(align == null) align = this.getBZAttribute('align') || 'center' this.currentOrientation = orientation // Cancel any previous autoPlace() animations by bumping a token. @@ -795,7 +795,7 @@ class BZgraflow extends Buildoz{ this.moveNode(nid, x, y, orientation, tween, null, token) // Never increment parentsY for fake nodes: they're placeholders and must not disalign real children y = Math.max(y, placedY + gapy + fakeNodeHeight) - } + } parentsY[nid] = placedY nodeY[nid] = placedY nodeX[nid] = x @@ -1182,12 +1182,12 @@ class BZgraflow extends Buildoz{ Buildoz.define('graflow', BZgraflow) class MovingNodes{ + constructor(graflow, itemSelector, handleSelector = itemSelector){ this.graflow = graflow this.itemSelector = itemSelector this.handleSelector = handleSelector this.nodesContainer = this.graflow.mainContainer.querySelector('.bzgf-nodes-container') - this.state = null this.interactiveElementsSelector = ` .port, @@ -1197,6 +1197,9 @@ class MovingNodes{ button, a[href] ` + this._boundPointerDown = this.pointerDown.bind(this) + this._boundPointerMove = this.pointerMove.bind(this) + this._boundPointerUp = this.pointerUp.bind(this) this.graflow.addEventListener('refreshed', this.enableMovingNodes.bind(this)) } @@ -1210,21 +1213,21 @@ class MovingNodes{ } this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item => - item.addEventListener('pointerdown', this.pointerDown.bind(this)) + item.addEventListener('pointerdown', this._boundPointerDown) ) - this.nodesContainer.addEventListener('pointermove', this.pointerMove.bind(this)) + this.nodesContainer.addEventListener('pointermove', this._boundPointerMove) this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item => - item.addEventListener('pointerup', this.pointerUp.bind(this)) + item.addEventListener('pointerup', this._boundPointerUp) ) } disableMovingNodes(){ this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item => - item.removeEventListener('pointerdown', this.pointerDown.bind(this)) + item.removeEventListener('pointerdown', this._boundPointerDown) ) - this.nodesContainer.removeEventListener('pointermove', this.pointerMove.bind(this)) + this.nodesContainer.removeEventListener('pointermove', this._boundPointerMove) this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item => - item.removeEventListener('pointerup', this.pointerUp.bind(this)) + item.removeEventListener('pointerup', this._boundPointerUp) ) } @@ -1291,7 +1294,7 @@ class EditWires{ this.nodesContainer = this.graflow.mainContainer.querySelector('.bzgf-nodes-container') this.state = null this.graflow.tabIndex = 0 // Make keyboard reactive - + this._boundPointerMove = this.pointerMove.bind(this) this.graflow.addEventListener('refreshed', this.enableEditWires.bind(this)) this.graflow.addEventListener('refreshed', this.enableSelectPorts.bind(this)) this.graflow.addEventListener('wiresUpdated', this.enableEditWires.bind(this)) @@ -1322,19 +1325,68 @@ class EditWires{ if(this.currentlySelectedPort == port) { this.currentlySelectedPort.style.removeProperty('border') this.currentlySelectedPort = null + this.state = null + this.graflow.wiresContainer.removeEventListener('pointermove', this._boundPointerMove) + if(this.tempwire) this.tempwire.remove() return } if(this.currentlySelectedPort) { + this.tempwire.remove() + this.tempwire = null this.makeWireBetweenPorts(this.currentlySelectedPort, port) this.enableEditWires() this.currentlySelectedPort.style.removeProperty('border') this.currentlySelectedPort = null + this.state = null + this.graflow.wiresContainer.removeEventListener('pointermove', this._boundPointerMove) } else { + this.tension = parseInt(this.graflow.getBZAttribute('tension')) || 60 + this.wireType = this.graflow.getBZAttribute('wiretype') || 'bezier' this.currentlySelectedPort = port port.style.setProperty('border', '5px solid #FF0', 'important') + this.state = { + startX: e.clientX, + startY: e.clientY, + port + } + this.tempwire = document.createElementNS('http://www.w3.org/2000/svg', 'path') + this.graflow.wiresContainer.appendChild(this.tempwire) + this.tempwire.classList.add('bzgf-wire') + this.graflow.wiresContainer.addEventListener('pointermove', this._boundPointerMove) } } + + pointerMove(e){ + if(!this.state) return + const { port } = this.state + const bb = port.getBoundingClientRect() + const p1 = this.graflow.clientToSvg(bb.x + bb.width / 2, bb.y + bb.height / 2) + const p2 = this.graflow.clientToSvg(e.clientX, e.clientY) + const x1 = Math.floor(p1.x) + const y1 = Math.floor(p1.y) + const x2 = Math.floor(p2.x) + const y2 = Math.floor(p2.y) + const dir = port.dataset.direction + const c1x = x1 + this.tension * this.graflow.dirVect[dir].x + const c1y = y1 + this.tension * this.graflow.dirVect[dir].y + const c2x = x2 - this.tension * this.graflow.dirVect[dir].x + const c2y = y2 - this.tension * this.graflow.dirVect[dir].y + const node1 = port.closest('.bzgf-node') + const node2 = { offsetWidth: 0, offsetHeight: 0 } //Fake it for buildsegment + const seg = this.graflow.buildSegment( + x1, y1, + c1x, c1y, + c2x, c2y, + x2, y2, + this.wireType, + node1, node2, + dir, dir, + this.tension) + if(!seg) return + this.tempwire.setAttribute('d', `M ${x1} ${y1} ${seg}`) + } + makeWireBetweenPorts(port1, port2){ const node1 = port1.closest('.bzgf-node') const node2 = port2.closest('.bzgf-node') @@ -1370,8 +1422,18 @@ class EditWires{ return } if(e.key == 'Escape') { - if(this.currentlySelectedWire) this.currentlySelectedWire.style.setProperty('stroke', '#0000', 'important') - this.currentlySelectedWire = null + if(this.currentlySelectedWire) { + this.currentlySelectedWire.style.setProperty('stroke', '#0000', 'important') + this.currentlySelectedWire = null + } + if(this.currentlySelectedPort) { + this.currentlySelectedPort.style.removeProperty('border') + this.currentlySelectedPort = null + } + if(this.tempwire) { + this.tempwire.remove() + this.tempwire = null + } return } } diff --git a/graflow_examples/flows/testFlowEvent1.json b/graflow_examples/flows/testFlowEvent1.json new file mode 100644 index 0000000..caf880a --- /dev/null +++ b/graflow_examples/flows/testFlowEvent1.json @@ -0,0 +1,98 @@ +{ + "nodesFile": "./nodesLib/nodesEIC.html", + "flow": { + "nodes":[ + { "nodeType": "eicBasic", + "id": "config", + "ncoords": { "x": 50, "y": 120}, + "markup": { + "title": "Configure event", + "subtitle": "", + "severity": "warning" + } + }, + { "nodeType": "eicBasic", + "id": "mailinvit", + "ncoords": { "x": 100, "y": 220}, + "markup": { + "title": "Candidates invitation mailing", + "subtitle": "", + "severity": "success" + } + }, + { "nodeType": "eicBasic", + "id": "applicationsurvey", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Application survey", + "subtitle": "", + "severity": "success" + } + }, + { "nodeType": "eicBasic", + "id": "enrollment", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Candidates enrollment", + "subtitle": "", + "severity": "secondary" + } + }, + { "nodeType": "eicBasic", + "id": "mailwelcome", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Welcome mailing", + "subtitle": "", + "severity": "warning" + } + }, + { "nodeType": "eicBasic", + "id": "mailrejection", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Rejection mailing", + "subtitle": "", + "severity": "warning" + } + }, + { "nodeType": "eicBasic", + "id": "event", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Event", + "subtitle": "", + "severity": "secondary" + } + }, + { "nodeType": "eicBasic", + "id": "mailstatisfaction", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Satisfaction survey mailing", + "subtitle": "", + "severity": "success" + } + }, + { "nodeType": "eicBasic", + "id": "satisfactionsurvey", + "ncoords": { "x": 150, "y": 320}, + "markup": { + "title": "Satisfaction survey", + "subtitle": "", + "severity": "warning" + } + } + ], + "links": [ + { "from": ["config", "out1"], "to": ["mailinvit", "in1"] }, + { "from": ["mailinvit", "out1"], "to": ["applicationsurvey", "in1"] }, + { "from": ["applicationsurvey", "out1"], "to": ["enrollment", "in1"] }, + { "from": ["enrollment", "out1"], "to": ["mailwelcome", "in1"] }, + { "from": ["enrollment", "out1"], "to": ["mailrejection", "in1"] }, + { "from": ["mailwelcome", "out1"], "to": ["event", "in1"] }, + { "from": ["event", "out1"], "to": ["mailstatisfaction", "in1"] }, + { "from": ["mailstatisfaction", "out1"], "to": ["satisfactionsurvey", "in1"] } + ] + } +} \ No newline at end of file diff --git a/graflow_examples/test3.1.html b/graflow_examples/test3.1.html new file mode 100644 index 0000000..54fc996 --- /dev/null +++ b/graflow_examples/test3.1.html @@ -0,0 +1,98 @@ + + + + graflow + + + + + + + + + + + + +
+ + + + +
+
+
+ + diff --git a/graflow_examples/test4.html b/graflow_examples/test4.html index 40209c3..a1985cc 100644 --- a/graflow_examples/test4.html +++ b/graflow_examples/test4.html @@ -118,6 +118,7 @@ setTimeout(sevanimation, 1000) } grflw4.addEventListener('refreshed',() => { + if(aifmi) return aifmi = grflw4.stagedNodes['aifm-investment'].querySelector('.body') sevanimation() })