Skip to content

Instantly share code, notes, and snippets.

@eeropic
Last active October 22, 2017 09:52
Show Gist options
  • Select an option

  • Save eeropic/db8a0bb3cf003574d1ebe6f6b69c3ec3 to your computer and use it in GitHub Desktop.

Select an option

Save eeropic/db8a0bb3cf003574d1ebe6f6b69c3ec3 to your computer and use it in GitHub Desktop.
node editor hack in progress
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