|
@@ -5,36 +5,17 @@
|
|
|
class="view"
|
|
|
:width="width"
|
|
|
:height="height">
|
|
|
-
|
|
|
- <!-- static dragger -->
|
|
|
- <rect
|
|
|
- ref="transformer"
|
|
|
- class="transformer"
|
|
|
- width="100%"
|
|
|
- height="100%"
|
|
|
- @mousedown="dragStart"/>
|
|
|
-
|
|
|
- <g
|
|
|
- ref="transform"
|
|
|
- :transform="panzoomTransform">
|
|
|
-
|
|
|
- <!-- links -->
|
|
|
- <g
|
|
|
- class="connection"
|
|
|
+ <flow-pan-zoom ref="panzoom" v-model="nodeData.panzoom">
|
|
|
+ <flow-link
|
|
|
v-for="(l,i) in nodeData.links"
|
|
|
:key="i"
|
|
|
- >
|
|
|
- <path
|
|
|
- class="area"
|
|
|
- v-bind="link(l)"
|
|
|
- />
|
|
|
- <path
|
|
|
- class="visible"
|
|
|
- v-bind="link(l)"
|
|
|
- />
|
|
|
- </g>
|
|
|
-
|
|
|
- <!-- nodes -->
|
|
|
+ v-bind="linkProps(l)"
|
|
|
+ />
|
|
|
+ <!-- mousel link-->
|
|
|
+ <flow-link
|
|
|
+ v-if="pointerLink.active"
|
|
|
+ v-bind="pointerLink"
|
|
|
+ />
|
|
|
<flow-node
|
|
|
ref="nodes"
|
|
|
v-for="(n,i) of nodeData.nodes"
|
|
@@ -43,10 +24,9 @@
|
|
|
:value="n"
|
|
|
:transform="nodeTransform(i)"
|
|
|
@nodePointerDown.prevent="nodeDragStart($event,i)"
|
|
|
- @socketPointerDown.prevent="nodeDragStart($event,i)"
|
|
|
+ @socketPointerDown="socketPointerDown(n.id,...arguments)"
|
|
|
/>
|
|
|
-
|
|
|
- </g>
|
|
|
+ </flow-pan-zoom>
|
|
|
</svg>
|
|
|
{{ nodeData }}
|
|
|
<div v-for="(n,i) of nodeData.nodes">
|
|
@@ -57,142 +37,137 @@
|
|
|
<script>
|
|
|
import nodeData from './nodedata'
|
|
|
import FlowNode from './flownode'
|
|
|
+import FlowLink from './flowlink'
|
|
|
+import FlowPanZoom from './flowpanzoom'
|
|
|
|
|
|
export default {
|
|
|
name: 'FlowManager',
|
|
|
- components: {FlowNode},
|
|
|
+ components: {FlowNode, FlowLink, FlowPanZoom},
|
|
|
props: {
|
|
|
'width': {type: String, default: '800px'},
|
|
|
'height': {type: String, default: '600px'}
|
|
|
},
|
|
|
data () {
|
|
|
return {
|
|
|
- nodeData: nodeData // shared?
|
|
|
+ nodeData: nodeData, // shared?
|
|
|
+ pointerLink: {active: false, x1: 0, y1: 0, x2: 0, y2: 0}
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
- panzoomTransform () {
|
|
|
- const transString = 'matrix(' + [
|
|
|
- this.nodeData.zoom, 0, 0,
|
|
|
- this.nodeData.zoom, this.nodeData.pan.x, this.nodeData.pan.y
|
|
|
- ].join(' ') + ')'
|
|
|
- return transString
|
|
|
- },
|
|
|
nodeTransform () {
|
|
|
return (i) => `translate(${this.nodeData.nodes[i].x} ${this.nodeData.nodes[i].y})`
|
|
|
+ },
|
|
|
+ // computed
|
|
|
+ linkProps () {
|
|
|
+ return (link) => {
|
|
|
+ if (!this.$refs.nodes) return
|
|
|
+ const refFrom = this.$refs.nodes.find(n => n.value.id === link.from)
|
|
|
+ const refTo = this.$refs.nodes.find(n => n.value.id === link.to)
|
|
|
+
|
|
|
+ const fromOutput = refFrom.output(0) // only 1 output
|
|
|
+ const toInput = refTo.input(link.in)
|
|
|
+
|
|
|
+ const x1 = refFrom.value.x + fromOutput.cx // + inputPos.x
|
|
|
+ const y1 = refFrom.value.y + fromOutput.cy // + inputPos.y
|
|
|
+
|
|
|
+ const x2 = refTo.value.x + toInput.cx
|
|
|
+ const y2 = refTo.value.y + toInput.cy
|
|
|
+ // console.log('Thing:', x1, y1, x2, y2)
|
|
|
+ return {x1, y1, x2, y2}
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
},
|
|
|
mounted () {
|
|
|
- document.addEventListener('mousewheel', this.wheel)
|
|
|
- document.addEventListener('mousemove', this.mousemove)
|
|
|
this.$nextTick(() => {
|
|
|
this.$forceUpdate()
|
|
|
})
|
|
|
},
|
|
|
- beforeDestroy () {
|
|
|
- document.removeEventListener('mousewheel', this.wheel)
|
|
|
- document.removeEventListener('mousemove', this.mousemove)
|
|
|
- },
|
|
|
methods: {
|
|
|
- socketPointerDown (e, i, ...params) {
|
|
|
- console.log('Socket down', e, i, params)
|
|
|
+ socketPointerDown (nodeId, e, socket) {
|
|
|
+ const node = this.$refs.nodes.find(n => n.value.id === nodeId)
|
|
|
+
|
|
|
+ const isInput = socket.in != undefined
|
|
|
+ console.log('Socket:', socket)
|
|
|
+ if (isInput) {
|
|
|
+ console.log('Socket is input')
|
|
|
+ }
|
|
|
+ const socketPos = isInput ? node.input(socket.in) : node.output(socket.out)
|
|
|
+
|
|
|
+ const p = this.transformedPoint(e.x, e.y)
|
|
|
+
|
|
|
+ if (isInput) {
|
|
|
+ this.pointerLink.x1 = node.value.x + socketPos.cx
|
|
|
+ this.pointerLink.y1 = node.value.y + socketPos.cy
|
|
|
+ this.pointerLink.x2 = p.x
|
|
|
+ this.pointerLink.y2 = p.y
|
|
|
+ } else {
|
|
|
+ this.pointerLink.x1 = p.x
|
|
|
+ this.pointerLink.y1 = p.y
|
|
|
+ this.pointerLink.x2 = node.value.x + socketPos.cx
|
|
|
+ this.pointerLink.y2 = node.value.y + socketPos.cy
|
|
|
+ }
|
|
|
+
|
|
|
+ this.pointerLink.active = true
|
|
|
+
|
|
|
+ // What socket is this
|
|
|
+ // Create a temporary link
|
|
|
+ const drag = (e) => {
|
|
|
+ const p = this.transformedPoint(e.x, e.y)
|
|
|
+ if (isInput) {
|
|
|
+ this.pointerLink.x1 = p.x
|
|
|
+ this.pointerLink.y1 = p.y
|
|
|
+ } else {
|
|
|
+ this.pointerLink.x2 = p.x
|
|
|
+ this.pointerLink.y2 = p.y
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const drop = (e) => {
|
|
|
+ console.log('Dropping link in ', e.target)
|
|
|
+ document.removeEventListener('mousemove', drag)
|
|
|
+ document.removeEventListener('mouseup', drop)
|
|
|
+ }
|
|
|
+ document.addEventListener('mousemove', drag)
|
|
|
+ document.addEventListener('mouseup', drop)
|
|
|
},
|
|
|
nodeDragStart (e, i) {
|
|
|
+ if (e.button !== 0) return // first button
|
|
|
// we can handle with nodeId and a search
|
|
|
var tnode = this.nodeData.nodes[i]
|
|
|
this.nodeData.nodes.splice(i, 1)
|
|
|
this.nodeData.nodes.push(tnode) // put in last
|
|
|
|
|
|
- const mousemove = (e) => {
|
|
|
- tnode.x += e.movementX / this.nodeData.zoom
|
|
|
- tnode.y += e.movementY / this.nodeData.zoom
|
|
|
+ // transform CTM
|
|
|
+ const delta = this.transformedPoint(e.clientX, e.clientY)
|
|
|
+ delta.x -= tnode.x
|
|
|
+ delta.y -= tnode.y
|
|
|
+
|
|
|
+ const drag = (e) => {
|
|
|
+ const point = this.transformedPoint(e.clientX, e.clientY)
|
|
|
+ tnode.x = point.x - delta.x
|
|
|
+ tnode.y = point.y - delta.y
|
|
|
}
|
|
|
- const mouseup = (e) => {
|
|
|
- document.removeEventListener('mousemove', mousemove)
|
|
|
- document.removeEventListener('mouseup', mouseup)
|
|
|
+ const drop = (e) => {
|
|
|
+ document.removeEventListener('mousemove', drag)
|
|
|
+ document.removeEventListener('mouseup', drop)
|
|
|
}
|
|
|
- document.addEventListener('mousemove', mousemove)
|
|
|
- document.addEventListener('mouseup', mouseup)
|
|
|
- },
|
|
|
- link (link) {
|
|
|
- if (!this.$refs.nodes) return
|
|
|
- const refFrom = this.$refs.nodes.find(n => n.value.id === link.from)
|
|
|
- const refTo = this.$refs.nodes.find(n => n.value.id === link.to)
|
|
|
-
|
|
|
- const fromOutput = refFrom.output(0) // only 1 output
|
|
|
- const toInput = refTo.input(link.in)
|
|
|
-
|
|
|
- const x1 = refFrom.value.x + fromOutput.cx // + inputPos.x
|
|
|
- const y1 = refFrom.value.y + fromOutput.cy // + inputPos.y
|
|
|
-
|
|
|
- const x2 = refTo.value.x + toInput.cx
|
|
|
- const y2 = refTo.value.y + toInput.cy
|
|
|
- // console.log('Thing:', x1, y1, x2, y2)
|
|
|
-
|
|
|
- const linkProps = {d: `M${x1},${y1} C${x1 + 50},${y1} ${x2 - 50},${y2} ${x2},${y2}`}
|
|
|
- return linkProps
|
|
|
- },
|
|
|
- /*
|
|
|
- nodeDragStart (idx) {
|
|
|
- console.log('Start drag')
|
|
|
- var tnode = this.nodes[idx]
|
|
|
- this.nodes.splice(idx, 1)
|
|
|
- this.nodes.push(tnode) // put in last
|
|
|
- },
|
|
|
- nodeDrag (idx) {
|
|
|
- this.$nextTick(() => {
|
|
|
- // manipulate links
|
|
|
- var tnode = this.nodes[idx]
|
|
|
- const foundLinks = this.links.filter(l => l.from === tnode.id || l.to === tnode.id)
|
|
|
- for (let l of foundLinks) {
|
|
|
- const fromNode = this.nodes.find(n => n.id === l.from)
|
|
|
- const toNode = this.nodes.find(n => n.id === l.to)
|
|
|
-
|
|
|
- let {cx: x1, cy: y1} = fromNode.node.output[0]
|
|
|
- let {cx: x2, cy: y2} = toNode.node.input[l.in]
|
|
|
-
|
|
|
- x1 += fromNode.node.movePos.x
|
|
|
- y1 += fromNode.node.movePos.y
|
|
|
-
|
|
|
- x2 += toNode.node.movePos.x
|
|
|
- y2 += toNode.node.movePos.y
|
|
|
-
|
|
|
- l.link.d = `M${x1},${y1} C${x1 + 50},${y1} ${x2 - 50},${y2} ${x2},${y2}`
|
|
|
- }
|
|
|
- })
|
|
|
- }, */
|
|
|
-
|
|
|
- // panStart
|
|
|
- dragStart (e) {
|
|
|
- console.log(e.target)
|
|
|
- if (e.target !== this.$refs.transformer) return
|
|
|
- document.addEventListener('mousemove', this.drag)
|
|
|
- document.addEventListener('mouseup', this.dragStop)
|
|
|
+ document.addEventListener('mousemove', drag)
|
|
|
+ document.addEventListener('mouseup', drop)
|
|
|
},
|
|
|
- drag (e) {
|
|
|
- this.nodeData.pan.x += e.movementX
|
|
|
- this.nodeData.pan.y += e.movementY
|
|
|
+ createSVGPoint (x, y) {
|
|
|
+ const p = this.$refs.svg.createSVGPoint()
|
|
|
+ p.x = x; p.y = y
|
|
|
+ return p
|
|
|
},
|
|
|
- dragStop (e) {
|
|
|
- document.removeEventListener('mousemove', this.drag)
|
|
|
- document.removeEventListener('mouseup', this.dragStop)
|
|
|
- },
|
|
|
- wheel (e) {
|
|
|
- var oX = e.clientX
|
|
|
- var oY = e.clientY
|
|
|
- const z = this.nodeData.zoom - (e.deltaY * 0.001 * this.nodeData.zoom)
|
|
|
-
|
|
|
- var curX = this.nodeData.pan.x
|
|
|
- var curY = this.nodeData.pan.y
|
|
|
- var scaleD = z / this.nodeData.zoom // delta
|
|
|
-
|
|
|
- var nx = scaleD * (curX - oX) + oX
|
|
|
- var ny = scaleD * (curY - oY) + oY
|
|
|
-
|
|
|
- this.nodeData.pan.x = nx
|
|
|
- this.nodeData.pan.y = ny
|
|
|
- this.nodeData.zoom = z
|
|
|
+ transformedPoint (x, y, abs) {
|
|
|
+ const svgRect = this.$el.getBoundingClientRect()
|
|
|
+ if (!abs) {
|
|
|
+ x -= svgRect.x
|
|
|
+ y -= svgRect.y
|
|
|
+ }
|
|
|
+ return this.$refs.panzoom.transformedPoint(this.createSVGPoint(x, y))
|
|
|
}
|
|
|
+ // helper
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -207,28 +182,5 @@ svg.view {
|
|
|
border: solid 1px #F00;
|
|
|
position:relative;
|
|
|
}
|
|
|
-.transformer {
|
|
|
- stroke: black;
|
|
|
- stroke-width: 1;
|
|
|
- fill:transparent;
|
|
|
-
|
|
|
-}
|
|
|
-.connection {
|
|
|
- cursor:pointer;
|
|
|
-}
|
|
|
-.connection .area {
|
|
|
- stroke-width:20;
|
|
|
- stroke: transparent;
|
|
|
- fill:none;
|
|
|
-}
|
|
|
-.connection .visible{
|
|
|
- stroke: rgba(0,0,0,0.5);
|
|
|
- stroke-width:5;
|
|
|
- stroke-linecap:round;
|
|
|
- fill: transparent;
|
|
|
-}
|
|
|
-.connection:hover .visible {
|
|
|
- stroke: #F00;
|
|
|
-}
|
|
|
|
|
|
</style>
|