autofit fixed and simplified, thx Mike ! (Mike code readapted for edge cases)

This commit is contained in:
STEINNI
2026-07-29 13:50:47 +00:00
parent dfb1190e7b
commit 47f4e3e6c8
2 changed files with 32 additions and 71 deletions
+17 -61
View File
@@ -1332,69 +1332,25 @@ class BZgraflow extends Buildoz{
return(crossLayerLinks)
}
/**
* Union bounding boxes of nodes and wires (viewport coords).
* Same measurement strategy as autofit(). Call with transform cleared for stable sizes.
*/
getContentSize(){
let left = Infinity
let top = Infinity
let right = -Infinity
let bottom = -Infinity
const includeBB = (bb) => {
if(!bb) return
left = Math.min(left, bb.left)
top = Math.min(top, bb.top)
right = Math.max(right, bb.right)
bottom = Math.max(bottom, bb.bottom)
}
this.nodesContainer?.querySelectorAll?.('.bzgf-node').forEach(nodeEl => includeBB(nodeEl.getBoundingClientRect()))
this.wiresContainer?.querySelectorAll?.('path.bzgf-wire').forEach(path => includeBB(path.getBoundingClientRect()))
const gapx = parseInt(this.getBZAttribute('gapx')) || 80
const gapy = parseInt(this.getBZAttribute('gapy')) || 80
const hasBounds = Number.isFinite(left) && Number.isFinite(right) && Number.isFinite(top) && Number.isFinite(bottom)
const rawWidth = hasBounds ? Math.max(right - left, 1) : Math.max(this.mainContainer?.clientWidth || this.offsetWidth || 1, 1)
const rawHeight = hasBounds ? Math.max(bottom - top, 1) : Math.max(this.mainContainer?.clientHeight || this.offsetHeight || 1, 1)
return({
left: hasBounds ? left : null,
top: hasBounds ? top : null,
right: hasBounds ? right : null,
bottom: hasBounds ? bottom : null,
rawWidth,
rawHeight,
width: rawWidth + (2 * gapx),
height: rawHeight + (2 * gapy),
gapx,
gapy,
})
}
autofit(percent=100){
if(!this.parentElement) return
const prevTransformOrigin = this.style.transformOrigin
this.style.transform = 'none'
this.style.transformOrigin = 'top left'
const { left, top, width: contentW, height: contentH, gapx, gapy } = this.getContentSize()
const parentBB = this.parentElement.getBoundingClientRect()
const sx = parentBB.width / contentW
const sy = parentBB.height / contentH
const scale = Math.min(sx, sy)*(percent/100) // uniform scale to fit inside parent
const tx = left != null ? (-left + gapx) : gapx
const ty = top != null ? (-top + gapy) : gapy
if(!this.isSubflow) {
this.style.transformOrigin = prevTransformOrigin || 'top left'
this.style.transform = `scale(${scale}) translate(${tx}px, ${ty}px)`
} else {
this.style.transform = `scale(${scale})`
this.style.width = `calc(100% / ${scale})` // means 100% of the parent node DESPITE the scaling
this.style.height = `calc(100% / ${scale})` // means 100% of the parent node DESPITE the scaling
const outwidth = Math.max(this.clientWidth, 1)
const outheight = Math.max(this.clientHeight, 1)
let inwidth = this.nodesContainer.scrollWidth
let inheight = this.nodesContainer.scrollHeight
try { // SVG scrollWidth ignores overflowing paths; getBBox() covers wire extent.
const wireBB = this.wiresContainer.getBBox()
if(wireBB.width > 0 || wireBB.height > 0){
inwidth = Math.max(inwidth, wireBB.x + wireBB.width)
inheight = Math.max(inheight, wireBB.y + wireBB.height)
}
} catch(_){ // getBBox throws if SVG not rendered yet, but should not happen as we have _canRunAutoPlace() / _scheduleLayoutWhenReady()
return
}
const ratio = Math.min( (outwidth / inwidth), (outheight / inheight) ) * (percent / 100)
this.nodesContainer.style.scale = ratio
this.wiresContainer.style.scale = ratio
this.nodesContainer.style.transformOrigin = 'top left'
this.wiresContainer.style.transformOrigin = 'top left'
}
}
Buildoz.define('graflow', BZgraflow)
+13 -8
View File
@@ -45,19 +45,25 @@
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.icmp{ grid-column: 1 / -1; width: 100vw; height: 80vh; background: var(--eicui-base-color-grey-10); }
/* Fill the demo frame — autofit sizes to the graflow box, not the parent */
bz-graflow.icmp{
width: 100%;
height: 100%;
background: var(--eicui-base-color-grey-10);
}
.container {
resize: both;
overflow: auto; /* required in practice */
min-width: 800px;
min-height: 300px;
border: 1px solid #999;
overflow: hidden;
width: 90vw;
height: 80vh;
min-width: 400px;
min-height: 240px;
padding: 0;
position: relative;
border:2px solid #A00
border: 2px solid #A00;
box-sizing: border-box;
}
.container::after {
content: "";
@@ -102,7 +108,6 @@
)
const el = document.querySelector('.container')
let timer = null // debounce
const ro = new ResizeObserver(([entry]) => {
const grfl = entry.target.querySelector('bz-graflow')
grfl.autofit()