From 070be08dee9c8f11573b0afc547f84c759013f34 Mon Sep 17 00:00:00 2001 From: STEINNI Date: Sun, 1 Mar 2026 13:27:00 +0000 Subject: [PATCH] graflow: wireType straight --- bzGraflow.js | 120 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/bzGraflow.js b/bzGraflow.js index 249bffd..bcf2b3d 100644 --- a/bzGraflow.js +++ b/bzGraflow.js @@ -85,10 +85,11 @@ class BZgraflow extends Buildoz{ this.mainContainer.append(this.nodesContainer) this.append(this.hostContainer) this.loadFlow(flowUrl).then(() => { - if(this.hasAttribute('editable')){ + if((this.getBZAttribute('edit')=='move') || (this.getBZAttribute('edit')=='full')){ this.dnd = new MovingNodes(this) - this.dnd.enableMovingNodes('.bzgf-node') } - }) // Let it load async + this.dnd.enableMovingNodes('.bzgf-node') + } + }) } error(msg, err){ @@ -393,7 +394,7 @@ class BZgraflow extends Buildoz{ addWire(link){ const [idNode1, idPort1] = link.from const [idNode2, idPort2] = link.to - const path = this.bezierNodes(idNode1, idPort1, idNode2, idPort2, this.getBZAttribute('tension')) + const path = this.linkNodes(idNode1, idPort1, idNode2, idPort2) const id = `${idNode1}_${idNode2}` this.stagedWires[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path') this.stagedWires[id].setAttribute('d', path) @@ -458,8 +459,9 @@ class BZgraflow extends Buildoz{ return({ x: x - r.left, y: y - r.top }) } - bezierNodes(idNode1, idPort1, idNode2, idPort2, tension=60) { - tension = parseInt(tension) + linkNodes(idNode1, idPort1, idNode2, idPort2) { + const tension = parseInt(this.getBZAttribute('tension')) || 60 + const wireType = this.getBZAttribute('wiretype') || 'bezier' const node1 = this.stagedNodes[idNode1] const port1 = node1.ports[idPort1] const node2 = this.stagedNodes[idNode2] @@ -477,7 +479,6 @@ class BZgraflow extends Buildoz{ const x2 = Math.floor(p2.x) const y2 = Math.floor(p2.y) const loop = (idNode1==idNode2) && (idPort1==idPort2) - const dist = Math.abs(x2 - x1) + Math.abs(y2 - y1) let c1x = Math.floor(x1 + (this.dirVect[port1.direction].x * tension)) let c1y = Math.floor(y1 + (this.dirVect[port1.direction].y * tension)) @@ -492,42 +493,69 @@ class BZgraflow extends Buildoz{ c1y += 1*tension c2y -= 1*tension } - } - return(`M ${x1} ${y1} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`) + } + + if(wireType === 'bezier') { + return(`M ${x1} ${y1} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`) + } + if(wireType === 'straight') { + console.log('straight') + // Straight segments through the same control points + return(`M ${x1} ${y1} L ${c1x} ${c1y} L ${c2x} ${c2y} L ${x2} ${y2}`) + } + return('') + //return(`M ${x1} ${y1} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`) } - bezierInterNodes(idNode1, idPort1, idNode2, idPort2, interNodes, orientation='horizontal', tension=60) { - tension = parseInt(tension) + linkInterNodes(idNode1, idPort1, idNode2, idPort2, interNodes, orientation='horizontal') { + const tension = parseInt(this.getBZAttribute('tension')) || 60 + const wireType = this.getBZAttribute('wiretype') || 'bezier' const node1 = this.stagedNodes[idNode1] - let port1 = node1.ports[idPort1] + const port1 = node1.ports[idPort1] + const node2 = this.stagedNodes[idNode2] + const port2 = node2.ports[idPort2] + if(!node1 || !node2 || !port1 || !port2) { + console.warn('Link on bad node / port ', idNode1, idPort1, idNode2, idPort2) + return('') + } - const makeCubicBezier = (x1, y1, x2, y2, orientation1, orientation2) => { - const dist = Math.abs(x2 - x1) + Math.abs(y2 - y1) - - let c1x, c1y, c2x, c2y - if(orientation1=='horizontal'){ + const makeSegment = (x1, y1, x2, y2, orientation1, orientation2) => { + let c1x, c1y, c2x, c2y + if(orientation1=='horizontal') { c1x = Math.floor(x1 + tension) c1y = y1 } else { c1x = x1 c1y = Math.floor(y1 + tension) } - if(orientation2=='horizontal'){ + if(orientation2=='horizontal') { c2x = Math.floor(x2 - tension) c2y = y2 } else { c2x = x2 c2y = Math.floor(y2 - tension) } + if(wireType === 'bezier') { + return(`C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`) + } + if(wireType === 'straight') { + return(`L ${c1x} ${c1y} L ${c2x} ${c2y} L ${x2} ${y2}`) + } return(`C ${c1x} ${c1y}, ${c2x} ${c2y}, ${x2} ${y2}`) } - const directPath = this.bezierNodes(idNode1, idPort1, idNode2, idPort2, tension) - const startPath = directPath.substring(0,directPath.indexOf('C')) - const endPath = directPath.substring(directPath.lastIndexOf(',')+1).trim() - let path = startPath - let [ , x1, y1] = startPath.split(' ') - x1 = parseFloat(x1) - y1 = parseFloat(y1) + + // Start/end points in SVG coords (works for both bezier and line) + const bb1 = port1.el.getBoundingClientRect() + const bb2 = port2.el.getBoundingClientRect() + const sp = this.clientToSvg(bb1.x + (bb1.width/2), bb1.y + (bb1.height/2)) + const ep = this.clientToSvg(bb2.x + (bb2.width/2), bb2.y + (bb2.height/2)) + let x1 = Math.floor(sp.x) + let y1 = Math.floor(sp.y) + const xEnd = Math.floor(ep.x) + const yEnd = Math.floor(ep.y) + let path = `M ${x1} ${y1} ` + + let firstPort = port1 for(const interNode of interNodes){ const bb = this.stagedNodes[interNode].getBoundingClientRect() // Entry/exit points on the placeholder box, converted to SVG coords (handles CSS transforms) @@ -544,11 +572,11 @@ class BZgraflow extends Buildoz{ let x2 = Math.floor(entry.x) let y2 = Math.floor(entry.y) - if(port1){ - path += makeCubicBezier(x1, y1, x2, y2, ['w','e'].includes(port1.direction) ? 'horizontal' : 'vertical', orientation) - port1 = false + if(firstPort){ + path += makeSegment(x1, y1, x2, y2, ['w','e'].includes(firstPort.direction) ? 'horizontal' : 'vertical', orientation) + firstPort = null } else { - path += makeCubicBezier(x1, y1, x2, y2, orientation, orientation) + path += makeSegment(x1, y1, x2, y2, orientation, orientation) } const x3 = Math.floor(exit.x) @@ -558,10 +586,7 @@ class BZgraflow extends Buildoz{ x1 = x3 y1 = y3 } - let [x2, y2] = endPath.split(' ') - x2 = parseFloat(x2) - y2 = parseFloat(y2) - path += ' '+makeCubicBezier(x1, y1, x2, y2, orientation, orientation) + path += ' ' + makeSegment(x1, y1, xEnd, yEnd, orientation, orientation) return(path) } @@ -574,12 +599,7 @@ class BZgraflow extends Buildoz{ // Cleanup placeholders from previous autoPlace() runs. // Each run creates new longLinkPlaceHolder_* IDs; without cleanup they accumulate in the DOM. - for(const nid of Object.keys(this.stagedNodes || {})){ - if(!nid.startsWith('longLinkPlaceHolder_')) continue - const el = this.stagedNodes[nid] - if(el?.parentNode) el.parentNode.removeChild(el) - delete this.stagedNodes[nid] - } + this.clearFakeNodes() // Loops create infinite recursion in dfs for getting parents & adjacency lists: Remove them ! let linksWithoutBackEdges @@ -724,6 +744,15 @@ class BZgraflow extends Buildoz{ } } + clearFakeNodes(){ + for(const nid of Object.keys(this.stagedNodes || {})){ + if(!nid.startsWith('longLinkPlaceHolder_')) continue + const el = this.stagedNodes[nid] + if(el?.parentNode) el.parentNode.removeChild(el) + delete this.stagedNodes[nid] + } + } + getMaxWidth(layer){ return(layer.filter(nid => !nid.startsWith('longLinkPlaceHolder_')) @@ -849,7 +878,7 @@ class BZgraflow extends Buildoz{ const y = y0 + (desty - y0) * k el.style.left = `${x}px` el.style.top = `${y}px` - this.updateWires(nid, orientation) + this.updateWires(nid, orientation, true) if(p < 1) requestAnimationFrame(frame.bind(this)) else{ @@ -863,7 +892,7 @@ class BZgraflow extends Buildoz{ requestAnimationFrame(frame.bind(this)) } - updateWires(nid, orientation){ + updateWires(nid, orientation, LondLinkfix = false){ const wires = Object.keys(this.stagedWires) .filter(id => (id.startsWith(nid+'_')||id.endsWith('_'+nid))) .map(id => this.stagedWires[id]) @@ -873,11 +902,11 @@ class BZgraflow extends Buildoz{ if(!lnk) continue if(!this.flow?.longLinks) this.flow.longLinks = [] const longLink = this.flow.longLinks.find(item => (item.link.from[0] == lnk.from[0] && item.link.from[1] == lnk.from[1] && item.link.to[0] == lnk.to[0] && item.link.to[1] == lnk.to[1])) - if(longLink) { - const path = this.bezierInterNodes(nid1, lnk.from[1], nid2, lnk.to[1], longLink.interNodes, orientation, this.getBZAttribute('tension')) + if(longLink && LondLinkfix) { + const path = this.linkInterNodes(nid1, lnk.from[1], nid2, lnk.to[1], longLink.interNodes, orientation) wire.setAttribute('d', path) } else { - const path = this.bezierNodes(nid1, lnk.from[1], nid2, lnk.to[1], this.getBZAttribute('tension')) + const path = this.linkNodes(nid1, lnk.from[1], nid2, lnk.to[1]) wire.setAttribute('d', path) } } @@ -1051,6 +1080,7 @@ class MovingNodes{ } pointerDown(e){ + this.graflow.clearFakeNodes() const node = (e.target.classList.contains(this.itemSelector)) ? e.target : e.target.closest(this.itemSelector) const handle = (node.classList.contains(this.handleSelector)) ? node : node.querySelector(this.handleSelector) @@ -1081,7 +1111,7 @@ class MovingNodes{ const y = e.clientY - startY + offsetY node.style.left = `${x}px` node.style.top = `${y}px` - this.graflow.updateWires(node.dataset.id, this.graflow.currentOrientation) + this.graflow.updateWires(node.dataset.id, this.graflow.currentOrientation, false) } pointerUp(e){