Skip to content

Instantly share code, notes, and snippets.

@roundrobin
Created August 4, 2012 23:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roundrobin/3260634 to your computer and use it in GitHub Desktop.
Save roundrobin/3260634 to your computer and use it in GitHub Desktop.
just another inlet to tributary
var keys = jwerty.KEYS.keys;
//get a list of the keys we can represent
var keyskeys = Object.keys(keys);
//have event listeners on all of them (the keys of the piano)
var funcs = d3.dispatch.apply(null, keyskeys); //this is mandatory
var dial1, dial2, dial3;
var time = new Date(), dt;
function randomXToY(minVal,maxVal,floatVal)
{
var randVal = minVal+(Math.random()*(maxVal-minVal));
return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
}
tributary.init = function(g) {
time = new Date();
dial1 = Disc()
.cx(150)
.cy(200)
.bpm(120)
.hitpoints(4)
.arc_color("#B9B9B9");
dial2 = Disc()
.cx(460)
.cy(200)
.bpm(120)
.hitpoints(8)
.arc_color("#B9B9B9");
dial3 = Disc()
.cx(759)
.cy(200)
.bpm(120)
.hitpoints(16)
.ininr(42)
.inr(77)
.outr(140)
.arcw(0.25872)
.fill("#ffffff")
.arc_color("#B9B9B9")
.active_fill("#0CC74F")
.stroke("#000000")
.arc_color("#A7A7A7")
.hit_color("#ff0000")
.marker_color("#000000")
.stroke_width(3)
.ring_width(30)
.hit_radius(20)
.hit_font_size(40);
var d1g = g.append("g");
var d2g = g.append("g");
var d3g = g.append("g");
dial1(d1g);
dial2(d2g);
dial3(d3g);
///////// viz code
var n = 60;
var nx = 10;
var xx = 13;
var yy = 417;
var xsp = 98;
var ysp = 60;
var squarew = 33;
var strokew = 4;
var minrad = .3;
var maxrad = 4;
var ci = 0;
var sci = 0;
var colors = ["#FF5353", "#08B0CF", "#FF53EA", "#3DDA63"];
var highlight_color = "#ff0000";
var stroke_colors = ["#000000", "#7A7A7A", "#999999", "#FFFFFF"];
var range = d3.range(n);
var data = [];
range.forEach(function(d,i) {
d = {
ind: i,
w: squarew
};
data.push(d);
})
var defs = g.append('defs');
var gradient = defs.append('linearGradient')
.attr('id','g320')
.attr('gradientUnits','userSpaceOnUse')
.attr('x1','0%')
.attr('x2','0%')
.attr('y1','0%')
.attr('y2',141)
var stop1 = gradient.append('stop')
.attr('stop-color',"#68B4CF")
.attr('offset','0')
.attr('id','stop1');
var stop2 = gradient.append('stop')
.attr('stop-color',"#4DE3AC")
.attr('offset','1')
.attr('id','stop2');
var text = {"message":"Hello","amplitude":1.216,"segments":26.03,"change1":0,"functionName":"Sinus", "change2" : 16.3,"a":1,"b":1,"c":0};
var boolFlag = false;
var circleBoundaries = d3.scale.linear().domain([0, 1489]).range([0.79, 20]);
var r = 195 / 2,
data = d3.range(361).map(function(i) {
var returnedValue = 1;
var val = circleBoundaries(returnedValue);
return val;
});
var svg = g
.data([data])
.append("g")
.attr("transform", "translate(" + 75 + "," + 234 + ")");
var path = svg.append("path")
.attr("class", "area")
.attr('fill',"black")
.attr('transform',"translate(300,200)")
.attr("d", d3.svg.area.radial()
.innerRadius(function(d,i) {
return 50;
})
.outerRadius(function(d) {
return r * d;
})
.angle(function(d, i) { return i / 180 * Math.PI; }))
var circles = g.selectAll("rect.viz")
.data(data);
//shrink and grow radius within random bounds
funcs.on("s", function(dur) {
g.selectAll("rect.viz")
.transition()
.duration(dur)
.attr("transform",function(d,i){
d.r *= randomXToY(0.5, 0.8);
if(d.r < minrad) d.r = minrad;
d.scale = "scale(" + d.r + ")";
return d.translate + d.scale;
//return d.scale + d.translate;
})
})
/*
g.append("text")
.classed("display", true)
.attr("transform", "translate(" + [100, 425] + ")")
.style("font-size", 100)
.text("A")
//basic action for any keypress is to display that key
keyskeys.forEach(function(k) {
funcs.on(k, function() {
g.select("text.display").text(k);
})
})*/
/*
funcs.on("e", function() {
g.select("text").text("E");
})
funcs.on("n", function() {
g.select("text").text("N");
})
funcs.on("j", function() {
g.select("text").text("J");
})*/
};
tributary.run = function(g,t) {
old_time = time;
time = new Date();
dt = time - old_time;
dial1.spin(dt);
dial2.spin(dt);
dial3.spin(dt);
};
tributary.trace = false;
//we will tell the discs what keys are pressed through these events
//var keyvent = d3.dispatch("down", "up");
var keyvent = new Backbone.Model();
//util function to look up human readable key from keycode
var findIt = function( targetObj, target ){
for(key in targetObj){
if(targetObj.hasOwnProperty(key)){
if(targetObj[key] === target){
return key;
}
}
}
return null;
}
d3.select(window).on("keydown", keydown);
d3.select(window).on("keyup", keyup);
function keydown() {
var evt = d3.event;
var key = findIt(keys, evt.keyCode);
if(key !== null) {
//keyvent.down(key);
keyvent.trigger("down", key);
}
}
function keyup() {
var evt = d3.event;
var key = findIt(keys, evt.keyCode);
if(key !== null) {
console.log("up", key);
//keyvent.up(key);
keyvent.trigger("up", key);
}
}
function Disc() {
//rotating disc "sequencer"
var bpm = 120;
//beats per revolution
var bpr = 4;
//120 bpm with 4 bpr means 2 seconds per revolution
var hitpoints = 4;
var events = d3.dispatch("hit");
//position
var cx = 150;
var cy = 150;
//radii
var ininr = 42;
var inr = 77;
var outr = 140;
var midr;
var arcw = 0.25872;
//skin
var fill = "#ffffff";
var active_fill = "#0CC74F";
var stroke = "#000000";
var arc_color = "#0AE5F8";
var hit_color = "#ff0000";
var marker_color = "#000000";
var colors = d3.scale.category10();
var stroke_width = 3;
var ring_width = 30;
var hit_radius = 20;
var hit_font_size = 40;
//current angle
var Θ = 0.1;
//cycle angle, and old cycle angle for calculating hits
var Θr = 0.1
var oΘr = 0.1;
//keep track of the time
var t, ot;
//the group this disc belongs to
var g;
var mspb;
var arc = d3.svg.arc();
var hitters = [];
var active = false;
var active_key = null;
var disc = function(group) {
g = group;
//[ms]/[b] = 1 [m] / x [b] * [m] * 60 [s]/[m] * 1000[ms]/[s]
//so replace x with 120 to get ms/b for 120bpm
mspb = 60 * 1000 / bpm;
midr = inr + (outr - inr)/2;
arc.innerRadius(inr*1.04)
.outerRadius(outr*0.98);
for(var i = 0; i < hitpoints; i++) {
hitters.push({});
}
//var hitdata = pie(hitters);
//console.log(hitdata)
hitters.forEach(function(d,i) {
var w = 2*Math.PI/hitpoints;//Math.abs(d.endAngle - d.startAngle) / 2;
var th = i * w;
//var center = d.startAngle;// + w/2;
var center = th;
//console.log(center, w);
//setup arcs
d.startingAngle = center - w*arcw;
d.endingAngle = center + w*arcw;
d.centeringAngle = center;
//hit angle (when angle passes this point, we hit)
d.hit = th;
d.w = w;
d.index = i;
//d.hit = (hitpoints - i - 1) * 2*Math.PI/hitpoints;
//d.index = hitpoints - i - 1;
d.key = "";
})
var mousedown = function() {
active = true;
g.select(".inner")
.style("fill", active_fill)
};
var mouseup = function() {
active = false;
g.select(".inner")
.transition()
.duration(100)
.style("fill", fill)
};
//we need to know if a key is being held down for recording
keyvent.on("down", function(key) {
active_key = key;
});
keyvent.on("up", function(key) {
//set whatever cycle we are on to the active key
hitters.forEach(function(d, i) {
//see if we made a hit for each one of our hits;
//console.log(i, oΘr, d.hit, Θr)
if(Θr >= d.hit && Θr <= d.hit + d.w) {
//console.log("HIT!", d.index);
events.hit(d.index);
//console.log("or", oΘr, Θr, d.index, "hit", dhit);
} else if(d.index === 0 && oΘr > Θr) {
//console.log("cycle HIT!", d.index);
events.hit(d.index);
//console.log("or", oΘr, Θr, d.index, "hit", dhit);
}
});
active_key = null;
});
g.attr("pointer-events", "all")
.on("mousedown", mousedown)
.on("touchstart", mousedown)
.on("mouseup", mouseup)
.on("touchend", mouseup)
g.append("circle")
.classed("ring", true)
.attr("r", midr)
.attr("cx", cx)
.attr("cy", cy)
.style("fill", fill)
.style("stroke", stroke)
.style("stroke-width", ring_width);
g.append("circle")
.classed("inner", true)
.attr("r", ininr)
.attr("cx", cx)
.attr("cy", cy)
.style("fill", fill)
.style("stroke", stroke)
.style("stroke-width", stroke_width);
g.selectAll("path.hits")
.data(hitters)
.enter()
.append("path")
.classed("hits", true)
.attr("transform", "translate(" + [cx,cy] + ")")
//.attr("d", arc)
.style("fill", function(d, i) {
//return colors(i);
return arc_color;
})
g.selectAll("circle.hits")
.data(hitters)
.enter()
.append("circle")
.classed("hits", true)
.style("fill", "#FFFFFF")
.style("stroke", "#000000")
.style("stroke-width", 2)
.attr("r", hit_radius)
g.selectAll("text.hits")
.data(hitters)
.enter()
.append("text")
.classed("hits", true)
.style("fill", "#000000")
.style("font-size", hit_font_size)
.attr("alignment-baseline", "central")
.attr("text-anchor", "middle")
/*
g.selectAll("text.numbers")
.data(hitdata)
.enter()
.append("text")
.classed("numbers", true)
.text(function(d,i) {
return d.index;
})
.style("fill", "#ff0000")
*/
g.append("circle")
.classed("mark", true)
.style("fill", marker_color)
.attr("r", 5)
};
disc.update = function() {
//update representations
var th = -Math.PI/2;
g.select("circle.mark")
.attr("cx", cx + ininr * Math.cos(-Θ - th*2))
.attr("cy", cy + ininr * Math.sin(-Θ - th*2))
g.selectAll("path.hits")
.attr("d", arc)
g.selectAll("text.hits")
.attr("transform", function(d,i) {
var x = cx + midr * Math.cos(d.centerAngle + th);
var y = cy + midr * Math.sin(d.centerAngle + th);
return "translate(" + [x,y] + ")";
})
.text(function(d) {
return d.key;
})
g.selectAll("circle.hits")
.attr("transform", function(d,i) {
var x = cx + midr * Math.cos(d.centerAngle + th);
var y = cy + midr * Math.sin(d.centerAngle + th);
return "translate(" + [x,y] + ")";
})
/*g.selectAll("text.numbers")
.attr("transform", function(d,i) {
var x = cx + midr * Math.cos(d.centerAngle + th);
var y = cy + midr * Math.sin(d.centerAngle + th);
return "translate(" + [x,y] + ")";
})*/
}
disc.spin = function(dt) {
//ot = t;
//t += dt;
oΘ = Θ;
//spin the disc by dt (in miliseconds)
//we want to make bpr revolutions per beat
//so we need to calculate how much to rotate each update
Θ += (2*Math.PI) * dt / mspb / bpr;
//see where in the cycle we are
oΘr = Θr;
Θr = Math.abs(Θ + Math.PI/2) % (2*Math.PI);
//console.log(Θr,oΘr);
//console.log("or", oΘr, Θr);
hitters.forEach(function(d, i) {
var th = -Θ -Math.PI/2
d.startAngle = th + d.startingAngle;
d.endAngle = th + d.endingAngle;
d.centerAngle = th + d.centeringAngle;
//see if we made a hit for each one of our hits;
//console.log(i, oΘr, d.hit, Θr)
if(d.hit > oΘr && d.hit <= Θr) {
//console.log("HIT!", d.index);
events.hit(d.index);
//console.log("or", oΘr, Θr, d.index, "hit", dhit);
} else if(d.index === 0 && oΘr > Θr) {
//console.log("cycle HIT!", d.index);
events.hit(d.index);
//console.log("or", oΘr, Θr, d.index, "hit", dhit);
}
});
events.on("hit", function(hit) {
//console.log("hit", hit, hitkeys[hit]);
if(active) {
//listen on keyboard events (if active) and assign
//letters to whatever hits happen
//also have erase
if(active_key === "space") {
hitters[hit].key = "";
}
else if(active_key !== null) {
//record a key if pressed
//hitkeys[hit] = active_key;
//console.log("save", hit, active_key);
hitters[hit].key = active_key;
}
}
if(hitters[hit].key !== "") {
//console.log(hit, hitters[hit].key)
funcs[hitters[hit].key](mspb);
}
g.selectAll("path.hits")
.filter(function(d) {
return d.index === hit;
})
.style("fill", hit_color)
.transition()
.duration(100)
.style("fill", arc_color);
/*
g.selectAll("circle.hits")
.filter(function(d) {
return d.index === hit;
})
.style("fill", hit_color)
.transition()
.duration(100)
.style("fill", fill);
*/
})
disc.update();
};
disc.hitpoints = function(value) {
if (!arguments.length) { return hitpoints; }
hitpoints = value;
return disc;
};
disc.bpm = function(value) {
if (!arguments.length) { return bpm; }
bpm = value;
return disc;
};
disc.cx = function(value) {
if (!arguments.length) { return cx; }
cx = value;
return disc;
};
disc.cy = function(value) {
if (!arguments.length) { return cy; }
cy = value;
return disc;
};
//radii
disc.ininr = function(value) {
if (!arguments.length) { return ininr; }
ininr = value;
return disc;
};
disc.inr = function(value) {
if (!arguments.length) { return inr; }
inr = value;
return disc;
};
disc.outr = function(value) {
if (!arguments.length) { return outr; }
outr = value;
return disc;
};
disc.arcw = function(value) {
if (!arguments.length) { return arcw; }
arcw = value;
return disc;
};
//skin
disc.fill = function(value) {
if (!arguments.length) { return fill; }
fill = value;
return disc;
};
disc.active_fill = function(value) {
if (!arguments.length) { return active_fill; }
active_fill = value;
return disc;
};
disc.stroke = function(value) {
if (!arguments.length) { return stroke; }
stroke = value;
return disc;
};
disc.arc_color = function(value) {
if (!arguments.length) { return arc_color; }
arc_color = value;
return disc;
};
disc.hit_color = function(value) {
if (!arguments.length) { return hit_color; }
hit_color = value;
return disc;
};
disc.marker_color = function(value) {
if (!arguments.length) { return marker_color; }
marker_color = value;
return disc;
};
disc.stroke_width = function(value) {
if (!arguments.length) { return stroke_width; }
stroke_width = value;
return disc;
};
disc.ring_width = function(value) {
if (!arguments.length) { return ring_width; }
ring_width = value;
return disc;
};
disc.hit_radius = function(value) {
if (!arguments.length) { return hit_radius; }
hit_radius = value;
return disc;
};
disc.hit_font_size = function(value) {
if (!arguments.length) { return hit_font_size; }
hit_font_size = value;
return disc;
};
return disc;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment