Skip to content

Instantly share code, notes, and snippets.

@enjalot
Last active August 29, 2015 14:16
Show Gist options
  • Save enjalot/90bed79b74aaa9b97c1a to your computer and use it in GitHub Desktop.
Save enjalot/90bed79b74aaa9b97c1a to your computer and use it in GitHub Desktop.
blobular droplets!!
{"editor_editor":{"coffee":false,"vim":true,"emacs":false,"width":528,"height":680,"hide":false},"description":"blobular droplets!!","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":true,"loop":true,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/PcrQGNa.gif","ajax-caching":true}
//trying to recreate the effect from here:
//www.themaninblue.com/experiment/Blobular/
var A = { x: tributary.sw/2, y: tributary.sh/2, r: 76, index: -1 };
var data = [A];
for(var i = 0; i < 10; i++ ) {
data.push({
x1: tributary.sw * Math.random(),
y1: tributary.sh * Math.random(),
x2: tributary.sw * Math.random(),
y2: tributary.sh * Math.random(),
r: 33,
index: i
});
}
var join = { r: 163 };
//"period", "pingpong"
tributary.__config__.set("loop_type", "pingpong")
var color = "#00ea00";
var circleColor = "#1470ad";
var strokeWidth = 20;
function renderGoo(a,b,add) {
var originDistance = a.r - b.r;
var distance = calculateDistance(a,b);
var distanceDiff = distance - originDistance;
if(distanceDiff < 1) { distanceDiff = 1 }
var angle = calculateAngle(a,b);
b.h = 0;
b.k = 0 - a.r + b.r - distanceDiff;
var triangleA = a.r + join.r; // Side a
var triangleB = b.r + join.r; // Side b
var triangleC = Math.abs(b.k); // Side c
var triangleP = (triangleA + triangleB + triangleC) / 2; // Triangle half perimeter
var triangleArea = Math.sqrt(triangleP * (triangleP - triangleA) * (triangleP - triangleB) * (triangleP - triangleC)); // Triangle area
if (triangleC >= triangleA)
{
var triangleH = 2 * triangleArea / triangleC; // Triangle height
var triangleD = Math.sqrt(Math.pow(triangleA, 2) - Math.pow(triangleH, 2)); // Big circle bisection of triangleC
}
else
{
var triangleH = 2 * triangleArea / triangleA; // Triangle height
var triangleD = Math.sqrt(Math.pow(triangleC, 2) - Math.pow(triangleH, 2)); // Small circle bisection of triangleA
}
a.tan = triangleH / triangleD;
a.angle = Math.atan(a.tan);
a.sin = Math.sin(a.angle);
a.intersectX = a.sin * a.r;
a.cos = Math.cos(a.angle);
a.intersectY = a.cos * a.r;
join.x = 0 + a.sin * (a.r + join.r);
join.y = 0 - a.cos * (a.r + join.r);
var coord1 = { x: -a.intersectX, y: -a.intersectY };
var coord2 = { x: a.intersectX, y: -a.intersectY }
b.tan = (b.k - join.y) / (b.h - join.x);
b.angle = Math.atan(b.tan);
b.intersectX = join.x - Math.cos(b.angle) * (join.r);
b.intersectY = join.y - Math.sin(b.angle) * (join.r);
var lavaPathD = "M " + coord1.x + " " + coord1.y + " A " + a.r + " " + a.r + " 0 1 0 " + coord2.x + " " + coord2.y;
if (join.x - join.r <= 0 && b.k < join.y)
{
var crossOverY = circleYFromX(join, 0);
lavaPathD += "A " + join.r + " " + join.r + " 0 0 1 0 " + (join.y + crossOverY);
lavaPathD += "m 0 -" + (crossOverY * 2);
}
lavaPathD += "A " + join.r + " " + join.r + " 0 0 1 " + b.intersectX + " " + b.intersectY;
var largeArcFlag = 1;
if (join.y < b.k)
{
largeArcFlag = 0;
}
lavaPathD += "a " + b.r + " " + b.r + " 0 " + largeArcFlag + " 0 " + (b.intersectX * -2) + " 0";
if (join.x - join.r <= 0 && b.k < join.y)
{
lavaPathD += "A " + join.r + " " + join.r + " 0 0 1 0 " + (join.y - crossOverY);
lavaPathD += "m 0 " + (crossOverY * 2);
}
lavaPathD += "A " + join.r + " " + join.r + " 0 0 1 " + coord1.x + " " + coord1.y;
lavaPathD += "A " + join.r + " " + join.r + " 0 0 1 " + coord1.x + " " + coord1.y;
var dontdraw = false;
if(distance > 2*join.r + a.r + b.r) {
dontdraw = true;
}
if(add) {
var lavaPath = svg.append("path")
.classed("lava", true)
.datum(b)
.attr("transform", function(d) {
var translate = "translate(" + [a.x, a.y] + ")";
var rotate = "rotate(" + [angle, 0, 0] + ")";
return translate + rotate;
})
.style("fill", color)
.style("stroke", color)
.style("stroke-linecap", "round")
.style("stroke-width", strokeWidth)
.style("display", function(d) { if(d === a) return "none" })
lavaPath.attr("d", lavaPathD)
} else {
var lava = svg.selectAll("path.lava")
.data(data, function(d) {return d.index === b.index })
.attr("transform", function(d) {
var translate = "translate(" + [a.x, a.y] + ")";
var rotate = "rotate(" + [angle, 0, 0] + ")";
return translate + rotate;
})
if(lavaPathD.indexOf("NaN") < 0)
lava.attr("d", lavaPathD);
lava.style("display", dontdraw ? "none" : "")
}
}
var svg = d3.select("svg");
for(var i = 0; i < data.length; i++) {
renderGoo(A, data[i], true);
}
var drag = d3.behavior.drag()
.on("drag", function(d) {
var evt = d3.event;
d.x += evt.dx;
d.y += evt.dy;
d3.select(this)
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) {return d.y })
for(var i = 1; i < data.length; i++) {
renderGoo(A, data[i]);
}
})
svg.selectAll("circle.blob")
.data(data)
.enter()
.append("circle")
.classed("blob", true)
.call(drag)
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) {return d.y })
.attr("r", function(d) { return d.r })
.style("fill", function(d,i) { return circleColor; })
.style("stroke", color)
.style("stroke-width", strokeWidth/2)
tributary.run = function(g,t) {
//console.log(t);
for(var i = 1; i < data.length; i++) {
b = data[i];
b.x = d3.interpolate(b.x1, b.x2)(t)
b.y = d3.interpolate(b.y1, b.y2)(t)
renderGoo(A, b);
d3.selectAll("circle.blob")
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) {return d.y })
}
}
function calculateDistance(origin, point) {
var xx = point.x - origin.x;
var yy = point.y - origin.y;
return Math.sqrt(xx*xx + yy*yy)
}
function calculateAngle(origin, point)
{
var tan = (point.y - origin.y) / (point.x - origin.x);
var angle = Math.atan(tan) / Math.PI * 180 + 90;
if (point.x < origin.x)
{
angle += 180;
}
return angle;
}
function circleYFromX (circle, x)
{
return Math.sqrt(Math.pow(circle.r, 2) - Math.pow(x - circle.x, 2));
};
#display {
background-color: #0074bc;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment