Last active
October 22, 2017 09:52
-
-
Save eeropic/db8a0bb3cf003574d1ebe6f6b69c3ec3 to your computer and use it in GitHub Desktop.
node editor hack in progress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| include('https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.3/svg.min.js'); | |
| include('http://eerojohannes.com/js/svg.draggable.min.js') | |
| include('http://eerojohannes.com/js/NexusUI.js') | |
| include('https://cdnjs.cloudflare.com/ajax/libs/tone/0.12.7/Tone.min.js') | |
| $('.right_panel').prepend('<div id="root"></div>') | |
| $('<style>svg text{user-select:none;cursor:initial}.node{cursor:move}.inlet, .outlet { fill: #eee; } .inlet:hover, .outlet:hover { fill: #bbb; cursor:pointer }</style>').appendTo('body'); | |
| const letWidth=10 | |
| const letHeight=20 | |
| const nodeWidth=120 | |
| const nodeHeight=80 | |
| const gridSize=10 | |
| const minTangent=20 | |
| var nodeCount=0 | |
| var connectionCount=0 | |
| var inletCount=0 | |
| var outletCount=0 | |
| var root = SVG('root').size(500, 500) | |
| root.attr('id','svgroot') | |
| root.addClass('root') | |
| root.mode='pointer' | |
| root.connecting=false | |
| root.draggedNode=null | |
| root.connectionSource=null | |
| root.connectionTarget=null | |
| root.currentConnections=null | |
| root.connections=[] | |
| root.nodes=[] | |
| root.getNode=function(id){ | |
| var result = this.nodes.filter(function(obj) { | |
| return obj.id == id; | |
| }); | |
| return result[0] | |
| } | |
| root.getNodeConnections=function(id){ | |
| var result = this.connections.filter(function(obj) { | |
| return obj.src.id == id || obj.tgt.id == id; | |
| }); | |
| return result | |
| } | |
| root.getPortConnections=function(id){ | |
| var result = this.connections.filter(function(obj) { | |
| return obj.src.port == id || obj.tgt.port == id; | |
| }); | |
| return result | |
| } | |
| root.routeConnections=function(connections,eventTarget,isTarget){ | |
| var self=this; | |
| for(var i=0;i<connections.length;i++){ | |
| var connection=connections[i] | |
| var index=self.connections.map(function(e){return e.id}).indexOf(connection.id); | |
| if(!isTarget){ | |
| self.connections[index].src.id=eventTarget.ownerSVGElement.id; | |
| self.connections[index].src.port=eventTarget.id | |
| } | |
| else{ | |
| self.connections[index].tgt.id=eventTarget.ownerSVGElement.id; | |
| self.connections[index].tgt.port=eventTarget.id | |
| } | |
| self.modifyConnectionSVG(connection) | |
| } | |
| } | |
| root.removeConnections=function(connections){ | |
| var self=this | |
| var removeConnections=[] | |
| //get connections to be removed and sort the indices in a list | |
| for(var j=0;j<connections.length;j++){ | |
| var connection=connections[j] | |
| var removeConnection=self.connections.map(function(e){return e.id}).indexOf(connection.id); | |
| removeConnections.push(removeConnection) | |
| } | |
| removeConnections.sort(function(a,b){return a-b;}) | |
| for(var i=removeConnections.length-1;i>=0;i--){ | |
| SVG.get(self.connections[removeConnections[i]].id).remove(); | |
| self.connections.splice(removeConnections[i],1) | |
| } | |
| } | |
| root.mousedown(function(e){ | |
| var self = this; | |
| var mX=e.x-$('.right_panel').offset().left | |
| var mY=e.y-$('.right_panel').offset().top | |
| var targets = { | |
| 'root':()=>{ | |
| self.mode='pointer' | |
| }, | |
| 'node':()=>{ | |
| console.log(root.getNode(e.target.ownerSVGElement.id)) | |
| self.mode='dragNode' | |
| self.hitNode=SVG.get(e.target.ownerSVGElement.id); | |
| self.hitNode.front(); | |
| self.hitPos={x:mX-self.hitNode.cx(),y:mY-self.hitNode.cy()} | |
| self.currentConnections=self.getNodeConnections(self.hitNode.node.id) | |
| console.log(root.connections) | |
| }, | |
| 'inlet':()=>{ | |
| var connections=self.getPortConnections(e.target.id) | |
| if(connections.length==0){ | |
| self.mode='connectFromInlet' | |
| root.fire('createConnection',{element:e.target}) | |
| } | |
| else{ | |
| if(!e.shiftKey){ | |
| self.currentConnections=connections | |
| self.mode='routeInlet' | |
| } | |
| if(e.shiftKey){ | |
| self.mode='connectFromInlet' | |
| root.fire('createConnection',{element:e.target}) | |
| } | |
| } | |
| }, | |
| 'outlet':()=>{ | |
| var connections=self.getPortConnections(e.target.id) | |
| if(connections.length==0){ | |
| self.mode='connectFromOutlet' | |
| root.fire('createConnection',{element:e.target}) | |
| } | |
| else{ | |
| if(!e.shiftKey){ | |
| self.currentConnections=connections | |
| self.mode='routeOutlet' | |
| } | |
| if(e.shiftKey){ | |
| self.mode='connectFromOutlet' | |
| root.fire('createConnection',{element:e.target}) | |
| } | |
| } | |
| } | |
| } | |
| return targets[e.target.getAttribute("class") || 'root']() | |
| }) | |
| root.mousemove(function(e){ | |
| var self=this; | |
| var mX=e.x-$('.right_panel').offset().left | |
| var mY=e.y-$('.right_panel').offset().top | |
| var modes = { | |
| 'pointer':()=>{ | |
| }, | |
| 'dragNode':()=>{ | |
| var fX=Math.floor((mX-self.hitPos.x)/gridSize)*gridSize | |
| var fY=Math.floor((mY-self.hitPos.y)/gridSize)*gridSize | |
| self.hitNode.center(fX,fY) | |
| if(self.currentConnections.length>0){ | |
| for(var i=0;i<self.currentConnections.length;i++){ | |
| var connection=self.currentConnections[i] | |
| if( connection.src.id == self.hitNode.node.id || | |
| connection.tgt.id == self.hitNode.node.id){ | |
| self.modifyConnectionSVG(connection) | |
| } | |
| } | |
| } | |
| }, | |
| 'connectFromInlet':()=>{ | |
| self.connectionSVG.attr('d', | |
| root.createConnectionStr( | |
| mX,mY, | |
| self.connectionSourcePort.attr('x')+self.connectionSource.attr('x'), | |
| self.connectionSourcePort.attr('y')+self.connectionSource.attr('y')+letHeight/2)) | |
| }, | |
| 'connectFromOutlet':()=>{ | |
| self.connectionSVG.attr('d', | |
| root.createConnectionStr( | |
| self.connectionSourcePort.attr('x')+self.connectionSource.attr('x'), | |
| self.connectionSourcePort.attr('y')+self.connectionSource.attr('y')+letHeight/2, | |
| mX,mY)) | |
| }, | |
| 'routeOutlet':()=>{ | |
| //console.log('routing outlet') | |
| for(var i=0;i<self.currentConnections.length;i++){ | |
| var connection=SVG.get(self.currentConnections[i].id) | |
| var connectionNode=SVG.get(self.currentConnections[i].tgt.id) | |
| var connectionPort=SVG.get(self.currentConnections[i].tgt.port) | |
| //console.log('cn x '+connectionNode.attr('x')) | |
| connection.attr('d', | |
| root.createConnectionStr( | |
| mX,mY, | |
| connectionNode.attr('x')+connectionPort.attr('x'), | |
| connectionNode.attr('y')+connectionPort.attr('y')+letHeight/2)) | |
| } | |
| }, | |
| 'routeInlet':()=>{ | |
| //console.log('routing inlet') | |
| for(var i=0;i<self.currentConnections.length;i++){ | |
| var connection=SVG.get(self.currentConnections[i].id) | |
| var connectionNode=SVG.get(self.currentConnections[i].src.id) | |
| var connectionPort=SVG.get(self.currentConnections[i].src.port) | |
| //console.log('cn x '+connectionNode.attr('x')) | |
| connection.attr('d', | |
| root.createConnectionStr( | |
| mX,mY, | |
| connectionNode.attr('x')+connectionPort.attr('x'), | |
| connectionNode.attr('y')+connectionPort.attr('y')+letHeight/2)) | |
| } | |
| } | |
| } | |
| return modes[this.mode || 'pointer']() | |
| }) | |
| root.mouseup(function(e){ | |
| var self=this; | |
| var targetClass=e.target.getAttribute("class"); | |
| var targetID=e.target.getAttribute("id") | |
| var modes = { | |
| 'pointer':()=>{ | |
| }, | |
| 'dragNode':()=>{ | |
| }, | |
| 'connectFromInlet':()=>{ | |
| if(targetClass=='outlet'){ | |
| var connection={ | |
| id:self.connectionSVG.node.id, | |
| src:{ | |
| id:e.target.ownerSVGElement.id, | |
| port:targetID | |
| }, | |
| tgt:{ | |
| id:self.connectionSource.node.id, | |
| port:self.connectionSourcePort | |
| } | |
| } | |
| self.connections.push(connection) | |
| self.modifyConnectionSVG(connection) | |
| } | |
| else{ | |
| self.connectionSVG.remove(); | |
| } | |
| }, | |
| 'connectFromOutlet':()=>{ | |
| if(targetClass=='inlet'){ | |
| var connection={ | |
| id:self.connectionSVG.node.id, | |
| src:{ | |
| id:self.connectionSource.node.id, | |
| port:self.connectionSourcePort | |
| }, | |
| tgt:{ | |
| id:e.target.ownerSVGElement.id, | |
| port:targetID | |
| } | |
| } | |
| var sourceNode=root.getNode(self.connectionSource.node.id) | |
| var targetNode=root.getNode(e.target.ownerSVGElement.id) | |
| if(sourceNode.tone!=null && targetNode.tone!=null){ | |
| sourceNode.tone.connect(targetNode.tone) | |
| } | |
| console.log(sourceNode,targetNode) | |
| self.connections.push(connection) | |
| self.modifyConnectionSVG(connection) | |
| } | |
| else{ | |
| self.connectionSVG.remove(); | |
| } | |
| }, | |
| 'routeOutlet':()=>{ | |
| if(targetClass=='outlet')self.routeConnections(self.currentConnections,e.target,false) | |
| else { | |
| self.removeConnections(self.currentConnections) | |
| } | |
| }, | |
| 'routeInlet':()=>{ | |
| if(targetClass=='inlet')self.routeConnections(self.currentConnections,e.target,true) | |
| else{ | |
| self.removeConnections(self.currentConnections) | |
| } | |
| } | |
| } | |
| modes[this.mode || 'pointer']() | |
| this.mode='pointer' | |
| this.currentConnections=null | |
| }) | |
| root.createConnectionStr=function(x1,y1,x2,y2){ | |
| var dist=(x2-x1)/3; | |
| var c=Math.max(minTangent,dist) | |
| //console.log('x1 '+x1+'x2 '+x2+'c '+c+' mint '+minTangent+' dist '+dist) | |
| var str='M'+x1+','+y1+' C'+(x1+c)+','+y1+' '+(x2-c)+','+y2+' '+x2+','+y2; | |
| //console.log(str) | |
| return str | |
| } | |
| root.modifyConnectionSVG=function(connection){ | |
| var obj=SVG.get(connection.id); | |
| var inlet=SVG.get(connection.tgt.port); | |
| var outlet=SVG.get(connection.src.port); | |
| var src=SVG.get(connection.src.id); | |
| var tgt=SVG.get(connection.tgt.id); | |
| var dist=( (tgt.x()+inlet.x())-(src.x()+outlet.x()) )/3; | |
| var c=Math.max(minTangent,dist) | |
| var str=obj.attr('d'); | |
| var data=str.split(" "); | |
| var srcX=src.x()+outlet.x()+letWidth | |
| var srcY=src.y()+outlet.y()+letHeight/2 | |
| var tgtX=tgt.x()+inlet.x() | |
| var tgtY=tgt.y()+inlet.y()+letHeight/2 | |
| data[0]='M'+srcX+','+srcY; | |
| data[1]='C'+(srcX+c)+','+srcY; | |
| data[2]=''+(tgtX-c)+','+tgtY; | |
| data[3]=''+tgtX+','+tgtY; | |
| var modified=data.join(" ") | |
| obj.attr('d',modified) | |
| } | |
| root.on('createConnection', function(e) { | |
| var elem=SVG.get(e.detail.element.id); | |
| var node=SVG.get(e.detail.element.ownerSVGElement.id) | |
| this.connectionSource=node; | |
| this.connectionSourcePort=elem; | |
| this.connectionSVG=root.path( | |
| root.createConnectionStr( | |
| node.attr('x')+elem.attr('x'),node.attr('y')+elem.attr('y'), | |
| node.attr('x')+elem.attr('x'),node.attr('y')+elem.attr('y')) | |
| ) | |
| this.connectionSVG.attr({'stroke':'#999','stroke-width':2,'fill':"none"}) | |
| this.connectionSVG.attr('id','connection'+connectionCount) | |
| this.connectionSVG.back(); | |
| connectionCount+=1 | |
| }) | |
| function Node(w,h,inlets,outlets,name){ | |
| var inlets = inlets || 0 | |
| var outlets = outlets || 0 | |
| var w = w || nodeWidth | |
| var h = h || nodeHeight | |
| var h = Math.max(h,(Math.max(inlets,outlets)+1)*letHeight) | |
| var nodeId='node'+nodeCount; | |
| var name = name || nodeId; | |
| this.node={id:nodeId,inlets:[],outlets:[]} | |
| this.nodeSVG = root.nested(); | |
| this.nodeSVG.attr('id',nodeId) | |
| var nodeSVG=this.nodeSVG; | |
| this.rect = nodeSVG.rect(w, h).radius(10).attr({fill:'#FEFEFE',stroke:'#777','fill-opacity':0.75}) | |
| this.rect.addClass('node') | |
| this.text = nodeSVG.text(name).move(letWidth*2,letWidth) | |
| for(var i=0;i<inlets;i++){ | |
| this.inlet=nodeSVG.rect(letWidth,letHeight) | |
| .radius(2).move(0,letHeight/2) | |
| .attr({y:letHeight*(i+0.5),fill:'#FEFEFE',stroke:'#777'}) | |
| var id='inlet'+inletCount; | |
| this.inlet.attr('id',id) | |
| this.inlet.addClass('inlet') | |
| this.node.inlets.push(id) | |
| inletCount+=1; | |
| } | |
| for(var i=0;i<outlets;i++){ | |
| this.outlet=nodeSVG.rect(letWidth,letHeight) | |
| .radius(2).move(w-letWidth,letHeight/2) | |
| .attr({y:letHeight*(i+0.5),fill:'#FEFEFE',stroke:'#777'}) | |
| var id='outlet'+outletCount; | |
| this.outlet.attr('id',id) | |
| this.outlet.addClass('outlet') | |
| this.node.outlets.push(id) | |
| outletCount+=1; | |
| } | |
| root.nodes.push(this.node) | |
| nodeCount+=1; | |
| } | |
| var test=new Node(); | |
| var dial=Nexus.Add.Dial('root',{position:[0,0],size:[40,40],id:'diali'}) | |
| // dial.element = SVG dial.parent = DIV | |
| var d=SVG.adopt(dial.element) | |
| d.move(5,30) | |
| test.nodeSVG.add(d) | |
| dial.on('change',function(v){ | |
| console.log(v) | |
| }) | |
| var masterNode=new Node(80,80,1,0,'Master'); | |
| var toneMaster=Tone.Master | |
| masterNode.node.tone=toneMaster; | |
| var oscNode=new Node(80,80,0,1,'Osc'); | |
| var osc=new Tone.Oscillator(440, "sine").start(); | |
| oscNode.node.tone=osc; | |
| var synth = new Tone.Synth().toMaster(); | |
| synth.triggerAttackRelease("C4", "8n"); | |
| var number = Nexus.Add.Number('root') | |
| /* | |
| new Tone.Master ( ) | |
| DEFAULTS | |
| {volume:0,mute:false} | |
| */ | |
| //number.link(dial2) | |
| //var test=new Node(80,80); | |
| //var test=new Node(80,120,8,4); | |
| //var test=new Node(80,20,4,4); | |
| //var test=new Node(80,80); | |
| //var test=new Node(80,80); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment