|
@@ -7,6 +7,7 @@ import FlowModalData from './modal-data' // NEW 15/02/2018
|
|
|
import HxContextMenu from '@/components/shared/hx-contextmenu'
|
|
|
import SvgDefs from './svgdefswrapper'
|
|
|
import utils from '@/utils/utils'
|
|
|
+import _debounce from 'lodash.debounce'
|
|
|
|
|
|
export default {
|
|
|
name: 'FlowManager',
|
|
@@ -29,14 +30,16 @@ export default {
|
|
|
|
|
|
stickySockets: false,
|
|
|
stickyTriggers: false,
|
|
|
- nodeActivity: true
|
|
|
+ nodeActivity: true,
|
|
|
+ nodeProps: [],
|
|
|
+ linkProps: []
|
|
|
+ // cacheNodeProps: [],
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
- ...mapGetters('flow', ['registry', 'activity', 'nodeData', 'nodeById', 'nodeSelection']),
|
|
|
+ ...mapGetters('flow', ['registry', 'activity', 'nodeData', 'nodeById', 'nodeSelection', 'nodeIdxCache']),
|
|
|
outputNode () {
|
|
|
const n = this.nodeData.nodes.find(n => n.src === 'Output')
|
|
|
-
|
|
|
return !!n
|
|
|
},
|
|
|
viewClasses () {
|
|
@@ -48,60 +51,11 @@ export default {
|
|
|
'selecting': !!this.selector
|
|
|
}
|
|
|
},
|
|
|
- nodeProps () {
|
|
|
+ /* nodeProps () {
|
|
|
return (node) => {
|
|
|
- let highlight = {}
|
|
|
- if (this.pointerLink.active && this.pointerLink.src.nodeId !== node.id) {
|
|
|
- if (this.pointerLink.src.in !== undefined) {
|
|
|
- highlight = {type: 'socket-out', dtype: this.pointerLink.src.type}
|
|
|
- } else {
|
|
|
- highlight = {type: 'socket-in', dtype: this.pointerLink.src.type}
|
|
|
- }
|
|
|
- }
|
|
|
- if (this.pointerTriggerLink.active && this.pointerTriggerLink.src.nodeId !== node.id) {
|
|
|
- highlight = {type: (this.pointerTriggerLink.src.dir === 'in') ? 'trigger-in' : 'trigger-out'}
|
|
|
- }
|
|
|
-
|
|
|
- const nodeClass = this.registry[node.src]
|
|
|
- if (!nodeClass) {
|
|
|
- this.NODE_REMOVE([node])
|
|
|
- return
|
|
|
- }
|
|
|
- return {
|
|
|
- transform: `translate(${node.x} ${node.y})`,
|
|
|
- id: node.id,
|
|
|
- // Combine this into one
|
|
|
- match: highlight,
|
|
|
- dragging: this.dragging && !!this.dragging[node.id],
|
|
|
- activity: this.activity && this.activity.nodes && this.activity.nodes[node.id]
|
|
|
- }
|
|
|
+ return this.nodePropsBuild(node)
|
|
|
}
|
|
|
- },
|
|
|
- linkProps () {
|
|
|
- return (link) => {
|
|
|
- if (!this.$refs.nodes) return
|
|
|
- // For size .x .y
|
|
|
- const nodeFrom = this.nodeById(link.from)
|
|
|
- const nodeTo = this.nodeById(link.to)
|
|
|
-
|
|
|
- const refFrom = this.$refs.nodes.find(n => n.id === link.from)
|
|
|
- const refTo = this.$refs.nodes.find(n => n.id === link.to)
|
|
|
- if (!refFrom || !refTo) { // delete link
|
|
|
- return {}
|
|
|
- }
|
|
|
-
|
|
|
- const fromOutput = refFrom.outputPos(0) // only 1 output
|
|
|
- const toInput = refTo.inputPos(link.in)
|
|
|
-
|
|
|
- return {
|
|
|
- x1: nodeFrom.x + fromOutput.x,
|
|
|
- y1: nodeFrom.y + fromOutput.y,
|
|
|
- x2: nodeTo.x + toInput.x,
|
|
|
- y2: nodeTo.y + toInput.y,
|
|
|
- status: this.activity.nodes[nodeFrom.id] && this.activity.nodes[nodeFrom.id].status
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
+ }, */
|
|
|
triggerProps () {
|
|
|
return (trigger) => {
|
|
|
if (!this.$refs.nodes) return
|
|
@@ -133,11 +87,28 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ 'nodeData.nodes' (val, oldVal) {
|
|
|
+ console.log('Nodes updated')
|
|
|
+ this.nodePropsUpdate()
|
|
|
+ },
|
|
|
+ 'nodeData.links' () {
|
|
|
+ console.log('Updating links')
|
|
|
+ this.linkPropsUpdate()
|
|
|
+ },
|
|
|
+ 'activity' () {
|
|
|
+ _debounce(this.activityUpdate, 1500)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created () {
|
|
|
+ this.nodePropsUpdate()
|
|
|
},
|
|
|
mounted () {
|
|
|
+ console.log('Mounted')
|
|
|
this.$nextTick(() => {
|
|
|
this.$forceUpdate()
|
|
|
+ this.$nextTick(() => { this.linkPropsUpdate() })
|
|
|
})
|
|
|
document.addEventListener('keydown', this.keyDown)
|
|
|
document.addEventListener('keyup', this.keyUp)
|
|
@@ -155,6 +126,99 @@ export default {
|
|
|
'LINK_ADD', 'LINK_REMOVE',
|
|
|
'TRIGGER_ADD', 'TRIGGER_REMOVE' ]),
|
|
|
|
|
|
+ activityUpdate () {
|
|
|
+ console.log('Activity updated')
|
|
|
+ this.linkPropsUpdate()
|
|
|
+ },
|
|
|
+ nodePropsBuild (node) {
|
|
|
+ let highlight = {}
|
|
|
+ if (this.pointerLink.active && this.pointerLink.src.nodeId !== node.id) {
|
|
|
+ if (this.pointerLink.src.in !== undefined) {
|
|
|
+ highlight = {type: 'socket-out', dtype: this.pointerLink.src.type}
|
|
|
+ } else {
|
|
|
+ highlight = {type: 'socket-in', dtype: this.pointerLink.src.type}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this.pointerTriggerLink.active && this.pointerTriggerLink.src.nodeId !== node.id) {
|
|
|
+ highlight = {type: (this.pointerTriggerLink.src.dir === 'in') ? 'trigger-in' : 'trigger-out'}
|
|
|
+ }
|
|
|
+
|
|
|
+ const nodeClass = this.registry[node.src]
|
|
|
+ if (!nodeClass) {
|
|
|
+ this.NODE_REMOVE([node])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ transform: `translate(${node.x} ${node.y})`,
|
|
|
+ id: node.id,
|
|
|
+ node: node,
|
|
|
+ // Combine this into one
|
|
|
+ match: highlight,
|
|
|
+ selected: !!this.nodeSelection[node.id],
|
|
|
+ dragging: this.dragging && !!this.dragging[node.id],
|
|
|
+ activity: this.activity && this.activity.nodes && this.activity.nodes[node.id]
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ nodePropsUpdate (n) {
|
|
|
+ // Find node ID and update it only
|
|
|
+ if (n) {
|
|
|
+ const idx = this.nodeIdxCache[n.id]
|
|
|
+ this.$set(this.nodeProps, idx, this.nodePropsBuild(n))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const ret = []
|
|
|
+ for (let node of this.nodeData.nodes) {
|
|
|
+ ret.push(this.nodePropsBuild(node))
|
|
|
+ }
|
|
|
+ this.nodeProps = ret
|
|
|
+ },
|
|
|
+ // propCaches
|
|
|
+ linkPropsUpdate (link, idx) {
|
|
|
+ if (!this.$refs.nodes) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.linkPropsUpdate() // Retry until we have refs
|
|
|
+ }, 200)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const linkProps = (link) => {
|
|
|
+ if (!this.$refs.nodes) return [] // empty we need $refs.nodes
|
|
|
+ // For size .x .y
|
|
|
+ const nodeFrom = this.nodeById(link.from)
|
|
|
+ const nodeTo = this.nodeById(link.to)
|
|
|
+
|
|
|
+ const refFrom = this.$refs.nodes.find(n => n.node.id === link.from)
|
|
|
+ const refTo = this.$refs.nodes.find(n => n.node.id === link.to)
|
|
|
+ if (!refFrom || !refTo) { // delete link
|
|
|
+ // No ref yet
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+
|
|
|
+ const fromOutput = refFrom.outputPos(0) // only 1 output
|
|
|
+ const toInput = refTo.inputPos(link.in)
|
|
|
+
|
|
|
+ return {
|
|
|
+ x1: nodeFrom.x + fromOutput.x,
|
|
|
+ y1: nodeFrom.y + fromOutput.y,
|
|
|
+ x2: nodeTo.x + toInput.x,
|
|
|
+ y2: nodeTo.y + toInput.y,
|
|
|
+ status: this.activity.nodes[nodeFrom.id] && this.activity.nodes[nodeFrom.id].status
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (link) {
|
|
|
+ if (idx === undefined)idx = this.linkProps.findIndex(l => l === link)
|
|
|
+ this.$set(this.linkProps, idx, linkProps(link))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const ret = []
|
|
|
+ for (let link of this.nodeData.links) {
|
|
|
+ const p = linkProps(link)
|
|
|
+ ret.push(p)
|
|
|
+ }
|
|
|
+ this.linkProps = ret
|
|
|
+ },
|
|
|
+
|
|
|
keyDown (ev) {
|
|
|
if (document.activeElement && document.activeElement.matches('input,textarea')) { return }
|
|
|
if (ev.shiftKey) {
|
|
@@ -162,23 +226,22 @@ export default {
|
|
|
this.triggerLinking = true
|
|
|
}
|
|
|
|
|
|
- let single = null
|
|
|
- if (Object.keys(this.nodeSelection).length === 1) { single = this.nodeSelection[Object.keys(this.nodeSelection)[0]] }
|
|
|
+ let singleId = null
|
|
|
+ if (Object.keys(this.nodeSelection).length === 1) { singleId = Object.keys(this.nodeSelection)[0] }
|
|
|
switch (ev.key) {
|
|
|
case 'Enter':
|
|
|
- if (!single) { return }
|
|
|
- this.nodeInspect(single, true)
|
|
|
+ if (!singleId) { return }
|
|
|
+ this.nodeInspect(singleId, true)
|
|
|
break
|
|
|
case 'Delete':
|
|
|
if (Object.keys(this.nodeSelection).length === 0) { return }
|
|
|
- console.log('Removing nodes:', this.nodeSelection)
|
|
|
this.NODE_REMOVE(this.nodeSelection)
|
|
|
break
|
|
|
case 'a':
|
|
|
if (ev.ctrlKey) {
|
|
|
ev.preventDefault()
|
|
|
ev.stopPropagation()
|
|
|
- this.NODE_SELECTION_ADD(this.nodeData.nodes)
|
|
|
+ this.select(this.nodeData.nodes)
|
|
|
}
|
|
|
break
|
|
|
}
|
|
@@ -196,8 +259,7 @@ export default {
|
|
|
// and create some LinkAdd method
|
|
|
socketPointerDown (nodeId, ev, socket) {
|
|
|
if (ev.button !== 0) return
|
|
|
-
|
|
|
- const nodeRef = this.$refs.nodes.find(n => n.id === nodeId)
|
|
|
+ const nodeRef = this.$refs.nodes.find(n => n.node.id === nodeId)
|
|
|
const node = this.nodeById(nodeId)
|
|
|
const isInput = socket.in !== undefined
|
|
|
const socketPos = isInput ? nodeRef.inputPos(socket.in) : nodeRef.outputPos(socket.out)
|
|
@@ -210,13 +272,17 @@ export default {
|
|
|
y2: node.y + socketPos.y
|
|
|
}
|
|
|
|
|
|
- this.pointerLink.active = true
|
|
|
if (isInput) {
|
|
|
this.pointerLink.src = {nodeId: nodeId, type: this.registry[node.src].inputs[socket.in].type, in: socket.in}
|
|
|
} else {
|
|
|
this.pointerLink.src = {nodeId: nodeId, type: this.registry[node.src].output.type, out: 0}
|
|
|
}
|
|
|
+
|
|
|
utils.createDrag({
|
|
|
+ dragStart: (ev) => {
|
|
|
+ this.pointerLink.active = true
|
|
|
+ this.nodePropsUpdate()
|
|
|
+ },
|
|
|
drag: (ev) => {
|
|
|
const p = this.transformedPoint(ev.clientX, ev.clientY)
|
|
|
if (isInput) {
|
|
@@ -229,6 +295,7 @@ export default {
|
|
|
},
|
|
|
drop: (ev) => {
|
|
|
this.pointerLink.active = false
|
|
|
+ this.nodePropsUpdate()
|
|
|
if (ev.target.matches('.flow-pan-zoom__transformer')) {
|
|
|
if (isInput) {
|
|
|
console.error('LINK: Invalid target')
|
|
@@ -369,20 +436,21 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
-
|
|
|
+ nodeRemove (nodeId) {
|
|
|
+ const node = this.nodeById(nodeId)
|
|
|
+ this.NODE_REMOVE([node])
|
|
|
+ },
|
|
|
// Is this used?
|
|
|
- nodeInspect (tnode, force) {
|
|
|
- this.$emit('nodeInspect', tnode, force)
|
|
|
+ nodeInspect (nodeId, force) {
|
|
|
+ this.$emit('nodeInspect', nodeId, force)
|
|
|
},
|
|
|
|
|
|
// HERE
|
|
|
- nodePointerDown (ev, i) {
|
|
|
+ nodePointerDown (ev, nodeId) {
|
|
|
document.activeElement && document.activeElement.blur()
|
|
|
- const tnode = this.nodeData.nodes[i]
|
|
|
+ const tnode = this.nodeById(nodeId)
|
|
|
if (ev.button === 1) {
|
|
|
this.NODE_REMOVE([tnode])
|
|
|
- // this.nodeRemove(tnode)
|
|
|
- // remove related links
|
|
|
return
|
|
|
}
|
|
|
if (ev.button !== 0) return // first button
|
|
@@ -392,13 +460,14 @@ export default {
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
- this.nodeInspect(tnode)
|
|
|
+ this.nodeInspect(tnode.id)
|
|
|
|
|
|
+ let selectionAdd = true
|
|
|
// Switch selection
|
|
|
if (!this.nodeSelection[tnode.id] && !ev.ctrlKey) {
|
|
|
- this.NODE_SELECTION_CLEAR()
|
|
|
+ selectionAdd = false
|
|
|
}
|
|
|
- this.NODE_SELECTION_ADD([tnode])
|
|
|
+ this.select([tnode], selectionAdd)
|
|
|
this.NODE_RAISE(this.nodeSelection)
|
|
|
|
|
|
let curP = this.transformedPoint(ev.x, ev.y)
|
|
@@ -406,6 +475,7 @@ export default {
|
|
|
if (ev.ctrlKey && Object.keys(this.nodeSelection).length > 0) clone = true
|
|
|
utils.createDrag({
|
|
|
drag: (ev) => {
|
|
|
+ if (!ev.ctrlKey) clone = false
|
|
|
/// /////////// IMPORTANT NEW ////////////////
|
|
|
// logic: we analyse selection, create new nodes based on same src
|
|
|
// with same things, and checkout the inner links, nodes between our nodes
|
|
@@ -442,23 +512,29 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// Check inner links
|
|
|
-
|
|
|
- this.NODE_SELECTION_CLEAR()
|
|
|
- this.NODE_SELECTION_ADD(newNodes)
|
|
|
+ this.select(newNodes)
|
|
|
}
|
|
|
+ // DRAG operation
|
|
|
this.dragging = this.nodeSelection
|
|
|
const dragP = this.transformedPoint(ev.x, ev.y)
|
|
|
const nodeUpdate = []
|
|
|
for (let k in this.nodeSelection) {
|
|
|
const n = this.nodeById(k)
|
|
|
- // create new nodes
|
|
|
- nodeUpdate.push({
|
|
|
+ const cloneNode = {
|
|
|
...n,
|
|
|
x: n.x + dragP.x - curP.x,
|
|
|
y: n.y + dragP.y - curP.y
|
|
|
+ }
|
|
|
+ // XXX: temporary code
|
|
|
+ this.nodePropsUpdate(cloneNode)
|
|
|
+ // Find links too
|
|
|
+ this.nodeData.links.forEach((link, idx) => {
|
|
|
+ if (link.from !== k && link.to !== k) return true
|
|
|
+ this.$nextTick(() => { this.linkPropsUpdate(link, idx) })
|
|
|
})
|
|
|
+
|
|
|
+ nodeUpdate.push(cloneNode)
|
|
|
}
|
|
|
this.NODE_UPDATE(nodeUpdate)
|
|
|
curP = dragP
|
|
@@ -472,14 +548,23 @@ export default {
|
|
|
for (let k in this.nodeSelection) {
|
|
|
const n = this.nodeById(k)
|
|
|
// create new nodes
|
|
|
- nodeUpdate.push({
|
|
|
+ const cloneNode = {
|
|
|
...n,
|
|
|
x: n.x + dragP.x - curP.x,
|
|
|
y: n.y + dragP.y - curP.y
|
|
|
// snapping
|
|
|
// x: Math.round((n.x + dragP.x - curP.x) / 10) * 10,
|
|
|
// y: Math.round((n.y + dragP.y - curP.y) / 10) * 10
|
|
|
+ }
|
|
|
+ // XXX: temporary code
|
|
|
+ this.nodePropsUpdate(cloneNode)
|
|
|
+ // Place this in the nodeProps itself
|
|
|
+ this.nodeData.links.forEach((link, idx) => {
|
|
|
+ if (link.from !== k && link.to !== k) return true
|
|
|
+ this.$nextTick(() => { this.linkPropsUpdate(link, idx) })
|
|
|
})
|
|
|
+
|
|
|
+ nodeUpdate.push(cloneNode)
|
|
|
}
|
|
|
// Updating nodes
|
|
|
this.NODE_UPDATE(nodeUpdate)
|
|
@@ -490,6 +575,7 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
+
|
|
|
/// ////////////
|
|
|
// NODE CREATOR FUNC
|
|
|
//
|
|
@@ -551,7 +637,8 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
drop: (ev) => {
|
|
|
- if (!ev.shiftKey) this.NODE_SELECTION_CLEAR()
|
|
|
+ let selectionAdd = false
|
|
|
+ if (ev.shiftKey) selectionAdd = true
|
|
|
const nodesToSelect = []
|
|
|
for (let n in this.nodeData.nodes) {
|
|
|
const node = this.nodeData.nodes[n]
|
|
@@ -562,14 +649,16 @@ export default {
|
|
|
// Add to selection
|
|
|
}
|
|
|
}
|
|
|
- this.NODE_SELECTION_ADD(nodesToSelect)
|
|
|
+ this.select(nodesToSelect, selectionAdd)
|
|
|
this.selector = null
|
|
|
+ this.nodePropsUpdate()
|
|
|
},
|
|
|
noDrag: (ev) => {
|
|
|
- if (!ev.shiftKey) this.NODE_SELECTION_CLEAR()
|
|
|
+ if (!ev.shiftKey) this.select()
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
+
|
|
|
documentProcess () {
|
|
|
const n = this.nodeData.nodes.find(n => n.src === 'Output')
|
|
|
this.NODE_PROCESS(n.id)
|
|
@@ -604,6 +693,15 @@ export default {
|
|
|
|
|
|
this.NODE_ADD([portalNode])
|
|
|
},
|
|
|
+ select (nodes, add) {
|
|
|
+ if (!add) {
|
|
|
+ this.NODE_SELECTION_CLEAR()
|
|
|
+ }
|
|
|
+ if (nodes) {
|
|
|
+ this.NODE_SELECTION_ADD(nodes)
|
|
|
+ }
|
|
|
+ this.nodePropsUpdate()
|
|
|
+ },
|
|
|
// HELPERS depending on svg ref
|
|
|
createSVGPoint (x, y) {
|
|
|
const p = this.$refs.svg.createSVGPoint()
|