| 
					
				 | 
			
			
				@@ -0,0 +1,234 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  <div class="flow-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <svg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ref="svg" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      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" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          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 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <flow-node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ref="nodes" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          v-for="(n,i) of nodeData.nodes" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :key="'node' + n.id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :id="n.id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :value="n" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :transform="nodeTransform(i)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          @nodePointerDown.prevent="nodeDragStart($event,i)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          @socketPointerDown.prevent="nodeDragStart($event,i)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </g> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </svg> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    {{ nodeData }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <div v-for="(n,i) of nodeData.nodes"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <input type="text" v-model="n.label"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nodeData from './nodedata' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import FlowNode from './flownode' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  name: 'FlowManager', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  components: {FlowNode}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  props: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    'width': {type: String, default: '800px'}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    'height': {type: String, default: '600px'} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  data () { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      nodeData: nodeData // shared? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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})` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    nodeDragStart (e, i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const mouseup = (e) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        document.removeEventListener('mousemove', mousemove) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        document.removeEventListener('mouseup', mouseup) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    drag (e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.nodeData.pan.x += e.movementX 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.nodeData.pan.y += e.movementY 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<style> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.flow-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display:flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex-flow:column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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> 
			 |