Skip to content

Instantly share code, notes, and snippets.

@enjalot
Last active August 29, 2015 14:16
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 enjalot/2e3ccdfa5d8d285b833d to your computer and use it in GitHub Desktop.
Save enjalot/2e3ccdfa5d8d285b833d 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":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/Zi8r6bS.png","ajax-caching":true}
//trying to recreate the effect from here:
//www.themaninblue.com/experiment/Blobular/
var a = { x: tributary.sw/2, y: 303, r: 249 };
var b = { x: tributary.sw - 120, y: 90, r: 43 };
var join = { r: 173 };
var color = "#1fea00"
var originDistance = a.r - b.r;
function renderBlobs() {
var data = [a,b];
var svg = d3.select("svg");
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 })
renderGoo(a, b)
})
// Add the original circles
var blobs = svg.selectAll("circle.blob")
.data(data)
.enter()
.append("circle")
.classed("blob", true)
.call(drag)
/*
.on("mousedown", function(d) { d.drag = true; })
.on("mouseup", function(d) { d.drag = false; })
.on("mousemove", function(d) {
if(d.drag) {
var m = d3.mouse(this);
d.x = m[0];
d.y = m[1];
d3.select(this)
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) {return d.y })
renderGoo(a, b)
}
});
*/
// Update the circles
blobs.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 "red"; });
}
function renderGoo(a, b, add) {
var svg = d3.select("svg");
//a.area = Math.PI * Math.pow(a.r, 2);
//b.area = Math.PI * Math.pow(b.r, 2);
//var afterCircleArea = a.area - b.area;
var distance = calculateDistance(a,b);
var distanceDiff = distance - originDistance;
if(distanceDiff < 1) { distanceDiff = 1 }
var dontdraw = false;
if(distance > 2*join.r + a.r + b.r) {
dontdraw = true;
}
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);
console.log(a);
console.log("Distance: " + distance);
console.log("DistanceDiff: " + distanceDiff);
console.log("triangleA: " + triangleA);
console.log("triangleB: " + triangleB);
console.log("triangleC: " + triangleC);
console.log("triangleP: " + triangleP);
console.log("triangleArea: " + triangleArea);
console.log("triangleH: " + triangleH);
console.log("triangleD: " + triangleD);
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;
console.log(lavaPathD);
if(!dontdraw) {
if(add) {
var lavaPath = svg.append("path")
.classed("lava", true)
.attr("transform", function() {
var translate = "translate(" + [a.x, a.y] + ")";
var rotate = "rotate(" + [angle, 0, 0] + ")";
return translate + rotate;
})
.style("fill", "none")
.style("stroke", color)
.style("fill", color)
.style("stroke-linecap", "round")
.style("stroke-width", 17)
lavaPath.attr("d", lavaPathD)
} else {
svg.selectAll("path.lava")
.attr("transform", function() {
var translate = "translate(" + [a.x, a.y] + ")";
var rotate = "rotate(" + [angle, 0, 0] + ")";
return translate + rotate;
})
.attr("d", lavaPathD);
}
}
}
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));
};
renderGoo(a, b, true);
renderBlobs();
#display {
background-color: #001b3d;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment