Compare commits

..

36 Commits

Author SHA1 Message Date
STEINNI
158e9c4044 import flow OK 2026-03-30 19:57:21 +00:00
STEINNI
334cce8af3 export flow 2026-03-23 20:21:57 +00:00
STEINNI
266036a6ec graflowEditor: fixed gapy bug , graflow: update flow coords after move 2026-03-23 19:45:40 +00:00
STEINNI
0cb4491920 graflowEditor console 2026-03-22 20:42:04 +00:00
STEINNI
710bddd8e4 fixed chicked&egg&connectedCB issue between graflow & editor + fixed no Flow issue in graflow + Fixed nodesMove issue on displaced graflow + graflowEditor: DND ok 2026-03-22 15:29:48 +00:00
STEINNI
4122545cff fixed refacto of this.buildosUrl 2026-03-21 19:01:42 +00:00
STEINNI
e58ff43014 fireEvent + graflow uses new-style fireEvent 2026-03-21 15:49:40 +00:00
STEINNI
c3624d8aca graflow: autoplace uses live links 2026-03-15 18:54:14 +00:00
STEINNI
bf30315217 graflow: debugging autoplace on new links 2026-03-15 18:41:40 +00:00
STEINNI
46a344db74 graflow: improved landing of temp-wire on hovering dest port + improved test5 example to test it 2026-03-15 18:04:51 +00:00
STEINNI
5de7699182 graflow: tempwire on creating new wire 2026-03-15 16:48:37 +00:00
STEINNI
1dd5df8074 graflow playing with severity in test4 2026-03-11 22:07:16 +00:00
STEINNI
b15edd0e90 graflow: fixed interference between anti dbl-link and refresh 2026-03-11 18:30:39 +00:00
STEINNI
34e3989ef6 graflow: better (live) implementation of getLink + warning anti dbl-link 2026-03-11 18:22:17 +00:00
STEINNI
9c032b9b0b graflow: add wires ok 2026-03-11 17:49:53 +00:00
STEINNI
50810fec47 cleanup 2026-03-11 16:04:43 +00:00
STEINNI
67ce4fd1b0 graflow: fixing path 2026-03-10 21:18:31 +00:00
STEINNI
bfb96b7dde graflow: fixing path 2026-03-10 21:16:45 +00:00
STEINNI
dadb236bc3 graflow: fixing path 2026-03-10 21:14:53 +00:00
STEINNI
8cd1a65189 graflow: fixing path 2026-03-10 21:09:15 +00:00
STEINNI
c359aae479 Merge branch 'main' of https://gitea.internike.com/nike/buildoz 2026-03-10 21:05:58 +00:00
STEINNI
d90c63ceb4 graflow: fixing examples 2026-03-10 21:05:54 +00:00
STEINNI
313afec294 graflow examples:fixed paths 2026-03-10 21:04:40 +00:00
STEINNI
10276f7fd5 Merge branch 'main' of https://gitea.internike.com/nike/buildoz 2026-03-10 20:46:08 +00:00
STEINNI
860740f3fe graflow: relative paths in examples 2026-03-10 20:45:53 +00:00
STEINNI
2de301dbed Merge branch 'main' of https://gitea.internike.com/nike/buildoz 2026-03-10 20:36:26 +00:00
STEINNI
e55630f986 graflow: fix delete wires 2026-03-09 20:53:15 +00:00
STEINNI
301e44997f graflow: select unselect & delete wires 2026-03-09 20:47:08 +00:00
STEINNI
0ed56594ff graflow: improved test pages 2026-03-09 19:32:27 +00:00
STEINNI
080c919569 graflow: improved test pages 2026-03-09 19:28:34 +00:00
STEINNI
2efe358891 Merge branch 'main' of https://gitea.internike.com/nike/buildoz 2026-03-08 18:11:24 +00:00
STEINNI
451d8ae191 local examples 2026-03-08 18:11:20 +00:00
STEINNI
11d3247a8c graflow: rehresh event to fix movenodes 2026-03-08 16:58:01 +00:00
STEINNI
e41869a9e7 Merge branch 'main' of https://gitea.internike.com/nike/buildoz 2026-03-08 16:50:26 +00:00
STEINNI
03fe8696ec graflow: rehresh event to fix movenodes 2026-03-08 16:50:20 +00:00
STEINNI
f7d5f40c0f rapatriated graflow examples 2026-03-08 14:19:10 +00:00
27 changed files with 3322 additions and 127 deletions

View File

@@ -23,7 +23,7 @@ bz-select > button::after {
content: "\00BB"; content: "\00BB";
transform: rotate(90deg); transform: rotate(90deg);
position: absolute; position: absolute;
right: 0.5em; right: clamp(-1em, calc(100% - 1em), 0.5em);
top: 0; top: 0;
pointer-events: none; pointer-events: none;
font-size: 1.5em; font-size: 1.5em;
@@ -184,7 +184,7 @@ bz-slidepane[side="right"] div.handle {
top: 50%; top: 50%;
width: 11px; width: 11px;
height: 40px; height: 40px;
background: repeating-linear-gradient( to right, rgba(255,255,255,1) 0, rgba(255,255,255,1) 2px, rgba(0,0,0,0.2) 3px, rgba(0,0,0,0.2) 4px ); background: repeating-linear-gradient( to right, rgba(255,255,255,1) 0, rgba(255,255,255,1) 2px, rgba(0,0,0,0.5) 3px, rgba(0,0,0,0.5) 4px );
transform: translateY(-50%); transform: translateY(-50%);
cursor: ew-resize; cursor: ew-resize;
} }
@@ -195,14 +195,16 @@ bz-graflow {
position: relative; position: relative;
display: block; display: block;
width: 100vw; width: 100vw;
height: 50vh; height: 100vh;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden;
} }
bz-graflow .bzgf-main-container{ bz-graflow .bzgf-main-container{
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
overflow: auto;
} }
/* BZGRAFLOW_CORE_START */ /* BZGRAFLOW_CORE_START */
@@ -247,4 +249,82 @@ bz-graflow button.bzgf-zoom-out{
left: 5px; left: 5px;
top: 5px; top: 5px;
} }
bz-graflow path.bzgf-wirecoat{
pointer-events: auto;
stroke-width: 6;
stroke: #0000!important;
}
bz-graflow path.bzgf-wirecoat:hover{
stroke: #FF08!important;
}
bz-graflow .bzgf-nodes-container .port.selectable:hover{
border: 5px solid #FF08!important;
cursor: pointer;
}
bz-graflow .graflow-error{ background:red;color:black;position: absolute;top: 0;left: 50%;transform: translateX(-50%); }
/* BZGRAFLOW_CORE_END */ /* BZGRAFLOW_CORE_END */
bz-grafloweditor {
width: 98vw;
height: 98vh;
margin: auto;
}
bz-grafloweditor .bzgfe-main-container{
height: 100%;
width: 100%;
overflow: hidden;
display: grid;
grid-template-columns: 15vw auto;
grid-gap: 1px;
background: #FFF;
}
bz-grafloweditor .bzgfe-nodes-container{
overflow: auto;
border: 2px solid #000;
display: grid;
grid-auto-flow: row;
justify-items: center;
}
bz-grafloweditor bz-graflow{
height: 100%;
width: 100%;
}
bz-grafloweditor .bzgfe-nodes-container .bzgf-node{
position: relative;
margin: 5px auto;
}
bz-grafloweditor bz-slidepane { z-index: 10; background-color: #0008!important;}
bz-grafloweditor bz-slidepane .inner-console{
padding: 5px;
background: #FFF;
}
bz-grafloweditor .inner-console section{
display: grid;
grid-auto-flow: row;
grid-gap: 5px;
background-color: #DDD;
padding: 5px;
margin: 5px auto;
}
bz-grafloweditor .inner-console section .cols-2{
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 1em;
background-color: #CCC;
min-height: 2.5em;
}
bz-grafloweditor .inner-console section .cols-2 label{
text-align: right;
align-self: center;
}
bz-grafloweditor .inner-console section .cols-2 input{
max-height: 2em;
align-self: center;
}

View File

@@ -12,9 +12,17 @@
*/ */
class Buildoz extends HTMLElement { class Buildoz extends HTMLElement {
// static is evaluated when the class is defined, therefore while buildoz.js is executing.
// therefore document.currentScript refers to buildoz.js (but not later!!)
static _buildozUrl = document.currentScript?.src ?? ''
constructor(){ constructor(){
super() // always call super() first! super() // always call super() first!
this.attrs = {} this.attrs = {}
// Usefull for relative dependencies, to keep lib fully portable
this.buildozUrl = Buildoz._buildozUrl // was defined in the past
} }
static get observedAttributes(){ //observable attributes triggering attributeChangedCallback static get observedAttributes(){ //observable attributes triggering attributeChangedCallback
@@ -48,6 +56,17 @@ class Buildoz extends HTMLElement {
getBZAttribute(attrName){ // Little helper for defaults getBZAttribute(attrName){ // Little helper for defaults
return(this.getAttribute(attrName) || this.defaultAttrs[attrName] ) return(this.getAttribute(attrName) || this.defaultAttrs[attrName] )
} }
fireEvent(eventName, detail){
let myname = this.tagName.toLocaleLowerCase()
myname = myname.substring(myname.indexOf('-')+1)
const eventFullName = `bz:${myname}:${eventName}`
this.dispatchEvent(new CustomEvent(eventFullName, {
detail,
bubbles: true,
composed: true,
}))
}
} }
class BZselect extends Buildoz { class BZselect extends Buildoz {
@@ -271,6 +290,8 @@ class BZslidePane extends Buildoz {
} }
this.dragMove = this.dragMove.bind(this) this.dragMove = this.dragMove.bind(this)
this.dragEnd = this.dragEnd.bind(this) this.dragEnd = this.dragEnd.bind(this)
this.lastClientX = 0
this.lastClientY = 0
// Fill with innerHTML or other DOM manip should not allow coating to be removed // Fill with innerHTML or other DOM manip should not allow coating to be removed
this._observer = new MutationObserver(muts => { this.coat() }) this._observer = new MutationObserver(muts => { this.coat() })
} }
@@ -301,36 +322,61 @@ class BZslidePane extends Buildoz {
evt.target.setPointerCapture(evt.pointerId) evt.target.setPointerCapture(evt.pointerId)
this.dragStartX = evt.clientX this.dragStartX = evt.clientX
this.dragStartY = evt.clientY this.dragStartY = evt.clientY
this.lastClientX = evt.clientX
this.lastClientY = evt.clientY
this.handle.addEventListener('pointermove', this.dragMove) this.handle.addEventListener('pointermove', this.dragMove)
this.handle.addEventListener('pointerup', this.dragEnd) this.handle.addEventListener('pointerup', this.dragEnd)
} }
dragMove(evt){ dragMove(evt){
const box = this.getBoundingClientRect() const box = this.getBoundingClientRect()
const parentBox = this.parentElement.getBoundingClientRect() const boundaryEl = this.offsetParent || this.parentElement
let width, height const parentBox = boundaryEl.getBoundingClientRect()
let width, height, min, max
switch(this.getAttribute('side')){ switch(this.getAttribute('side')){
case 'top': case 'top':
height = (evt.clientY > box.top) ? (evt.clientY - box.top) : 0 min = parseInt(this.getBZAttribute('minheight')) || 0
if(height>(parentBox.height/2)) height = Math.floor(parentBox.height/2) if(evt.clientY > (box.top + min)) height = (evt.clientY - box.top)
else if(evt.clientY < this.lastClientY) height = min
else if(evt.clientY > this.lastClientY) height = 0
else break
max = parseInt(this.getBZAttribute('maxheight')) || Math.floor(parentBox.height/2)
height = Math.min(height, parentBox.height, max)
this.style.height = height+'px' this.style.height = height+'px'
break break
case 'bottom': case 'bottom':
height = (evt.clientY < box.bottom) ? (box.bottom - evt.clientY) : 0 min = parseInt(this.getBZAttribute('minheight')) || 0
if(height>(parentBox.height/2)) height = Math.floor(parentBox.height/2) if(evt.clientY < (box.bottom - min)) height = (box.bottom - evt.clientY)
else if(evt.clientY > this.lastClientY) height = min
else if(evt.clientY < this.lastClientY) height = 0
else break
max = parseInt(this.getBZAttribute('maxheight')) || Math.floor(parentBox.height/2)
height = Math.min(height, parentBox.height, max)
this.style.height = height+'px' this.style.height = height+'px'
break break
case 'left': case 'left':
width = (evt.clientX > box.left) ? (evt.clientX - box.left) : 0 min = parseInt(this.getBZAttribute('minwidth')) || 0
if(width>(parentBox.width/2)) width = Math.floor(parentBox.width/2) if(evt.clientX < (box.left + min)) width = (evt.clientX - box.left)
else if(evt.clientX > this.lastClientX) width = min
else if(evt.clientX < this.lastClientX) width = 0
else break
max = parseInt(this.getBZAttribute('maxwidth')) || Math.floor(parentBox.width/2)
width = Math.min(width, parentBox.width, max)
this.style.width = width+'px' this.style.width = width+'px'
break break
case'right': case 'right':
width = (evt.clientX < box.right) ? (box.right - evt.clientX) : 0 min = parseInt(this.getBZAttribute('minwidth')) || 0
if(width>(parentBox.width/2)) width = Math.floor(parentBox.width/2) if(evt.clientX < (box.right - min)) width = (box.right - evt.clientX)
else if(evt.clientX < this.lastClientX) width = min
else if(evt.clientX > this.lastClientX) width = 0
else break
max = parseInt(this.getBZAttribute('maxwidth')) || Math.floor(parentBox.width/2)
width = Math.min(width, parentBox.width, max)
this.style.width = width+'px' this.style.width = width+'px'
break break
} }
this.lastClientX = evt.clientX
this.lastClientY = evt.clientY
} }
dragEnd(evt){ dragEnd(evt){

191
bzGraflow-editor.js Normal file
View File

@@ -0,0 +1,191 @@
/**
* _ ___ Another
* / |/ (_)______ __ _____
* / / / __(_-</ // (_-<
* /_/|_/_/\__/___/\_, /___/
* /___/
* production !
*
* Licensed under the MIT License:
* This code is free to use and modify,
* as long as the copyright notice and license are kept.
*/
class BZgrafloweditor extends Buildoz{
constructor(){
super()
this.defaultAttrs = { }
window.debugEditor = this
}
async connectedCallback() {
await customElements.whenDefined('bz-graflow')
await customElements.whenDefined('bz-slidepane')
await customElements.whenDefined('bz-select')
super.connectedCallback()
const nodesUrl = this.getBZAttribute('nodes')
this.mainContainer = document.createElement('div')
this.mainContainer.classList.add('bzgfe-main-container')
this.nodesContainer = document.createElement('div')
this.nodesContainer.classList.add('bzgfe-nodes-container')
this.mainContainer.append(this.nodesContainer)
this.slidePane = document.createElement('bz-slidepane')
this.slidePane.setAttribute('side', 'right')
this.slidePane.setAttribute('data-output', 'console')
this.slidePane.setAttribute('maxwidth', '350')
this.slidePane.setAttribute('minwidth', '200')
this.fillconsole()
//this.mainContainer.append(this.slidePane)
this.graflow = document.createElement('bz-graflow')
this.graflow.setAttribute('nodes', nodesUrl)
this.graflow.setAttribute('edit', "nodesmove,editwires,dropnodes")
this.graflow.setAttribute('align', "center")
this.graflow.setAttribute('wiretype', "bezier")
this.graflow.setAttribute('tension', "30")
this.graflow.setAttribute('gapx', "80")
this.graflow.setAttribute('gapy', "80")
this.graflow.addEventListener('bz:graflow:domConnected', this.setupDropZone.bind(this))
this.graflow.append(this.slidePane)
this.mainContainer.append(this.graflow)
this.append(this.mainContainer)
document.querySelector('[data-trigger="onAutoplace1H"]').addEventListener('click',
(evt) => { this.graflow.autoPlace('horizontal', null, null, 1000, null) }
)
document.querySelector('[data-trigger="onAutoplace1V"]').addEventListener('click',
(evt) => { this.graflow.autoPlace('vertical', null, null, 1000, null) }
)
document.querySelector('input[name="tension"]').addEventListener('change',
(evt) => { this.graflow.setAttribute('tension', evt.target.value); this.graflow.refresh() }
)
document.querySelector('input[name="gapx"]').addEventListener('change',
(evt) => { this.graflow.setAttribute('gapx', evt.target.value); this.graflow.refresh() }
)
document.querySelector('input[name="gapy"]').addEventListener('change',
(evt) => { this.graflow.setAttribute('gapy', evt.target.value); this.graflow.refresh() }
)
document.querySelector('bz-select[name="wiretype"]').addEventListener('change',
(evt) => { this.graflow.setAttribute('wiretype', evt.target.value); this.graflow.refresh() }
)
document.querySelector('bz-select[name="align"]').addEventListener('change',
(evt) => { this.graflow.setAttribute('align', evt.target.value); this.graflow.refresh() }
)
this.graflow.addEventListener('bz:graflow:nodesLoaded', this.refreshNodes.bind(this))
this.graflow.loadNodes(nodesUrl)
}
fillconsole(){
this.slidePane.innerHTML = `
<div class="inner-console">
<section>
<button data-trigger="onAutoplace1H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace1V">Auto-place Vertical</button>
<div class="cols-2"><label>GapX</label><input name="gapx" type="number" size="2" value="80"></div>
<div class="cols-2"><label>GapY</label><input name="gapy" type="number" size="2" value="80"></div>
<div class="cols-2">
<label>Alignment</label>
<bz-select name="align">
<option value="center" selected>Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</bz-select>
</div>
<div class="cols-2">
<label>Wire Type</label>
<bz-select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight">Straight</option>
<option value="bezier" selected>Bezier</option>
</bz-select>
</div>
<div class="cols-2"><label>Tension</label><input name="tension" type="number" size="2" value="30"></div>
</section>
<section>
<button data-trigger="onImportFlow">Import Flow</button>
<button data-trigger="onExportFlow">Export Flow</button>
<input type="file" name="importFlow" accept="application/json" style="display: none;">
</section>
</div>
`
this.slidePane.querySelector('button[data-trigger="onExportFlow"]').addEventListener('click', this.onExportFlow.bind(this))
this.slidePane.querySelector('button[data-trigger="onImportFlow"]').addEventListener('click', this.onImportFlow.bind(this))
}
refreshNodes(e){
for(const nodeType in this.graflow.nodesRegistry){
const nodeDef = this.graflow.nodesRegistry[nodeType]
if(nodeDef.dataset.editor=='exclude') continue
const node = nodeDef.cloneNode(true)
this.makeNodeDraggable(node)
this.nodesContainer.append(node)
}
}
makeNodeDraggable(node){
node.draggable = true
node.style.cursor = 'pointer'
node.addEventListener('dragstart', (evt) => {
evt.dataTransfer.setData('text/plain', node.dataset.nodetype)
evt.dataTransfer.effectAllowed = 'copy'
evt.dataTransfer.setDragImage(node, evt.offsetX, evt.offsetY)
})
}
onNodeDragEnd(evt){
console.log('drag end', evt)
evt.dataTransfer.clearData()
}
setupDropZone(){
const dropZone = this.graflow.wiresContainer
const nodesContainer = this.graflow.nodesContainer
dropZone.addEventListener('dragover', (evt) => {
evt.preventDefault()
evt.dataTransfer.dropEffect = 'copy'
})
dropZone.addEventListener('drop', (evt) => {
evt.preventDefault()
const nodeType = evt.dataTransfer.getData('text/plain')
if(!nodeType || !(nodeType in this.graflow.nodesRegistry)) return
const rect = nodesContainer.getBoundingClientRect()
const x = evt.clientX - rect.left + nodesContainer.scrollLeft
const y = evt.clientY - rect.top + nodesContainer.scrollTop
const id = 'n' + crypto.randomUUID().replace(/-/g, '').slice(0, 8)
this.graflow.addNode({ id, nodeType, coords: { x, y } })
for(const node of this.graflow.flow.nodes){
if(node.id == id){
node.coords.x = x
node.coords.y = y
break
}
}
this.graflow.refresh()
})
}
onImportFlow(e){
const fileInput = this.slidePane.querySelector('input[name="importFlow"]')
fileInput.addEventListener('change', (evt) => {
const file = evt.target.files[0]
if(file) this.graflow.loadFlow(file)
fileInput.value = ''
}, { once: true })
fileInput.click()
}
onExportFlow(e){
const flowDeep = JSON.parse(JSON.stringify(this.graflow.flow))
delete flowDeep.longLinks
const exportObj = {
nodesFile: this.getBZAttribute('nodes'),
flow: flowDeep
}
const flowJson = JSON.stringify(exportObj, null, 2)
const flowBlob = new Blob([flowJson], { type: 'application/json' })
const flowUrl = URL.createObjectURL(flowBlob)
const flowLink = document.createElement('a')
flowLink.href = flowUrl
flowLink.download = 'flow.json'
flowLink.click()
}
}
Buildoz.define('grafloweditor', BZgrafloweditor)

View File

@@ -10,7 +10,6 @@
* This code is free to use and modify, * This code is free to use and modify,
* as long as the copyright notice and license are kept. * as long as the copyright notice and license are kept.
*/ */
class BZgraflow extends Buildoz{ class BZgraflow extends Buildoz{
dirVect = { dirVect = {
n: { x: 0, y: -1 }, n: { x: 0, y: -1 },
@@ -36,10 +35,11 @@ class BZgraflow extends Buildoz{
static _coreCssPromise = null static _coreCssPromise = null
static async getCoreCss(){ async getCoreCss(){
if(BZgraflow._coreCssPromise) return(await BZgraflow._coreCssPromise) if(BZgraflow._coreCssPromise) return(await BZgraflow._coreCssPromise)
BZgraflow._coreCssPromise = (async() => { BZgraflow._coreCssPromise = (async() => {
const res = await fetch('/app/thirdparty/buildoz/buildoz.css') const url = new URL('./buildoz.css', this.buildozUrl)
const res = await fetch(url)
const css = await res.text() const css = await res.text()
const m = css.match(/\/\*\s*BZGRAFLOW_CORE_START\s*\*\/([\s\S]*?)\/\*\s*BZGRAFLOW_CORE_END\s*\*\//) const m = css.match(/\/\*\s*BZGRAFLOW_CORE_START\s*\*\/([\s\S]*?)\/\*\s*BZGRAFLOW_CORE_END\s*\*\//)
const core = m ? m[1] : '' const core = m ? m[1] : ''
@@ -52,7 +52,7 @@ class BZgraflow extends Buildoz{
if(!this.hasAttribute('isolated')) return if(!this.hasAttribute('isolated')) return
if(this._isolatedCoreInjected) return if(this._isolatedCoreInjected) return
this._isolatedCoreInjected = true this._isolatedCoreInjected = true
const core = await BZgraflow.getCoreCss() const core = await this.getCoreCss()
// Convert light-dom selectors (`bz-graflow ...`) to shadow-dom selectors (`:host ...`) // Convert light-dom selectors (`bz-graflow ...`) to shadow-dom selectors (`:host ...`)
const shadowCss = core.replaceAll('bz-graflow', ':host') const shadowCss = core.replaceAll('bz-graflow', ':host')
const style = document.createElement('style') const style = document.createElement('style')
@@ -66,10 +66,6 @@ class BZgraflow extends Buildoz{
connectedCallback() { connectedCallback() {
super.connectedCallback() super.connectedCallback()
const flowUrl = this.getBZAttribute('flow')
if(!flowUrl) return // Be tolerant: maybe injected later from JS above
// If attribute "isolated" is present, render inside a shadow root.
// Otherwise, render in light DOM (no shadow DOM).
this.hostContainer = document.createElement('div') this.hostContainer = document.createElement('div')
this.hostContainer.classList.add('bzgf-main-container') this.hostContainer.classList.add('bzgf-main-container')
this.mainContainer = this.hasAttribute('isolated') this.mainContainer = this.hasAttribute('isolated')
@@ -84,41 +80,51 @@ class BZgraflow extends Buildoz{
this.mainContainer.append(this.wiresContainer) this.mainContainer.append(this.wiresContainer)
this.mainContainer.append(this.nodesContainer) this.mainContainer.append(this.nodesContainer)
this.append(this.hostContainer) this.append(this.hostContainer)
this.loadFlow(flowUrl).then(() => { if(this.getBZAttribute('edit')){
if(this.getBZAttribute('edit')){ const edit = this.getBZAttribute('edit').split(',')
const edit = this.getBZAttribute('edit').split(',') if(edit.includes('nodesmove')){
if(edit.includes('nodesmove')){ this.nodesMover = new MovingNodes(this, '.bzgf-node')
this.nodesMover = new MovingNodes(this)
this.nodesMover.enableMovingNodes('.bzgf-node')
}
if(edit.includes('wires')){
this.WiresEditor = new EditWires(this)
this.WiresEditor.enableEditWires()
//this.WiresEditor.enableMovingNodes('.bzgf-wire')
}
if(edit.includes('dropnodes')){
this.NodesReceiver = new DroppingNodes(this)
//this.NodesReceiver.enableDroppingNodes('.bzgf-node')
}
} }
}) if(edit.includes('editwires')){
this.WiresEditor = new EditWires(this, '.bzgf-wire')
}
if(edit.includes('dropnodes')){
this.NodesReceiver = new DroppingNodes(this, '.bzgf-node')
}
}
this.fireEvent('domConnected', { graflow: this })
const flowUrl = this.getBZAttribute('flow')
if(flowUrl) this.loadFlow(flowUrl)
else this.initFlow()
} }
error(msg, err){ error(msg, err){
this.innerHTML = `<div style="background:red;color:black;margin: auto;width: fit-content;">${msg}</div>` this.querySelector('.graflow-error')?.remove()
const errorEl = document.createElement('div')
errorEl.classList.add('graflow-error')
errorEl.innerHTML = `${msg}`
this.appendChild(errorEl)
if(err) console.error(msg, err) if(err) console.error(msg, err)
else console.error(msg) else console.error(msg)
} }
async loadFlow(url){ async loadFlow(source){
const res = await fetch(url+'?'+crypto.randomUUID()) let buf
const buf = await res.text() if(source instanceof Blob){
buf = await source.text()
} else {
const url = source
const fetchUrl = (typeof url === 'string' && !url.startsWith('blob:') && !url.startsWith('data:'))
? (url + '?' + crypto.randomUUID())
: url
const res = await fetch(fetchUrl)
buf = await res.text()
}
let flowObj let flowObj
try{ try{
flowObj = JSON.parse(buf) flowObj = JSON.parse(buf)
} catch(err){ } catch(err){
this.error('Could not parse flow JSON!?', err) this.error('Could not parse flow JSON!?', err)
return return
} }
if(!flowObj.nodesFile){ if(!flowObj.nodesFile){
@@ -128,11 +134,11 @@ class BZgraflow extends Buildoz{
await this.loadNodes(flowObj.nodesFile) await this.loadNodes(flowObj.nodesFile)
this.flow = flowObj.flow this.flow = flowObj.flow
this.refresh() this.refresh()
this.dispatchEvent(new CustomEvent('flowLoaded', { this.fireEvent('flowLoaded', { url: source instanceof Blob ? null : source, blob: source instanceof Blob ? source : null })
detail: { url }, }
bubbles: true,
composed: true, initFlow(){
})) this.flow = { nodes: [], links: [] }
} }
async loadNodes(url) { async loadNodes(url) {
@@ -175,11 +181,7 @@ class BZgraflow extends Buildoz{
BZgraflow._loadedNodeStyles.add(url) BZgraflow._loadedNodeStyles.add(url)
} }
} }
this.dispatchEvent(new CustomEvent('nodesLoaded', { this.fireEvent('nodesLoaded', { url: url })
detail: { url },
bubbles: true,
composed: true,
}))
} }
addNode(node){ addNode(node){
@@ -241,7 +243,7 @@ class BZgraflow extends Buildoz{
this.invade(this, childEl) this.invade(this, childEl)
childEl.hostContainer.appendChild(btnExitSubflow) childEl.hostContainer.appendChild(btnExitSubflow)
childEl.addEventListener('flowLoaded', (e) => { childEl.addEventListener('bz:graflow:flowLoaded', (e) => {
for(const portLink of flowNode.subflow.portLinks){ for(const portLink of flowNode.subflow.portLinks){
const nid = crypto.randomUUID() const nid = crypto.randomUUID()
childEl.addNode({ childEl.addNode({
@@ -305,12 +307,8 @@ class BZgraflow extends Buildoz{
this.hostContainer.style.visibility = 'hidden' this.hostContainer.style.visibility = 'hidden'
childEl.style.transform = 'none' // Important for nested subflows to position correctly childEl.style.transform = 'none' // Important for nested subflows to position correctly
childEl.style.willChange = '' childEl.style.willChange = ''
newEl.style.overflow = 'auto' childEl.style.overflow = 'auto'
this.dispatchEvent(new CustomEvent('subflowLoaded', { this.fireEvent('subflowLoaded', { subflow: childEl })
detail: { subflow: childEl },
bubbles: true,
composed: true,
}))
}, { once:true }) }, { once:true })
} }
@@ -385,11 +383,7 @@ class BZgraflow extends Buildoz{
this.hostContainer.style.opacity = '1' this.hostContainer.style.opacity = '1'
this.hostContainer.style.visibility = 'visible' this.hostContainer.style.visibility = 'visible'
childEl.style.willChange = '' childEl.style.willChange = ''
this.dispatchEvent(new CustomEvent('subflowExited', { this.fireEvent('subflowExited', { subflow: childEl })
detail: { subflow: childEl },
bubbles: true,
composed: true,
}))
}, { once:true }) }, { once:true })
} }
@@ -408,6 +402,10 @@ class BZgraflow extends Buildoz{
addWire(link){ addWire(link){
const [idNode1, idPort1] = link.from const [idNode1, idPort1] = link.from
const [idNode2, idPort2] = link.to const [idNode2, idPort2] = link.to
if(this.getLink(idNode1,idNode2)) {
console.warn('Current version of graflow does not allow multiple wires between same nodes',this.getLink(idNode1,idNode2),idNode1,idNode2)
return
}
const path = this.linkNodes(idNode1, idPort1, idNode2, idPort2) const path = this.linkNodes(idNode1, idPort1, idNode2, idPort2)
const id = `${idNode1}_${idNode2}` const id = `${idNode1}_${idNode2}`
this.stagedWires[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path') this.stagedWires[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path')
@@ -417,6 +415,7 @@ class BZgraflow extends Buildoz{
if(this.arrowDefs && link.startArrow) this.stagedWires[id].setAttribute('marker-start','url(#arrow)') if(this.arrowDefs && link.startArrow) this.stagedWires[id].setAttribute('marker-start','url(#arrow)')
this.stagedWires[id].classList.add('bzgf-wire') this.stagedWires[id].classList.add('bzgf-wire')
this.stagedWires[id].dataset.id = id this.stagedWires[id].dataset.id = id
this.stagedWires[id].link = link
this.wiresContainer.append(this.stagedWires[id]) this.wiresContainer.append(this.stagedWires[id])
if(!this.flow.links.find(l => l.from[0] === idNode1 && l.from[1] === idPort1 && l.to[0] === idNode2 && l.to[1] === idPort2)) { if(!this.flow.links.find(l => l.from[0] === idNode1 && l.from[1] === idPort1 && l.to[0] === idNode2 && l.to[1] === idPort2)) {
this.flow.links.push(link) this.flow.links.push(link)
@@ -425,6 +424,8 @@ class BZgraflow extends Buildoz{
} }
clear(){ clear(){
this.stagedNodes = {}
this.stagedWires = {}
this.nodesContainer.innerHTML = '' this.nodesContainer.innerHTML = ''
this.wiresContainer.innerHTML = '' this.wiresContainer.innerHTML = ''
if(this.arrowDefs) this.wiresContainer.appendChild(this.arrowDefs) if(this.arrowDefs) this.wiresContainer.appendChild(this.arrowDefs)
@@ -446,6 +447,7 @@ class BZgraflow extends Buildoz{
else this.currentOrientation = 'vertical' else this.currentOrientation = 'vertical'
} }
if(forceAutoplace) this.autoPlace(this.currentOrientation) if(forceAutoplace) this.autoPlace(this.currentOrientation)
this.fireEvent('refreshed', { })
} }
// Convert viewport (client) coordinates to this instance's SVG local coordinates. // Convert viewport (client) coordinates to this instance's SVG local coordinates.
@@ -635,11 +637,11 @@ class BZgraflow extends Buildoz{
return(path) return(path)
} }
autoPlace(orientation = 'horizontal', gapx = null, gapy = null, tween = null, align = null){ autoPlace(orientation = 'horizontal', gapx = null, gapy = null, tween = null, align = null){
if(gapx == null) gapx = parseInt(this.getBZAttribute('gapx')) || 80 if(gapx == null) gapx = parseInt(this.getBZAttribute('gapx')) || 80
if(gapy == null) gapy = parseInt(this.getBZAttribute('gapy')) || 80 if(gapy == null) gapy = parseInt(this.getBZAttribute('gapy')) || 80
if(tween == null) tween = parseInt(this.getBZAttribute('tween')) || 500 if(tween == null) tween = parseInt(this.getBZAttribute('tween')) || 500
if(align == null) align = this.getBZAttribute('align') || 'center' if(align == null) align = this.getBZAttribute('align') || 'center'
this.currentOrientation = orientation this.currentOrientation = orientation
// Cancel any previous autoPlace() animations by bumping a token. // Cancel any previous autoPlace() animations by bumping a token.
@@ -650,17 +652,17 @@ class BZgraflow extends Buildoz{
// Cleanup placeholders from previous autoPlace() runs. // Cleanup placeholders from previous autoPlace() runs.
// Each run creates new longLinkPlaceHolder_* IDs; without cleanup they accumulate in the DOM. // Each run creates new longLinkPlaceHolder_* IDs; without cleanup they accumulate in the DOM.
this.clearFakeNodes() this.clearFakeNodes()
let links = Object.values(this.stagedWires).map(w => w?.link).filter(Boolean)
links = links.length ? links : (this.flow?.links || [])
// Loops create infinite recursion in dfs for getting parents & adjacency lists: Remove them ! // Loops create infinite recursion in dfs for getting parents & adjacency lists: Remove them !
let linksWithoutBackEdges let linksWithoutBackEdges
if(this.hasAnyLoop(this.flow.nodes, this.flow.links)){ if(this.hasAnyLoop(this.flow.nodes, links)){
const backEdges = this.findBackEdges(this.flow.nodes, this.flow.links) const backEdges = this.findBackEdges(this.flow.nodes, links)
linksWithoutBackEdges = this.flow.links.filter((link, idx) => (!backEdges.includes(idx)) && (link.from[0] != link.to[0])) linksWithoutBackEdges = links.filter((link, idx) => (!backEdges.includes(idx)) && (link.from[0] != link.to[0]))
} else { } else {
linksWithoutBackEdges = this.flow.links linksWithoutBackEdges = links
} }
const { parents, adj } = this.buildGraphStructures(this.flow.nodes, linksWithoutBackEdges) const { parents, adj } = this.buildGraphStructures(this.flow.nodes, linksWithoutBackEdges)
const layers = this.computeLayers(this.flow.nodes, parents) const layers = this.computeLayers(this.flow.nodes, parents)
// Layer-0 nodes have no parents, so reorderLayers() (which uses parent ordering) cannot // Layer-0 nodes have no parents, so reorderLayers() (which uses parent ordering) cannot
@@ -709,10 +711,9 @@ class BZgraflow extends Buildoz{
layerWidths.push(totWidth) layerWidths.push(totWidth)
} }
// If any long-links, create placeholders for skipped layers // If any long-links, create placeholders for skipped layers
this._virtualLinks = new Map() this._virtualLinks = new Map()
this.flow.longLinks = this.findLongLinks(this.flow.links) this.flow.longLinks = this.findLongLinks(links)
for(const llink of this.flow.longLinks){ for(const llink of this.flow.longLinks){
let fakeParent = llink.link.from[0] let fakeParent = llink.link.from[0]
for(const layerIdx of llink.skippedLayers){ for(const layerIdx of llink.skippedLayers){
@@ -761,6 +762,7 @@ class BZgraflow extends Buildoz{
y = ((maxHeight - layerHeights[idx]) / 2) + gapy y = ((maxHeight - layerHeights[idx]) / 2) + gapy
break break
} }
console.log('======>',gapy, y)
for(const nid of layer){ for(const nid of layer){
let placedY let placedY
if(!nid.startsWith('longLinkPlaceHolder_')) { if(!nid.startsWith('longLinkPlaceHolder_')) {
@@ -768,7 +770,6 @@ class BZgraflow extends Buildoz{
const nodeHeight = this.stagedNodes[nid].offsetHeight || bb.height const nodeHeight = this.stagedNodes[nid].offsetHeight || bb.height
if((align == 'parent') && (nid in parents) && (parents[nid][0] in parentsY)) { if((align == 'parent') && (nid in parents) && (parents[nid][0] in parentsY)) {
y = Math.max(parentsY[parents[nid][0]], y) //TODO handle multiple parents with avg y = Math.max(parentsY[parents[nid][0]], y) //TODO handle multiple parents with avg
console.log('parent', nid, parents[nid], parentsY[parents[nid][0]])
} }
placedY = y placedY = y
this.moveNode(nid, x, y, orientation, tween, null, token) this.moveNode(nid, x, y, orientation, tween, null, token)
@@ -985,11 +986,13 @@ class BZgraflow extends Buildoz{
if(p < 1) requestAnimationFrame(frame.bind(this)) if(p < 1) requestAnimationFrame(frame.bind(this))
else{ else{
this.dispatchEvent(new CustomEvent('nodeMoved', { const flowNode = this.flow?.nodes?.find(n => n.id === nid)
detail: { nid, x, y }, if(flowNode) {
bubbles: true, if(!flowNode.coords) flowNode.coords = {}
composed: true, flowNode.coords.x = x
})) flowNode.coords.y = y
}
this.fireEvent('nodeMoved', { nid, x, y })
} }
} }
requestAnimationFrame(frame.bind(this)) requestAnimationFrame(frame.bind(this))
@@ -1013,15 +1016,13 @@ class BZgraflow extends Buildoz{
wire.setAttribute('d', path) wire.setAttribute('d', path)
} }
} }
this.fireEvent('wiresUpdated', { nid, orientation, LondLinkfix })
} }
getLink(nid1, nid2){ getLink(nid1, nid2){
let lnk = null const wire = this.stagedWires[`${nid1}_${nid2}`]
lnk = this.flow.links.find(item => ((item.from[0]==nid1) && (item.to[0]==nid2))) if(wire?.link) return wire.link
if(!lnk) { return this._virtualLinks?.get(`${nid1}__${nid2}`) ?? null
lnk = this._virtualLinks?.get(`${nid1}__${nid2}`)
}
return(lnk)
} }
buildGraphStructures(nodes, links, includeLinkIndexes = false) { buildGraphStructures(nodes, links, includeLinkIndexes = false) {
@@ -1128,11 +1129,11 @@ class BZgraflow extends Buildoz{
findLongLinks(links) { findLongLinks(links) {
let linksWithoutBackEdges let linksWithoutBackEdges
if(this.hasAnyLoop(this.flow.nodes, this.flow.links)){ if(this.hasAnyLoop(this.flow.nodes, links)){
const backEdges = this.findBackEdges(this.flow.nodes, this.flow.links) const backEdges = this.findBackEdges(this.flow.nodes, links)
linksWithoutBackEdges = this.flow.links.filter((link, idx) => (!backEdges.includes(idx)) && (link.from[0] != link.to[0])) linksWithoutBackEdges = links.filter((link, idx) => (!backEdges.includes(idx)) && (link.from[0] != link.to[0]))
} else { } else {
linksWithoutBackEdges = this.flow.links linksWithoutBackEdges = links
} }
/// Yes that means we ignore long & back links ! /// Yes that means we ignore long & back links !
const { parents } = this.buildGraphStructures(this.flow.nodes, linksWithoutBackEdges) const { parents } = this.buildGraphStructures(this.flow.nodes, linksWithoutBackEdges)
@@ -1157,14 +1158,14 @@ class BZgraflow extends Buildoz{
return(crossLayerLinks) return(crossLayerLinks)
} }
autofit(){ autofit(percent=100){
const parentBB = this.parentElement.getBoundingClientRect() const parentBB = this.parentElement.getBoundingClientRect()
// Use scroll dimensions for actual content extent (nodes can extend beyond element bounds) // Use scroll dimensions for actual content extent (nodes can extend beyond element bounds)
const contentW = Math.max(this.scrollWidth || this.offsetWidth || 1, 1) const contentW = Math.max(this.scrollWidth || this.offsetWidth || 1, 1)
const contentH = Math.max(this.scrollHeight || this.offsetHeight || 1, 1) const contentH = Math.max(this.scrollHeight || this.offsetHeight || 1, 1)
const sx = parentBB.width / contentW const sx = parentBB.width / contentW
const sy = parentBB.height / contentH const sy = parentBB.height / contentH
const scale = Math.min(sx, sy) // uniform scale to fit inside parent const scale = Math.min(sx, sy)*(percent/100) // uniform scale to fit inside parent
this.style.transformOrigin = 'top left' this.style.transformOrigin = 'top left'
this.style.transform = `scale(${scale})` this.style.transform = `scale(${scale})`
} }
@@ -1172,52 +1173,57 @@ class BZgraflow extends Buildoz{
Buildoz.define('graflow', BZgraflow) Buildoz.define('graflow', BZgraflow)
class MovingNodes{ class MovingNodes{
constructor(graflow){
constructor(graflow, itemSelector, handleSelector = itemSelector){
this.graflow = graflow this.graflow = graflow
this.itemSelector = itemSelector
this.handleSelector = handleSelector
this.nodesContainer = this.graflow.mainContainer.querySelector('.bzgf-nodes-container') this.nodesContainer = this.graflow.mainContainer.querySelector('.bzgf-nodes-container')
this.state = null
this.interactiveElementsSelector = ` this.interactiveElementsSelector = `
.port,
input, input,
textarea, textarea,
select, select,
button, button,
a[href] a[href]
` `
this._boundPointerDown = this.pointerDown.bind(this)
this._boundPointerMove = this.pointerMove.bind(this)
this._boundPointerUp = this.pointerUp.bind(this)
this.graflow.addEventListener('bz:graflow:refreshed', this.enableMovingNodes.bind(this))
} }
enableMovingNodes(itemSelector, handleSelector = itemSelector) { enableMovingNodes() {
this.itemSelector = itemSelector
this.handleSelector = handleSelector
if(!this._handleCursorStyle){ if(!this._handleCursorStyle){
const style = document.createElement('style') const style = document.createElement('style')
style.textContent = `${handleSelector}{ cursor: move }` const selector = `${this.handleSelector}:not(${this.interactiveElementsSelector.replace(/\s+/g, ' ').trim()})`
style.textContent = `${selector}{ cursor: move }`
this.nodesContainer.appendChild(style) this.nodesContainer.appendChild(style)
this._handleCursorStyle = style this._handleCursorStyle = style
} }
this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item => 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 => this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item =>
item.addEventListener('pointerup', this.pointerUp.bind(this)) item.addEventListener('pointerup', this._boundPointerUp)
) )
} }
disableMovingNodes(){ disableMovingNodes(){
this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item => 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 => this.nodesContainer.querySelectorAll(this.handleSelector).forEach(item =>
item.removeEventListener('pointerup', this.pointerUp.bind(this)) item.removeEventListener('pointerup', this._boundPointerUp)
) )
} }
pointerDown(e){ pointerDown(e){
this.graflow.clearFakeNodes() this.graflow.clearFakeNodes()
console.log('=====> interactive element', e.target)
const node = e.target.closest(this.itemSelector) const node = e.target.closest(this.itemSelector)
if(!node) return if(!node) return
@@ -1232,17 +1238,17 @@ class MovingNodes{
if(e.target != handle) return if(e.target != handle) return
} }
const rect = node.getBoundingClientRect() const rect = node.getBoundingClientRect()
const parentBB = this.nodesContainer.getBoundingClientRect()
const offsetX = rect.left - parentBB.left + this.nodesContainer.scrollLeft
const offsetY = rect.top - parentBB.top + this.nodesContainer.scrollTop
this.state = { this.state = {
node, node,
handle, handle,
startX: e.clientX, startX: e.clientX,
startY: e.clientY, startY: e.clientY,
offsetX: rect.left, offsetX,
offsetY: rect.top offsetY
} }
const x = e.clientX - this.state.startX + this.state.offsetX const x = e.clientX - this.state.startX + this.state.offsetX
const y = e.clientY - this.state.startY + this.state.offsetY const y = e.clientY - this.state.startY + this.state.offsetY
@@ -1251,7 +1257,7 @@ class MovingNodes{
node.style.left = `${x}px` node.style.left = `${x}px`
node.style.top = `${y}px` node.style.top = `${y}px`
node.style.margin = '0' node.style.margin = '0'
node.style.zIndex = '9999' node.style.zIndex = '3'
node.style.pointerEvents = 'none' node.style.pointerEvents = 'none'
} }
@@ -1267,8 +1273,19 @@ class MovingNodes{
pointerUp(e){ pointerUp(e){
if(!this.state) return if(!this.state) return
this.state.node.releasePointerCapture(e.pointerId) const { node, startX, startY, offsetX, offsetY } = this.state
this.state.node.style.pointerEvents = '' const x = e.clientX - startX + offsetX
const y = e.clientY - startY + offsetY
node.releasePointerCapture(e.pointerId)
node.style.pointerEvents = ''
for(const n of this.graflow.flow.nodes){
if(n.id == node.dataset.id){
n.coords.x = x
n.coords.y = y
break
}
}
this.graflow.fireEvent('nodeMoved', { nodeId: node.dataset.id, x, y })
this.state = null this.state = null
} }
} }
@@ -1278,15 +1295,179 @@ class EditWires{
this.graflow = graflow this.graflow = graflow
this.nodesContainer = this.graflow.mainContainer.querySelector('.bzgf-nodes-container') this.nodesContainer = this.graflow.mainContainer.querySelector('.bzgf-nodes-container')
this.state = null this.state = null
this.graflow.tabIndex = 0 // Make keyboard reactive
this._boundPointerMove = this.pointerMove.bind(this)
this.graflow.addEventListener('bz:graflow:refreshed', this.enableEditWires.bind(this))
this.graflow.addEventListener('bz:graflow:refreshed', this.enableSelectPorts.bind(this))
this.graflow.addEventListener('bz:graflow:wiresUpdated', this.enableEditWires.bind(this))
this.graflow.addEventListener('keyup', this.onKeyUp.bind(this))
} }
enableEditWires(){
enableEditWires(){
this.graflow.wiresContainer.querySelectorAll('.bzgf-wirecoat').forEach(item => item.remove())
for(const ref in this.graflow.stagedWires ){ for(const ref in this.graflow.stagedWires ){
this.graflow.stagedWires[ref].addEventListener('click', this.onSelectWire.bind(this)) const clone = this.graflow.stagedWires[ref].cloneNode(true)
clone.classList.add('bzgf-wirecoat')
this.graflow.wiresContainer.appendChild(clone)
clone.addEventListener('click', this.onSelectWire.bind(this))
if(clone.dataset.id == this.currentlySelectedWire?.dataset.id) this.onSelectWire({target: clone})
} }
} }
enableSelectPorts(){
this.currentlyHoveredPort = null
const portEls = this.graflow.nodesContainer.querySelectorAll('.port')
for(const port of portEls){
port.addEventListener('click', this.onSelectPort.bind(this))
port.addEventListener('pointerenter', this._onPortPointerEnter.bind(this))
port.addEventListener('pointerleave', this._onPortPointerLeave.bind(this))
port.classList.add('selectable')
}
}
_onPortPointerEnter(e){
this.currentlyHoveredPort = e.target.closest('.port')
}
_onPortPointerLeave(e){
if(this.currentlyHoveredPort === e.target.closest('.port')) this.currentlyHoveredPort = null
}
onSelectPort(e){
const port = e.target
if(this.currentlySelectedPort == port) {
this.currentlySelectedPort.style.removeProperty('border')
this.currentlySelectedPort = null
this.state = null
this._setWirecoatsPointerEvents('')
this.graflow.mainContainer.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._setWirecoatsPointerEvents('')
this.graflow.mainContainer.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.tempwire.setAttribute('fill', 'none')
this.tempwire.style.pointerEvents = 'none'
this.graflow.wiresContainer.appendChild(this.tempwire)
this.tempwire.classList.add('bzgf-wire')
this._setWirecoatsPointerEvents('none')
this.graflow.mainContainer.addEventListener('pointermove', this._boundPointerMove)
}
}
_setWirecoatsPointerEvents(value){
this.graflow.wiresContainer.querySelectorAll('.bzgf-wirecoat').forEach(el => { el.style.pointerEvents = value })
}
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 dir1 = port.dataset.direction
const oppositeDir = { n: 's', s: 'n', e: 'w', w: 'e' }
const hovered = this.currentlyHoveredPort
const dir2 = (hovered && hovered !== port) ? hovered.dataset.direction : oppositeDir[dir1]
const c1x = x1 + this.tension * this.graflow.dirVect[dir1].x
const c1y = y1 + this.tension * this.graflow.dirVect[dir1].y
const c2x = x2 + this.tension * this.graflow.dirVect[dir2].x
const c2y = y2 + this.tension * this.graflow.dirVect[dir2].y
const node1 = port.closest('.bzgf-node')
const node2 = hovered?.closest('.bzgf-node') ?? { offsetWidth: 0, offsetHeight: 0 }
const seg = this.graflow.buildSegment(
x1, y1,
c1x, c1y,
c2x, c2y,
x2, y2,
this.wireType,
node1, node2,
dir1, dir2,
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')
const idNode1 = node1.dataset.id
const idNode2 = node2.dataset.id
const idPort1 = port1.dataset.id
const idPort2 = port2.dataset.id
if(!node1 || !node2 || !port1 || !port2) {
console.warn('Link on bad node / port ', idNode1, idPort1, idNode2, idPort2)
return('')
}
this.graflow.addWire({ from: [idNode1, idPort1], to: [idNode2, idPort2] })
this.graflow.fireEvent('wireAdded', { from: [idNode1, idPort1], to: [idNode2, idPort2], id: `${idNode1}_${idNode2}` })
}
onSelectWire(e){ onSelectWire(e){
const wire = e.target const wire = e.target
console.log('wire', wire) if(this.currentlySelectedWire) this.currentlySelectedWire.style.removeProperty('stroke') //this.currentlySelectedWire.style.setProperty('stroke', '#0000', 'important')
if(wire==this.currentlySelectedWire) {
this.currentlySelectedWire = null
return
}
this.currentlySelectedWire = wire
wire.style.setProperty('stroke', '#FF0F', 'important')
}
onKeyUp(e){
if((e.key == 'Delete') && this.currentlySelectedWire) {
const wireId = this.currentlySelectedWire.dataset.id
const linkToRemove = this.graflow.stagedWires[wireId]?.link
this.graflow.flow.links = this.graflow.flow.links.filter(link =>
linkToRemove ? link !== linkToRemove : (link.from[0] + '_' + link.to[0] !== wireId)
)
this.graflow.stagedWires[wireId]?.remove()
delete this.graflow.stagedWires[wireId]
this.currentlySelectedWire.remove()
this.currentlySelectedWire = null
this.graflow.fireEvent('wireRemoved', { wireId })
return
}
if(e.key == 'Escape') {
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
this.graflow.mainContainer.removeEventListener('pointermove', this._boundPointerMove)
}
return
}
} }
} }

View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<script src="../bzGraflow-editor.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
bz-graflow{
border: 2px solid black;
}
bz-graflow.compunet{ grid-column: 1 / -1; width: 100vw; height: 60vh; background:black; }
</style>
<script>
window.addEventListener('load',()=>{
})
</script>
</head>
<body>
<bz-grafloweditor nodes="./nodesLib/nodesTest1.html" >
</bz-grafloweditor>
</body>
</html>

View File

@@ -0,0 +1,65 @@
{
"nodesFile": "./nodesLib/nodesTest1.html",
"flow": {
"nodes":[
{ "nodeType": "inc",
"id": "aze",
"coords": { "x": 220, "y": 120}
},
{ "nodeType": "inc",
"subflow": {
"url": "./flows/testFlowEic.json",
"portLinks": [
{ "refNodeType": "refnodein", "refnodePort": "out1",
"parentPort": "in1",
"subflowNode":"aze2", "subflowPort": "in1",
"direction": "in"
},
{ "refNodeType": "refnodeout", "refnodePort": "in1",
"parentPort": "out1",
"subflowNode":"aze5", "subflowPort": "out1",
"direction": "out"
}
]
},
"id": "aze2",
"coords": { "x": 220, "y": 10}
},
{ "nodeType": "factor",
"id": "qsd",
"coords": { "x": 470, "y": 170}
},
{ "nodeType": "factor",
"id": "qsd2",
"coords": { "x": 470, "y": 50}
},
{ "nodeType": "wadder",
"id": "wcx",
"coords": { "x": 720, "y": 50}
},
{ "nodeType": "multiplier",
"id": "ert",
"coords": { "x": 550, "y": 350}
},
{ "nodeType": "input",
"id": "0000",
"coords": { "x": 20, "y": 350}
},
{ "nodeType": "console",
"id": "9999",
"coords": { "x": 800, "y": 350}
}
],
"links": [
{ "from": ["0000", "out1"], "to": ["aze", "inp1"] },
{ "from": ["aze2", "out1"], "to": ["qsd2", "inp1"] },
{ "from": ["aze", "out1"], "to": ["qsd", "inp1"] },
{ "from": ["qsd2", "out1"], "to": ["ert", "inp2"] },
{ "from": ["0000", "out1"], "to": ["aze2", "inp1"] },
{ "from": ["qsd2", "out1"], "to": ["wcx", "inp2"] },
{ "from": ["wcx", "out1"], "to": ["ert", "inp1"] },
{ "from": ["qsd", "out1"], "to": ["wcx", "inp1"] },
{ "from": ["ert", "out1"], "to": ["9999", "inp1"] }
]
}
}

View File

@@ -0,0 +1,54 @@
{
"nodesFile": "./nodesLib/nodesTest1.html",
"flow": {
"nodes":[
{ "nodeType": "inc",
"id": "aze",
"coords": { "x": 220, "y": 120}
},
{ "nodeType": "inc",
"id": "aze2",
"coords": { "x": 220, "y": 10}
},
{ "nodeType": "factor",
"id": "qsd",
"coords": { "x": 470, "y": 170}
},
{ "nodeType": "factor",
"id": "qsd2",
"coords": { "x": 470, "y": 50}
},
{ "nodeType": "wadder",
"id": "wcx",
"coords": { "x": 720, "y": 50}
},
{ "nodeType": "multiplier",
"id": "ert",
"coords": { "x": 550, "y": 350}
},
{ "nodeType": "input",
"id": "0000",
"coords": { "x": 20, "y": 350}
},
{ "nodeType": "console",
"id": "9999",
"coords": { "x": 800, "y": 350}
},
{ "nodeType": "square",
"id": "prng",
"coords": { "x": 250, "y": 400}
}
],
"links": [
{ "from": ["0000", "out1"], "to": ["aze", "inp1"] },
{ "from": ["aze2", "out1"], "to": ["qsd2", "inp1"] },
{ "from": ["aze", "out1"], "to": ["qsd", "inp1"] },
{ "from": ["qsd2", "out1"], "to": ["ert", "inp2"] },
{ "from": ["0000", "out1"], "to": ["aze2", "inp1"] },
{ "from": ["qsd2", "out1"], "to": ["wcx", "inp2"] },
{ "from": ["wcx", "out1"], "to": ["ert", "inp1"] },
{ "from": ["qsd", "out1"], "to": ["wcx", "inp1"] },
{ "from": ["ert", "out1"], "to": ["9999", "inp1"] }
]
}
}

View File

@@ -0,0 +1,271 @@
{
"nodesFile": "./nodesLib/nodes16ports.html",
"flow": {
"nodes": [
{
"nodeType": "square",
"id": "p1center",
"coords": {
"x": 300,
"y": 200
},
"markup": {
"title": "Center",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p1west",
"coords": {
"x": 200,
"y": 200
},
"markup": {
"title": "West",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p1north",
"coords": {
"x": 300,
"y": 100
},
"markup": {
"title": "North",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p1east",
"coords": {
"x": 400,
"y": 200
},
"markup": {
"title": "East",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p1south",
"coords": {
"x": 300,
"y": 300
},
"markup": {
"title": "South",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p2center",
"coords": {
"x": 800,
"y": 200
},
"markup": {
"title": "Center",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p2west",
"coords": {
"x": 700,
"y": 200
},
"markup": {
"title": "West",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p2north",
"coords": {
"x": 800,
"y": 100
},
"markup": {
"title": "North",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p2east",
"coords": {
"x": 900,
"y": 200
},
"markup": {
"title": "East",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p2south",
"coords": {
"x": 800,
"y": 300
},
"markup": {
"title": "South",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p3center",
"coords": {
"x": 300,
"y": 600
},
"markup": {
"title": "Center",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p3west",
"coords": {
"x": 200,
"y": 600
},
"markup": {
"title": "West",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p3north",
"coords": {
"x": 300,
"y": 500
},
"markup": {
"title": "North",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p3east",
"coords": {
"x": 400,
"y": 600
},
"markup": {
"title": "East",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p3south",
"coords": {
"x": 300,
"y": 700
},
"markup": {
"title": "South",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p4center",
"coords": {
"x": 800,
"y": 600
},
"markup": {
"title": "Center",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p4west",
"coords": {
"x": 700,
"y": 600
},
"markup": {
"title": "West",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p4north",
"coords": {
"x": 800,
"y": 500
},
"markup": {
"title": "North",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p4east",
"coords": {
"x": 900,
"y": 600
},
"markup": {
"title": "East",
"subtitle": "."
}
},
{
"nodeType": "square",
"id": "p4south",
"coords": {
"x": 800,
"y": 700
},
"markup": {
"title": "South",
"subtitle": "."
}
}
],
"links": [
{ "from": ["p1center", "s"], "to": ["p1south", "n"] },
{ "from": ["p1center", "e"], "to": ["p1east", "w"] },
{ "from": ["p1center", "n"], "to": ["p1north", "s"] },
{ "from": ["p1center", "w"], "to": ["p1west", "e"] },
{ "from": ["p2center", "s"], "to": ["p2south", "e"] },
{ "from": ["p2center", "e"], "to": ["p2east", "n"] },
{ "from": ["p2center", "n"], "to": ["p2north", "w"] },
{ "from": ["p2center", "w"], "to": ["p2west", "s"] },
{ "from": ["p3center", "s"], "to": ["p3south", "s"] },
{ "from": ["p3center", "e"], "to": ["p3east", "e"] },
{ "from": ["p3center", "n"], "to": ["p3north", "n"] },
{ "from": ["p3center", "w"], "to": ["p3west", "w"] },
{ "from": ["p4center", "s"], "to": ["p4south", "w"] },
{ "from": ["p4center", "e"], "to": ["p4east", "s"] },
{ "from": ["p4center", "n"], "to": ["p4north", "e"] },
{ "from": ["p4center", "w"], "to": ["p4west", "n"] }
]
}
}

View File

@@ -0,0 +1,47 @@
{
"nodesFile": "./nodesLib/nodesTest2.html",
"flow": {
"nodes":[
{ "nodeType": "process",
"id": "aze2",
"xcoords": { "x": 220, "y": 120},
"markup": { "text": "x = alph - 1" }
},
{ "nodeType": "condition",
"id": "qsd",
"xcoords": { "x": 250, "y": 270},
"markup": { "text": "x > 0" }
},
{ "nodeType": "preparation",
"id": "qsd2",
"xcoords": { "x": 250, "y": 470},
"markup": { "text": "prepare SQL" }
},
{ "nodeType": "database",
"id": "wcx",
"xcoords": { "x": 500, "y": 450},
"markup": { "text": "MySQL<br>Store" }
},
{ "nodeType": "end",
"id": "ert",
"xcoords": { "x": 250, "y": 650},
"markup": { "text": "End" }
},
{ "nodeType": "start",
"id": "aze",
"xcoords": { "x": 220, "y": 20},
"markup": { "text": "StartMike" }
}
],
"links": [
{ "from": ["aze", "out1"], "to": ["aze2", "inout1"], "endArrow":true },
{ "from": ["aze2", "inout2"], "to": ["qsd", "inp1"], "endArrow":true },
{ "from": ["qsd", "out1"], "to": ["aze2", "inout3"], "endArrow":true },
{ "from": ["qsd", "out2"], "to": ["qsd2", "inp1"], "endArrow":true },
{ "from": ["qsd2", "inout2"], "to": ["wcx", "inout1"], "startArrow":true , "endArrow":true },
{ "from": ["qsd2", "out1"], "to": ["ert", "inp1"], "endArrow":true },
{ "from": ["qsd2", "inout1"], "to": ["qsd2", "inout1"], "endArrow":true },
{ "from": ["aze2", "inout4"], "to": ["wcx", "inout1"], "endArrow":true }
]
}
}

View File

@@ -0,0 +1,74 @@
{
"nodesFile": "./nodesLib/nodesEIC.html",
"flow": {
"nodes":[
{ "nodeType": "eicBasic",
"id": "aze",
"ncoords": { "x": 50, "y": 120},
"markup": {
"title": "Build attendees list",
"subtitle": "Build an attendees list to email"
},
"data": { "a": "a1", "b":"b1"}
},
{ "nodeType": "eicBasic",
"id": "aze2",
"ncoords": { "x": 100, "y": 220},
"markup": {
"title": "Select message",
"subtitle": "Select an email template"
},
"data": { "a": "a2", "b":"b2"}
},
{ "nodeType": "eicBasic",
"id": "aze3",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "Data mapping",
"subtitle": "Associate content variables with attendees data"
},
"data": { "a": "a3", "b":"b3"},
"subflow": {
"url": "./flows/testFlowICMP.json",
"portLinks": [
{ "refNodeType": "refnodein", "refnodePort": "out1",
"parentPort": "in1",
"subflowNode":"cid", "subflowPort": "in3",
"direction": "in"
},
{ "refNodeType": "refnodeout", "refnodePort": "in1",
"parentPort": "out1",
"subflowNode":"signature", "subflowPort": "out2",
"direction": "out"
}
]
}
},
{ "nodeType": "eicBasic",
"id": "aze4",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "Schedule mailing",
"subtitle": "Choose time to send the mail"
},
"data": { "a": "a3", "b":"b3"}
},
{ "nodeType": "eicBasic",
"id": "aze5",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "Stats",
"subtitle": "Access mailing statistics"
},
"data": { "a": "a3", "b":"b3"}
}
],
"links": [
{ "from": ["aze2", "out1"], "to": ["aze", "in1"] },
{ "from": ["aze2", "out2"], "to": ["aze3", "in1"] },
{ "from": ["aze", "out1"], "to": ["aze4", "in1"] },
{ "from": ["aze3", "out1"], "to": ["aze4", "in2"] },
{ "from": ["aze4", "out1"], "to": ["aze5", "in1"] }
]
}
}

View File

@@ -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"] }
]
}
}

View File

@@ -0,0 +1,150 @@
{
"nodesFile": "./nodesLib/nodesEIC.html",
"flow": {
"nodes":[
{ "nodeType": "eicBasic",
"id": "eval",
"markup": {
"title": "Evaluations",
"subtitle": "...",
"severity": "info"
},
"data": { "node": "eval", "nodeId":null}
},
{ "nodeType": "eicBasic",
"id": "gap",
"ncoords": { "x": 100, "y": 220},
"markup": {
"title": "GAP",
"subtitle": "...",
"severity": "accent"
},
"data": { "a": "a2", "b":"b2"}
},
{ "nodeType": "eicBasic",
"id": "cid",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "CID",
"subtitle": "...",
"severity": "primary"
},
"data": { "a": "a3", "b":"b3"}
},
{
"nodeType": "eicBasic",
"id": "allocation",
"markup": {
"title": "Case Allocation",
"subtitle": "...",
"severity": "success"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "signature",
"markup": {
"title": "Grant Signature",
"subtitle": "...",
"severity": "danger"
},
"data": {
"track": "grant"
}
},
{
"nodeType": "eicBasic",
"id": "progress-meeting",
"markup": {
"title": "Progress Meetings",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "grant",
"instanciable": true
}
},
{
"nodeType": "eicBasic",
"id": "techdd",
"markup": {
"title": "Tech Due Diligences",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "kyc",
"markup": {
"title": "KYC",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "aifm-advisory",
"markup": {
"title": "AIFM Advisory Commitee",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "aifm-investment",
"markup": {
"title": "AIFM Investment Commitee",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity",
"parent": "aifm-advisory"
}
},
{
"nodeType": "eicBasic",
"id": "agreement",
"markup": {
"title": "Investment Agreement",
"subtitle": "...",
"severity": "warning"
},
"data": {
"track": "equity",
"parent": "aifm-investment"
}
}
],
"links": [
{ "from": ["eval", "out2"], "to": ["gap", "in1"] },
{ "from": ["eval", "out1"], "to": ["cid", "in1"] },
{ "from": ["eval", "out3"], "to": ["allocation", "in1"] },
{ "from": ["gap", "out1"], "to": ["signature", "in1"] },
{ "from": ["signature", "out1"], "to": ["progress-meeting", "in1"] },
{ "from": ["cid", "out1"], "to": ["techdd", "in1"] },
{ "from": ["allocation", "out1"], "to": ["techdd", "in3"] },
{ "from": ["allocation", "out2"], "to": ["kyc", "in2"] },
{ "from": ["techdd", "out1"], "to": ["aifm-advisory", "in1"] },
{ "from": ["kyc", "out1"], "to": ["aifm-advisory", "in3"] },
{ "from": ["aifm-advisory", "out1"], "to": ["aifm-investment", "in1"] },
{ "from": ["aifm-investment", "out1"], "to": ["agreement", "in1"] },
{ "from": ["gap", "out3"], "to": ["aifm-investment", "in1"] }
]
}
}

View File

@@ -0,0 +1,150 @@
{
"nodesFile": "./nodesLib/nodesEIC2.html",
"flow": {
"nodes":[
{ "nodeType": "eicBasic",
"id": "eval",
"markup": {
"title": "Evaluations",
"subtitle": "...",
"severity": "secondary"
},
"data": { "node": "eval", "nodeId":null}
},
{ "nodeType": "eicBasic",
"id": "gap",
"ncoords": { "x": 100, "y": 220},
"markup": {
"title": "GAP",
"subtitle": "...",
"severity": "secondary"
},
"data": { "a": "a2", "b":"b2"}
},
{ "nodeType": "eicBasic",
"id": "cid",
"ncoords": { "x": 150, "y": 320},
"markup": {
"title": "CID",
"subtitle": "...",
"severity": "secondary"
},
"data": { "a": "a3", "b":"b3"}
},
{
"nodeType": "eicBasic",
"id": "allocation",
"markup": {
"title": "Case Allocation",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "signature",
"markup": {
"title": "Grant Signature",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "grant"
}
},
{
"nodeType": "eicBasic",
"id": "progress-meeting",
"markup": {
"title": "Progress Meetings",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "grant",
"instanciable": true
}
},
{
"nodeType": "eicBasic",
"id": "techdd",
"markup": {
"title": "Tech Due Diligences",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "kyc",
"markup": {
"title": "KYC",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "aifm-advisory",
"markup": {
"title": "AIFM Advisory Commitee",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity"
}
},
{
"nodeType": "eicBasic",
"id": "aifm-investment",
"markup": {
"title": "AIFM Investment Commitee",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity",
"parent": "aifm-advisory"
}
},
{
"nodeType": "eicBasic",
"id": "agreement",
"markup": {
"title": "Investment Agreement",
"subtitle": "...",
"severity": "secondary"
},
"data": {
"track": "equity",
"parent": "aifm-investment"
}
}
],
"links": [
{ "from": ["eval", "out1"], "to": ["gap", "in1"] , "endArrow":true},
{ "from": ["eval", "out1"], "to": ["cid", "in1"] , "endArrow":true},
{ "from": ["eval", "out1"], "to": ["allocation", "in1"] , "endArrow":true},
{ "from": ["gap", "out1"], "to": ["signature", "in1"] , "endArrow":true},
{ "from": ["signature", "out1"], "to": ["progress-meeting", "in1"] , "endArrow":true},
{ "from": ["cid", "out1"], "to": ["techdd", "in1"] , "endArrow":true, "startArrow":true},
{ "from": ["allocation", "out1"], "to": ["techdd", "in1"] , "endArrow":true, "startArrow":true},
{ "from": ["allocation", "out1"], "to": ["kyc", "in1"] , "endArrow":true, "startArrow":true},
{ "from": ["techdd", "out1"], "to": ["aifm-advisory", "in1"] },
{ "from": ["kyc", "out1"], "to": ["aifm-advisory", "in1"] , "endArrow":true},
{ "from": ["aifm-advisory", "out1"], "to": ["aifm-investment", "in1"] , "endArrow":true},
{ "from": ["aifm-investment", "out1"], "to": ["agreement", "in1"] , "endArrow":true},
{ "from": ["gap", "out1"], "to": ["aifm-investment", "in1"] , "endArrow":true}
]
}
}

View File

@@ -0,0 +1,59 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
width: 50px;
height: 50px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
}
.bzgf-node .body{
z-index: 1;
position: absolute;
inset: 0;
background: var(--eicui-base-color-grey-25);
border:2px solid var(--eicui-base-color-grey-50);
border-radius: 6px;
}
.bzgf-node .title {
font-weight: bold;
color: var(--app-color-black);
margin: .5em auto .2em auto;
}
.bzgf-node .subtitle {
font-size: .9em;
color: var(--eicui-base-color-primary-100);
width: 90%;
margin: auto;
}
.bzgf-node .port{
position: absolute;
height: 10px;
width: 10px;
background: var(--eicui-base-color-info-25);
border-radius: 10px;
}
.bzgf-node [data-direction="n"]{ top: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="w"]{ left: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-wire{ stroke: var(--eicui-base-color-info); stroke-width: 4px; stroke-dasharray: 10,5; }
</style>
<template>
<div class="bzgf-node" data-nodetype="square">
<div class="body">
<div class="title">{title}</div>
<div class="subtitle">{subtitle}</div>
</div>
<div class="port" data-id="w" data-direction="w"></div>
<div class="port" data-id="n" data-direction="n"></div>
<div class="port" data-id="e" data-direction="e"></div>
<div class="port" data-id="s" data-direction="s"></div>
</div>
</template>

View File

@@ -0,0 +1,105 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
}
div.bzgf-node div.body[primary] { background-color: var(--eicui-base-color-primary); color:white;}
div.bzgf-node div.body[info] { background-color: var(--eicui-base-color-info); color:white;}
div.bzgf-node div.body[success] { background-color: var(--eicui-base-color-success); color:white;}
div.bzgf-node div.body[warning] { background-color: var(--eicui-base-color-warning);}
div.bzgf-node div.body[danger] { background-color: var(--eicui-base-color-danger);}
div.bzgf-node div.body[accent] { background-color: var(--eicui-base-color-accent);}
.bzgf-node .body{
z-index: 1;
position: absolute;
inset: 0;
background: var(--eicui-base-color-grey-25);
border:2px solid var(--eicui-base-color-grey-50);
border-radius: 6px;
}
.bzgf-node .title {
font-weight: bold;
color: var(--app-color-black);
margin: .5em auto .2em auto;
}
.bzgf-node .subtitle {
font-size: .9em;
color: var(--eicui-base-color-primary-100);
width: 90%;
margin: auto;
}
.bzgf-node .port{
position: absolute;
height: 10px;
width: 10px;
background: var(--eicui-base-color-info-25);
border-radius: 10px;
}
.bzgf-node [data-direction="n"]{ top: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="w"]{ left: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-id="in2"]{ top: 25%; }
.bzgf-node [data-id="in3"]{ top: 75%; }
.bzgf-node [data-id="out2"]{ top: 25%; }
.bzgf-node [data-id="out3"]{ top: 75%; }
.bzgf-node[data-nodetype="refnodein"], .bzgf-node[data-nodetype="refnodeout"] {
width:3em;
height:3em;
padding: 2px;
}
.bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{
border-radius: 50%;
width: 3em;
height: 3em;
display: flex;
align-items: center;
justify-content: center;
}
.bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{ background: var(--eicui-base-color-grey-25); }
.bzgf-wire{ stroke: var(--eicui-base-color-info); stroke-width: 4px; stroke-dasharray: 10,5; }
</style>
<template>
<div class="bzgf-node" data-nodetype="eicBasic">
<div class="body" {severity}>
<div class="title">{title}</div>
<div class="subtitle">{subtitle}</div>
</div>
<div class="port" data-type="in" data-id="in1" data-direction="w"></div>
<div class="port" data-type="in" data-id="in2" data-direction="w"></div>
<div class="port" data-type="in" data-id="in3" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="port" data-type="out" data-id="out2" data-direction="e"></div>
<div class="port" data-type="out" data-id="out3" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="refnodein">
<div class="body">{parentport}</div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="refnodeout">
<div class="body">{parentport}</div>
<div class="port" data-type="in" data-id="in1" data-direction="w"></div>
</div>
</template>

View File

@@ -0,0 +1,113 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
}
div.bzgf-node[primary] { background-color: var(--eicui-base-color-primary);}
div.bzgf-node[info] { background-color: var(--eicui-base-color-info);}
div.bzgf-node[success] { background-color: var(--eicui-base-color-success);}
div.bzgf-node[warning] { background-color: var(--eicui-base-color-warning);}
div.bzgf-node[danger] { background-color: var(--eicui-base-color-danger);}
div.bzgf-node[accent] { background-color: var(--eicui-base-color-accent);}
.bzgf-node .body{
z-index: 1;
position: absolute;
inset: 0;
background: var(--eicui-base-color-grey-25);
border:2px solid var(--eicui-base-color-grey-50);
border-radius: 6px;
}
.bzgf-node .title {
font-weight: bold;
color: var(--app-color-black);
margin: .5em auto .2em auto;
}
.bzgf-node .subtitle {
font-size: .9em;
color: var(--eicui-base-color-primary-100);
width: 90%;
margin: auto;
}
.bzgf-node .port{
position: absolute;
height: 10px;
width: 10px;
background: var(--eicui-base-color-info-25);
opacity: 0;
border-radius: 10px;
}
.bzgf-node [data-direction="n"]{ top: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -4px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="w"]{ left: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -4px; top: 50%; transform: translateY(-50%);}
.bzgf-node[data-nodetype="refnodein"], .bzgf-node[data-nodetype="refnodeout"] {
width:3em;
height:3em;
padding: 2px;
}
.bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{
border-radius: 50%;
width: 3em;
height: 3em;
display: flex;
align-items: center;
justify-content: center;
}
.bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{ background: var(--eicui-base-color-grey-25); }
.bzgf-wire{ stroke: var(--eicui-base-color-info); stroke-width: 4px; stroke-dasharray: 10,5; }
path.arrow-head{ fill: var(--eicui-base-color-info); }
</style>
<svg style="display:none" aria-hidden="true">
<template id="svg-arrows">
<defs>
<marker id="arrow"
viewBox="0 0 16 16"
refX="16"
refY="8"
markerWidth="16"
markerHeight="16"
orient="auto-start-reverse"
markerUnits="userSpaceOnUse">
<path d="M0,0 L16,8 L0,16 Z" class="arrow-head"/>
</marker>
</defs>
</template>
</svg>
<template>
<div class="bzgf-node" data-nodetype="eicBasic">
<div class="body">
<div class="title">{title}</div>
<div class="subtitle">{subtitle}</div>
</div>
<div class="port" data-type="in" data-id="in1" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="refnodein">
<div class="body">{parentport}</div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="refnodeout">
<div class="body">{parentport}</div>
<div class="port" data-type="in" data-id="in1" data-direction="w"></div>
</div>
</template>

View File

@@ -0,0 +1,229 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
border-width:2px;
border-style: solid;
border-radius: 6px;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
}
.bzgf-node .title {
font-weight: bold;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 2em;
color: white;
}
.bzgf-node .body { margin-top: 2em; }
.bzgf-node .body input {
width:4em;
font-size: .9em;
border-radius: 6px;
border: 1px solid #CCC;
}
.bzgf-node .body div{ font-size: 12px; text-align: left; line-height: 24px; }
.bzgf-node .port{
position: absolute;
height: 10px;
width: 10px;
border: 1px solid black;
border-radius: 10px;
}
.bzgf-node .port[data-type="in"] { background: #0F0; }
.bzgf-node .port[data-type="out"] { background: #FF0; }
.bzgf-node [data-direction="w"]{ left: -7px; top: calc(50% + 1em); transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -7px; top: calc(50% + 1em); transform: translateY(-50%);}
.bzgf-node [data-direction="n"]{ top: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node[data-nodetype="inc"]{
background: #DFD;
border-color: #090;
}
.bzgf-node[data-nodetype="inc"] .title{ background: #090; }
.bzgf-node[data-nodetype="wadder"]{
background: #DFD;
border-color: #090;
height:150px
}
.bzgf-node[data-nodetype="wadder"] .body{ display: grid; grid-gap: 4px; margin-left:0.5em; grid-template-columns: 1fr 1fr; align-items: center; }
.bzgf-node[data-nodetype="wadder"] .title{ background: #090; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp1"] { top:51px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp2"] { top:75px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp3"] { top:99px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp4"] { top:123px; }
.bzgf-node[data-nodetype="wadder"] .port[data-id="inp5"] { top:147px; }
.bzgf-node[data-nodetype="factor"]{
background: #DDF;
border-color: #009;
}
.bzgf-node[data-nodetype="factor"] .title{ background: #009; }
.bzgf-node[data-nodetype="multiplier"]{
background: #DDF;
border-color: #009;
height:110px
}
.bzgf-node[data-nodetype="multiplier"] .body{
font-size:40px;
font-weight: bold;
align-items: center;
display: flex;
justify-content: center;
margin-top: 1em;
}
.bzgf-node[data-nodetype="multiplier"] .title{ background: #009; }
.bzgf-node[data-nodetype="multiplier"] .port[data-id="inp1"] { top:37px; }
.bzgf-node[data-nodetype="multiplier"] .port[data-id="inp2"] { top:63px; }
.bzgf-node[data-nodetype="multiplier"] .port[data-id="inp3"] { top:89px; }
.bzgf-node[data-nodetype="input"],
.bzgf-node[data-nodetype="console"]{
background: #CCC;
border-color: #555;
}
.bzgf-node[data-nodetype="input"] .title,
.bzgf-node[data-nodetype="console"] .title{ background: #555; }
.bzgf-node[data-nodetype="square"]{
background: #FAA;
border-color: #A00;
width: 100px;
height: 100px;
}
.bzgf-node[data-nodetype="square"] .title{ background: #555; }
.bzgf-node[data-nodetype="refnodein"], .bzgf-node[data-nodetype="refnodeout"] {
width:3em;
height:3em;
padding: 2px;
border: none;
}
.bzgf-node[data-nodetype="refnodein"] .body, .bzgf-node[data-nodetype="refnodeout"] .body{
border-radius: 50%;
width: 3em;
height: 3em;
display: flex;
align-items: center;
justify-content: center;
margin:0;
}
.bzgf-node[data-nodetype="refnodein"] .port, .bzgf-node[data-nodetype="refnodeout"] .port{
top: 50%;
}
.bzgf-node[data-nodetype="refnodein"] .body{ background: #0F0; }
.bzgf-node[data-nodetype="refnodeout"] .body{ background: #FF0; }
.bzgf-wire{ stroke: #0AF; stroke-width: 2; }
</style>
<template>
<div class="bzgf-node" data-nodetype="inc">
<div class="title">Fixed Increment</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<label>Increment:</label><input name="incvalue" type="text" value="1">
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="factor">
<div class="title">Fixed factor</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<label>Factor:</label><input name="factvalue" type="text" value="0.5">
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="wadder">
<div class="title">Adder</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp2" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp3" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp4" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp5" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<div>
<div>x <input type="text" name="weight1" value="1"></div>
<div>x <input type="text" name="weight2" value="1"></div>
<div>x <input type="text" name="weight3" value="1"></div>
<div>x <input type="text" name="weight4" value="1"></div>
<div>x <input type="text" name="weight5" value="1"></div>
</div>
<div style="font-size:40px;font-weight: bold;transform: translateY(-50%);">&sum;</div>
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="multiplier">
<div class="title">Multiply</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp2" data-direction="w"></div>
<div class="port" data-type="in" data-id="inp3" data-direction="w"></div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">x</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="console">
<div class="title">Console</div>
<div class="port" data-type="in" data-id="inp1" data-direction="w"></div>
<div class="body"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="input">
<div class="title">input</div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
<div class="body">
<label>Value:</label><input name="value" type="text" value="1">
</div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="square">
<div class="title">PRNG</div>
<div class="body"></div>
<div class="port" data-type="out" data-id="w" data-direction="w"></div>
<div class="port" data-type="out" data-id="n" data-direction="n"></div>
<div class="port" data-type="out" data-id="e" data-direction="e"></div>
<div class="port" data-type="out" data-id="s" data-direction="s"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="refnodein" data-editor="exclude">
<div class="body">{parentport}</div>
<div class="port" data-type="out" data-id="out1" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="refnodeout" data-editor="exclude">
<div class="body">{parentport}</div>
<div class="port" data-type="in" data-id="in1" data-direction="w"></div>
</div>
</template>

View File

@@ -0,0 +1,237 @@
<style>
.bzgf-node {
font-family: Arial, Helvetica, sans-serif;
border-width:2px;
border-style: solid;
border-radius: 6px;
width: 160px;
height: 80px;
color: black;
text-align: center;
position: absolute;
padding: .5em;
background: black;
}
.bzgf-node .text {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
width: 100%;
height: 2em;
color: white;
transform: translateX(-50%), translateY(-50%);
}
.bzgf-node .port{
position: absolute;
height: 6px;
width: 6px;
background: #FFF;
z-index: 99;
opacity: 0.3;
}
.bzgf-node [data-direction="w"]{ left: -7px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="e"]{ right: -7px; top: 50%; transform: translateY(-50%);}
.bzgf-node [data-direction="n"]{ top: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node [data-direction="s"]{ bottom: -7px; left: 50%; transform: translateX(-50%);}
.bzgf-node[data-nodetype="start"],
.bzgf-node[data-nodetype="end"]{
border: 1px solid white;
width: 100px;
height: 30px;
border-radius: 50%;
}
.bzgf-node[data-nodetype="start"] .text,
.bzgf-node[data-nodetype="end"] .text{ width: 80%; }
.bzgf-node[data-nodetype="condition"]{
border: none;
width: 100px;
height: 100px;
}
.bzgf-node[data-nodetype="condition"] .frame{
border: 1px solid white;
transform: rotate(-45deg) scale(0.7071);
position: absolute;
inset: 0;
}
.bzgf-node[data-nodetype="condition"] .port[data-direction="w"]{ left: -5px; }
.bzgf-node[data-nodetype="condition"] [data-direction="e"]{ right: -5px; }
.bzgf-node[data-nodetype="condition"] [data-direction="n"]{ top: -5px; }
.bzgf-node[data-nodetype="condition"] [data-direction="s"]{ bottom: -5px; }
.bzgf-node[data-nodetype="process"]{
border: 1px solid white;
width: 150px;
height: 70px;
padding: 0;
}
.bzgf-node[data-nodetype="process"] .text{ width: 80%; }
.bzgf-node[data-nodetype="process"] .dbline{
border: 1px solid white;
width: 75%;
height: 100%;
position: absolute;
top: -1px;
left: 10%;
}
.bzgf-node[data-nodetype="database"]{
border: 1px solid white;
width: 100px;
height: 100px;
isolation: isolate;
}
.bzgf-node[data-nodetype="database"] .top{
z-index: 2;
height: 20%;
border: 1px solid white;
border-radius: 50%;
position: absolute;
top: -10%;
left: 0;
width: 100%;
background: black;
}
.bzgf-node[data-nodetype="database"] .text{
background: black;
width: 87%;
z-index: 1;
}
.bzgf-node[data-nodetype="database"] .bottom{
z-index: 0;
height: 20%;
border: 1px solid white;
border-radius: 50%;
position: absolute;
bottom: -10%;
left: 0;
width: 99%;
background: black;
clip-path: polygon( 0% 110%, 100% 110%, 100% 50%, 0% 50%);
}
.bzgf-node[data-nodetype="database"] [data-direction="n"]{ top: -17px; }
.bzgf-node[data-nodetype="database"] [data-direction="s"]{ bottom: -17px; }
.bzgf-node[data-nodetype="preparation"]{
width: 150px;
height: 80px;
padding: 0;
border: none;
}
.bzgf-node[data-nodetype="preparation"] .text{ width: 85%; }
.bzgf-node[data-nodetype="preparation"] .outerframe{
width: 100%;
height: 100%;
position: absolute;
background: white;
border: none;
padding: 0;
place-items: center;
clip-path: polygon(
10% 0%,
90% 0%,
100% 50%,
90% 100%,
10% 100%,
0% 50%
);
}
.bzgf-node[data-nodetype="preparation"] .innerframe{
width: calc(100% - 2px);
height: calc(100% - 2px);
position: absolute;
top: 1px;
left: 1px;
background: black;
clip-path: inherit;
display: grid;
place-items: center;
color: white;
}
.bzgf-wire{ stroke: #FF0; stroke-width: 2; }
</style>
<svg style="display:none" aria-hidden="true">
<template id="svg-arrows">
<defs>
<marker id="arrow"
viewBox="0 0 10 10"
refX="10"
refY="5"
markerWidth="10"
markerHeight="10"
orient="auto-start-reverse"
markerUnits="userSpaceOnUse">
<path d="M0,0 L10,5 L0,10 Z" fill="#FF0"/>
</marker>
</defs>
</template>
</svg>
<template>
<div class="bzgf-node" data-nodetype="start">
<div class="text">{text}</div>
<div class="port" data-id="out1" data-direction="s"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="end">
<div class="text">{text}</div>
<div class="port" data-id="inp1" data-direction="n"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="condition">
<div class="frame"></div>
<div class="text">{text}</div>
<div class="port" data-id="inp1" data-direction="n"></div>
<div class="port" data-id="out1" data-direction="w"></div>
<div class="port" data-id="out2" data-direction="s"></div>
<div class="port" data-id="out3" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="process">
<div class="dbline"></div>
<div class="text">{text}</div>
<div class="port" data-id="inout1" data-direction="n"></div>
<div class="port" data-id="inout2" data-direction="s"></div>
<div class="port" data-id="inout3" data-direction="w"></div>
<div class="port" data-id="inout4" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="database">
<div class="top"></div>
<div class="bottom"></div>
<div class="text">{text}</div>
<div class="port" data-id="inout1" data-direction="n"></div>
<div class="port" data-id="inout2" data-direction="s"></div>
<div class="port" data-id="inout3" data-direction="w"></div>
<div class="port" data-id="inout4" data-direction="e"></div>
</div>
</template>
<template>
<div class="bzgf-node" data-nodetype="preparation">
<div class="outerframe">
<div class="innerframe">
<div class="text">{text}</div>
</div>
</div>
<div class="port" data-id="inp1" data-direction="n"></div>
<div class="port" data-id="out1" data-direction="s"></div>
<div class="port" data-id="inout1" data-direction="w"></div>
<div class="port" data-id="inout2" data-direction="e"></div>
</div>
</template>

147
graflow_examples/test.html Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
table {
margin: 0 auto;
border-collapse: collapse;
}
th, td {
border: 1px solid black;
max-width: 10em;
min-width: 7em;
text-align: center;
}
th{
background: #555;
color: white;
}
tr > td:first-child {
text-align: left;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th></th>
<th>Style</th>
<th>isolated</th>
<th>subflow</th>
<th>autofit</th>
<th>wireStyle</th>
<th>align</th>
<th>oriented</th>
<th>nodesmove</th>
<th>editwires</th>
</tr>
</thead>
<tbody>
<tr>
<td><a target="test1" href="./test1.html">test1</a></td>
<td>Graflow P42</td>
<td>YES</td>
<td>2 depths</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a target="test2" href="./test2.html">test2</a></td>
<td>Graflow Organigram</td>
<td>YES</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a target="test3" href="./test3.html">test3</a></td>
<td>Graflow EIC simple</td>
<td>NO</td>
<td>1 depth</td>
<td></td>
<td>Straight</td>
<td>First</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a target="test4" href="./test4.html">test4</a></td>
<td>Graflow EIC-ICMP</td>
<td>NO</td>
<td></td>
<td>X</td>
<td>Bezier</td>
<td>Center</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a target="test4.5" href="./test4.5.html">test4.5</a></td>
<td>Graflow EIC-ICMP II</td>
<td>NO</td>
<td></td>
<td></td>
<td>Ortho</td>
<td>Parent</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a target="test5" href="./test5.html">test5</a></td>
<td>Graflow P42</td>
<td>YES</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><a target="test6" href="./test6.html">test6</a></td>
<td>Graflow 16 ports test</td>
<td>NO</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>X</td>
<td></td>
</tr>
</tbody>
</table>
<br>
<table>
<thead>
<tr>
<th></th>
<th>Style</th>
</tr>
</thead>
<tbody>
<tr>
<td><a target="etest1" href="./etest1.html">Editor test</a></td>
<td>P42</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:99999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.compunet{ grid-column: 1 / -1; width: 100vw; height: 60vh; background:black; }
</style>
<script>
window.addEventListener('load',()=>{
let grflw1 = document.querySelector('bz-graflow.compunet')
grflw1.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw1 = evt.detail.subflow }
)
grflw1.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw1 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace1H"]').addEventListener('click',
(evt) => { grflw1.autoPlace('horizontal', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
document.querySelector('[data-trigger="onAutoplace1V"]').addEventListener('click',
(evt) => { grflw1.autoPlace('vertical', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
document.querySelector('input[data-id="compunet"]').addEventListener('change',
(evt) => { grflw1.setAttribute('tension', evt.target.value); grflw1.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw1.setAttribute('wiretype', evt.target.value); grflw1.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="compunet" flow="./flows/testFlow1.1.json" tension="60" isolated>
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace1H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace1V">Auto-place Vertical</button>
<select name="align" data-id="compunet">
<option value="center">Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight">Straight</option>
<option value="bezier" selected>Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="compunet" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
</body>
</html>

100
graflow_examples/test2.html Normal file
View File

@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:99999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.organi{ width: 40vw; height: 100vh; background:black; }
</style>
<script>
window.addEventListener('load',()=>{
let grflw3 = document.querySelector('bz-graflow.organi')
grflw3.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw3 = evt.detail.subflow }
)
grflw3.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw3 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace3H"]').addEventListener('click',
(evt) => { grflw3.autoPlace('horizontal', 80, 80, 1000, document.querySelector('[data-id="organi"]').value) }
)
document.querySelector('[data-trigger="onAutoplace3V"]').addEventListener('click',
(evt) => { grflw3.autoPlace('vertical', 80, 30, 1000, document.querySelector('[data-id="organi"]').value) }
)
document.querySelector('input[data-id="organi"]').addEventListener('change',
(evt) => { grflw3.setAttribute('tension', evt.target.value); grflw3.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw3.setAttribute('wiretype', evt.target.value); grflw3.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="organi" flow="./flows/testFlow2.json" tension="60" isolated>
<div class="demooptions">
<button data-trigger="onAutoplace3H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace3V">Auto-place Vertical</button>
<select name="align" data-id="organi">
<option value="center">Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight">Straight</option>
<option value="bezier" selected>Bezier</option>
<option value="parent">Parent</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="organi" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
</body>
</html>

View File

@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:99999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.eic{ grid-column: 1 / -1; width: 120vw; height: 40vh; background: var(--eicui-base-color-grey-10); }
</style>
<script>
window.addEventListener('load',()=>{
let grflw2 = document.querySelector('bz-graflow.eic')
grflw2.setAttribute('tension', document.querySelector('input[data-id="eic"]').value)
grflw2.setAttribute('align', document.querySelector('select[name="align"]').value)
grflw2.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
grflw2.addEventListener('bz:graflow:refresh',
(evt) => { grflw2.style.transform = 'scale(.75)'; }
)
document.querySelector('[data-trigger="onAutoplace2H"]').addEventListener('click',
(evt) => { grflw2.autoPlace('horizontal', 100, 30, 1000, document.querySelector('[data-id="eic"]').value) }
)
document.querySelector('[data-trigger="onAutoplace2V"]').addEventListener('click',
(evt) => { grflw2.autoPlace('vertical', 80, 80, 1000, document.querySelector('[data-id="eic"]').value) }
)
document.querySelector('input[data-id="eic"]').addEventListener('change',
(evt) => { grflw2.setAttribute('tension', evt.target.value); grflw2.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw2.setAttribute('wiretype', evt.target.value); grflw2.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="eic" flow="./flows/testFlowEvent1.json" tension="50">
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace2H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace2V">Auto-place Vertical</button>
<select name="align" data-id="eic">
<option value="center">Center</option>
<option value="first" selected>First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight">Straight</option>
<option value="bezier" selected>Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="eic" type="number" size="2" value="50"></div>
</div>
</bz-graflow>
</body>
</html>

101
graflow_examples/test3.html Normal file
View File

@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:99999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.eic{ grid-column: 1 / -1; width: 80vw; height: 60vh; background: var(--eicui-base-color-grey-10); }
</style>
<script>
window.addEventListener('load',()=>{
let grflw2 = document.querySelector('bz-graflow.eic')
grflw2.setAttribute('tension', document.querySelector('input[data-id="eic"]').value)
grflw2.setAttribute('align', document.querySelector('select[name="align"]').value)
grflw2.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
grflw2.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw2 = evt.detail.subflow }
)
grflw2.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw2 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace2H"]').addEventListener('click',
(evt) => { grflw2.autoPlace('horizontal', 100, 30, 1000, document.querySelector('[data-id="eic"]').value) }
)
document.querySelector('[data-trigger="onAutoplace2V"]').addEventListener('click',
(evt) => { grflw2.autoPlace('vertical', 80, 80, 1000, document.querySelector('[data-id="eic"]').value) }
)
document.querySelector('input[data-id="eic"]').addEventListener('change',
(evt) => { grflw2.setAttribute('tension', evt.target.value); grflw2.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw2.setAttribute('wiretype', evt.target.value); grflw2.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="eic" flow="./flows/testFlowEic.json" tension="60">
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace2H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace2V">Auto-place Vertical</button>
<select name="align" data-id="eic">
<option value="center">Center</option>
<option value="first" selected>First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight"selected>Straight</option>
<option value="bezier">Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="eic" type="number" size="2" value="1"></div>
</div>
</bz-graflow>
</body>
</html>

View File

@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:999999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
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); }
</style>
<script>
window.addEventListener('load',()=>{
let grflw4 = document.querySelector('bz-graflow.icmp')
grflw4.setAttribute('tension', document.querySelector('input[data-id="icmp"]').value)
grflw4.setAttribute('align', document.querySelector('select[name="align"]').value)
grflw4.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
grflw4.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw4 = evt.detail.subflow }
)
grflw4.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw4 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace4H"]').addEventListener('click',
(evt) => { grflw4.autoPlace('horizontal', 100, 30, 1000, document.querySelector('[data-id="icmp"]').value) }
)
document.querySelector('[data-trigger="onAutoplace4V"]').addEventListener('click',
(evt) => { grflw4.autoPlace('vertical', 80, 80, 1000, document.querySelector('[data-id="icmp"]').value) }
)
document.querySelector('input[data-id="icmp"]').addEventListener('change',
(evt) => { grflw4.setAttribute('tension', evt.target.value); grflw4.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw4.setAttribute('wiretype', evt.target.value); grflw4.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="icmp" flow="./flows/testFlowICMP2.json" tension="20" align="first" wiretype="ortho" gapx="100" gapy="30">
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace4H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace4V">Auto-place Vertical</button>
<select name="align" data-id="icmp">
<option value="center">Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent" selected>Parent</option>
</select>
<select name="wiretype">
<option value="ortho" selected>Ortho</option>
<option value="straight">Straight</option>
<option value="bezier">Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="icmp" type="number" size="2" value="20"></div>
</div>
</bz-graflow>
</body>
</html>

152
graflow_examples/test4.html Normal file
View File

@@ -0,0 +1,152 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:999999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
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); }
.container {
resize: both;
overflow: auto; /* required in practice */
min-width: 800px;
min-height: 300px;
border: 1px solid #999;
padding: 0;
position: relative;
border:2px solid #A00
}
.container::after {
content: "";
position: absolute;
right: 3px;
bottom: 3px;
width: 20px;
height: 20px;
pointer-events: none;
background:
repeating-linear-gradient(
135deg,
transparent 0px,
transparent 3px,
#A00 3px,
#A00 6px
);
}
</style>
<script>
window.addEventListener('load',()=>{
const severities = ['primary', 'info', 'success', 'warning', 'danger', 'accent']
let grflw4 = document.querySelector('bz-graflow.icmp')
grflw4.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw4 = evt.detail.subflow }
)
grflw4.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw4 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace4H"]').addEventListener('click',
(evt) => { grflw4.autoPlace('horizontal', 100, 30, 1000, document.querySelector('[data-id="icmp"]').value) }
)
document.querySelector('[data-trigger="onAutoplace4V"]').addEventListener('click',
(evt) => { grflw4.autoPlace('vertical', 80, 80, 1000, document.querySelector('[data-id="icmp"]').value) }
)
document.querySelector('input[data-id="icmp"]').addEventListener('change',
(evt) => { grflw4.setAttribute('tension', evt.target.value); grflw4.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw4.setAttribute('wiretype', evt.target.value); grflw4.refresh() }
)
const el = document.querySelector('.container')
let timer = null // debounce
const ro = new ResizeObserver(([entry]) => {
const grfl = entry.target.querySelector('bz-graflow')
grfl.autofit()
})
ro.observe(el)
let aifmi = null; let sidx=0;
const sevanimation = () => { console.log('sevanimation')
severities.forEach(severity => aifmi.removeAttribute(severity))
aifmi.setAttribute(severities[sidx], '')
sidx++
if (sidx >= severities.length) sidx = 0
setTimeout(sevanimation, 1000)
}
grflw4.addEventListener('bz:graflow:refreshed',() => {
if(aifmi) return
aifmi = grflw4.stagedNodes['aifm-investment'].querySelector('.body')
sevanimation()
})
})
</script>
</head>
<body>
<div class="container">
<bz-graflow class="icmp" flow="./flows/testFlowICMP.json" tension="60">
<div class="demooptions">
<button data-trigger="onAutoplace4H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace4V">Auto-place Vertical</button>
<select name="align" data-id="icmp">
<option value="center">Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight">Straight</option>
<option value="bezier" selected>Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="icmp" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
</div>
</body>
</html>

View File

@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:999999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.compunet{ grid-column: 1 / -1; width: 100vw; height: 60vh; background:black; }
</style>
<script>
window.addEventListener('load',()=>{
let grflw1 = document.querySelector('bz-graflow.compunet')
grflw1.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw1 = evt.detail.subflow }
)
grflw1.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw1 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace1H"]').addEventListener('click',
(evt) => { grflw1.autoPlace('horizontal', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
document.querySelector('[data-trigger="onAutoplace1V"]').addEventListener('click',
(evt) => { grflw1.autoPlace('vertical', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
document.querySelector('input[data-id="compunet"]').addEventListener('change',
(evt) => { grflw1.setAttribute('tension', evt.target.value); grflw1.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw1.setAttribute('wiretype', evt.target.value); grflw1.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="compunet" flow="./flows/testFlow1.json" tension="60" isolated edit="nodesmove,editwires,dropnodes" >
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace1H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace1V">Auto-place Vertical</button>
<select name="align" data-id="compunet">
<option value="center">Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho">Ortho</option>
<option value="straight">Straight</option>
<option value="bezier" selected>Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="compunet" type="number" size="2" value="60"></div>
</div>
</bz-graflow>
</body>
</html>

102
graflow_examples/test6.html Normal file
View File

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>graflow</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="../../eicui/eicui-2.0.css">
<link type="text/css" rel="stylesheet" href="../buildoz.css">
<script src="../buildoz.js"></script>
<script src="../bzGraflow.js"></script>
<style>
@font-face { /*FF does not indirectly load if inside a shawdow-dom */
font-family: 'glyphs';
src: url('/assets/styles/fonts/glyphs.eot');
src: url('/assets/styles/fonts/glyphs.eot') format('embedded-opentype'),
url('/assets/styles/fonts/glyphs.ttf') format('truetype'),
url('/assets/styles/fonts/glyphs.woff') format('woff'),
url('/assets/styles/fonts/glyphs.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
body{
display: grid;
grid-gap: 5px;
background:#888;
font-size: 16px;
}
.demooptions{
padding: 2px;
position: absolute;
top: 2px;
right: 2px;
width: 10em;
background: #FFFB;
border-radius: 5px;
text-align: center;
z-index:999999;
font-size: .7em;
border: 1px solid #999;
}
.demooptions button{
text-transform: none;
margin: 2px;
font-size: 1em;
}
bz-graflow{
overflow: scroll;
border: 2px solid black;
}
bz-graflow.compunet{ grid-column: 1 / -1; width: 100vw; height: 100vh; background:black; }
</style>
<script>
window.addEventListener('load',()=>{
let grflw1 = document.querySelector('bz-graflow.compunet')
grflw1.setAttribute('tension', document.querySelector('input[data-id="compunet"]').value)
grflw1.setAttribute('align', document.querySelector('select[name="align"]').value)
grflw1.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
grflw1.addEventListener('bz:graflow:subflowLoaded',
(evt) => { grflw1 = evt.detail.subflow }
)
grflw1.addEventListener('bz:graflow:subflowExited',
(evt) => { grflw1 = evt.target }
)
document.querySelector('[data-trigger="onAutoplace1H"]').addEventListener('click',
(evt) => { grflw1.autoPlace('horizontal', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
document.querySelector('[data-trigger="onAutoplace1V"]').addEventListener('click',
(evt) => { grflw1.autoPlace('vertical', 80, 30, 1000, document.querySelector('[data-id="compunet"]').value) }
)
document.querySelector('input[data-id="compunet"]').addEventListener('change',
(evt) => { grflw1.setAttribute('tension', evt.target.value); grflw1.refresh() }
)
document.querySelector('select[name="wiretype"]').addEventListener('change',
(evt) => { grflw1.setAttribute('wiretype', evt.target.value); grflw1.refresh() }
)
})
</script>
</head>
<body>
<bz-graflow class="compunet" flow="./flows/testFlow16ports.json" tension="60" isolated edit="nodesmove" >
<div class="demooptions"> <!-- just for demo purposes -->
<button data-trigger="onAutoplace1H">Auto-place Horizontal</button>
<button data-trigger="onAutoplace1V">Auto-place Vertical</button>
<select name="align" data-id="compunet">
<option value="center">Center</option>
<option value="first">First</option>
<option value="last">Last</option>
<option value="parent">Parent</option>
</select>
<select name="wiretype">
<option value="ortho" selected>Ortho</option>
<option value="straight">Straight</option>
<option value="bezier">Bezier</option>
</select>
<div class="cols-2"><label>tension</label><input data-id="compunet" type="number" size="2" value="20"></div>
</div>
</bz-graflow>
</body>
</html>