|
@@ -0,0 +1,190 @@
|
|
|
|
+<template>
|
|
|
|
+ <div id="app">
|
|
|
|
+ <h3>An app with svg</h3>
|
|
|
|
+ <input
|
|
|
|
+ type="text"
|
|
|
|
+ v-model="nodes[nodes.length-1].label">
|
|
|
|
+ <s-svg
|
|
|
|
+ width="100%"
|
|
|
|
+ height="100%">
|
|
|
|
+
|
|
|
|
+ <g class="connection" v-for="l of links">
|
|
|
|
+ <path
|
|
|
|
+ class="area"
|
|
|
|
+ :d="l.link.d"
|
|
|
|
+ />
|
|
|
|
+ <path
|
|
|
|
+ class="visible"
|
|
|
|
+ :d="l.link.d"
|
|
|
|
+ />
|
|
|
|
+ </g>
|
|
|
|
+
|
|
|
|
+ <s-node
|
|
|
|
+ v-model="n.node"
|
|
|
|
+ v-for="(n,i) of nodes"
|
|
|
|
+ :inputs="n.inputs"
|
|
|
|
+ :label="n.label"
|
|
|
|
+ :key="n.id"
|
|
|
|
+ :id="n.id"
|
|
|
|
+ @nodeDragStart="nodeDragStart(i,$event)"
|
|
|
|
+ @nodeDrag="nodeDrag(i,$event)"
|
|
|
|
+ />
|
|
|
|
+
|
|
|
|
+ </s-svg>
|
|
|
|
+
|
|
|
|
+ <div v-for="n of nodes">{{ n }}</div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import AppSvg from '@/components/svgcontainer'
|
|
|
|
+import AppCircle from '@/components/circle'
|
|
|
|
+import AppNode from '@/components/node'
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ name: 'App',
|
|
|
|
+ components: {
|
|
|
|
+ 's-svg': AppSvg,
|
|
|
|
+ 's-circle': AppCircle,
|
|
|
|
+ 's-node': AppNode
|
|
|
|
+ },
|
|
|
|
+ data () {
|
|
|
|
+ return {
|
|
|
|
+ // And retrieve as event
|
|
|
|
+ // We want X/Y position from the node to serialize
|
|
|
|
+ // we will comunicate to the server only the nodes and links
|
|
|
|
+ nodes: [
|
|
|
|
+ {id: '1', label: 'Input', inputs: 0, node: {}},
|
|
|
|
+ {id: '2', label: 'MatMul-2', inputs: 2, node: {}},
|
|
|
|
+ {id: '3', label: 'Weights-3', inputs: 0, node: {}},
|
|
|
|
+ {id: '4', label: 'Activation-4', inputs: 1, node: {}},
|
|
|
|
+ {id: '5', label: 'MatMul-5', inputs: 4, node: {}}
|
|
|
|
+ ],
|
|
|
|
+ links: [
|
|
|
|
+ {from: '1', to: '2', in: 1, link: {}},
|
|
|
|
+ {from: '3', to: '2', in: 0, link: {}},
|
|
|
|
+
|
|
|
|
+ {from: '2', to: '4', in: 0, link: {}},
|
|
|
|
+ {from: '4', to: '5', in: 1, link: {}}
|
|
|
|
+ // {from: '3', to: '4', in: 1, link: {}}
|
|
|
|
+ ]
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ nodes (nodes) {
|
|
|
|
+ console.log('Nodes:', nodes)
|
|
|
|
+ for (let node of nodes) {
|
|
|
|
+ console.log('Linking:', node.id)
|
|
|
|
+ // Links for node?
|
|
|
|
+ const foundLinks = this.links.filter(l => l.from === node.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}`
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ deep: true
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ 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(() => {
|
|
|
|
+ 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}`
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss">
|
|
|
|
+#app {
|
|
|
|
+ font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
|
|
|
+ -webkit-font-smoothing: antialiased;
|
|
|
|
+ -moz-osx-font-smoothing: grayscale;
|
|
|
|
+ text-align: center;
|
|
|
|
+ color: #2c3e50;
|
|
|
|
+ margin-top: 60px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#app svg {
|
|
|
|
+ position:fixed;
|
|
|
|
+ top:0;
|
|
|
|
+ right:0;
|
|
|
|
+ left:0;
|
|
|
|
+ bottom:0;
|
|
|
|
+ pointer-events:none;
|
|
|
|
+}
|
|
|
|
+#app svg > * {
|
|
|
|
+ pointer-events: initial;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+h1, h2 {
|
|
|
|
+ font-weight: normal;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ul {
|
|
|
|
+ list-style-type: none;
|
|
|
|
+ padding: 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+li {
|
|
|
|
+ display: inline-block;
|
|
|
|
+ margin: 0 10px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+a {
|
|
|
|
+ color: #42b983;
|
|
|
|
+}
|
|
|
|
+input {
|
|
|
|
+ display:block;
|
|
|
|
+}
|
|
|
|
+.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>
|