Skip to content

Instantly share code, notes, and snippets.

@panamantis
Created May 2, 2013 11:39
Show Gist options
  • Save panamantis/5501666 to your computer and use it in GitHub Desktop.
Save panamantis/5501666 to your computer and use it in GitHub Desktop.
circle line
{"editor_editor":{"coffee":false,"vim":false,"emacs":false,"width":528,"height":680,"hide":false},"description":"circle line","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},"_.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}
//trying to recreate the effect from here:
//www.themaninblue.com/experiment/Blobular/
var a = {
x: 250,
y: 300,
r: 226,
};
var b = {
x: 770,
y: 300,
r: 100
};
var join = {
r: 119,
};
var originDistance = a.r - b.r;
a.area = Math.PI * Math.pow(a.r, 2);
b.area = Math.PI * Math.pow(b.r, 2);
var afterCircleArea = a.area - b.area;
a.rmax = a.r;
a.rmin = Math.sqrt(afterCircleArea / Math.PI);
var distance = calculateDistance(a,b);
//var distanceDiff = distance - a.rmax + b.r;
var distanceDiff = distance - originDistance;
//var distanceDiff = originDistance;
if(distanceDiff < 1) { distanceDiff = 1 }
var dontdraw = false;
if(distance > 2*join.r + a.r + b.r) {
console.log("MAY DAY")
dontdraw = true;
}
var angle = calculateAngle(a,b);
b.h = 0;
b.k = 0 - a.rmax + b.r - distanceDiff;
var startY = 0 - a.rmin - join.r * 2 - b.r;
var finalY = 0 - a.rmax + b.r - 1;
var differenceY = startY - finalY;
//console.log("start final", startY, finalY, differenceY)
var currDifferenceY = b.k - finalY;
var differencePercentage = currDifferenceY / differenceY;
//console.log("diff per", differencePercentage)
//var differencePercentage = 1.38632;
//join.r = join.rmax - (join.rmax - join.rmin) * differencePercentage;
//a.r = a.rmax - (a.rmax - a.rmin) * differencePercentage;
//console.log(b.k, join.r)
var triangleA = a.r + join.r; // Side a
var triangleB = b.r + join.r; // Side b
var triangleC = Math.abs(b.k - 0); // 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;
//console.log("crossover?", join.x - join.r, b.k, join.y, b.k < join.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(join)
var data = [a,b];
var cs = d3.scale.category10();
var svg = d3.select("svg");
svg.selectAll("circle.blob")
.data(data)
.enter()
.append("circle")
.classed("blob", true)
.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 cs(i); })
.style("fill-opacity", 0.5)
.style("stroke", function(d,i) { return cs(i); })
if(!dontdraw) {
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", "#000")
.style("stroke-width", 10)
// lavaPath.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));
};
/*
var o = {
x: 150,
y: 0,
r: 20
};
var originDistance = calculateDistance(a,o);
b.r = a.r - originDistance;
*/
//debugging stuff:
coord1.r = 10;
coord2.r = 10;
//join.r = 650;
//show helper things
var aint = {
x: a.intersectX,
y: a.intersectY,
r: 20
};
var ak = { //a center
x: a.h,
y: a.k,
r: 5
};
var bint = {
x: b.intersectX,
y: b.intersectY,
r: 20
};
var bk = { // center
x: b.h,
y: b.k,
r: 5
};
// Add line
var liner={
x1:a.x,
y1:a.y,
x2:b.x,
y2:b.y
};
var linerr=[liner];
rect_w=w;
radius=rect_w+90;//radius=220;
r1=a.r;
console.log("Given: "+ "w: "+w+", r1: "+r1+" at ("+a.x+","+a.y+")");
// Control point P1
x1=w;
y1=Math.sqrt(Math.pow(r1,2)-Math.pow(w,2));
// reference translate
y1=-1*y1;
console.log("Place P1 at: ("+x1+","+y1+")");
var p1 = { // center
x: x1,
y: y1,
r: 3
};
// Circle start POINT 2
x2=Math.sqrt(Math.pow(radius,2)-Math.pow(Math.pow(radius,2)/(2*a.r),2));
y2=a.r-Math.pow(radius,2)/(2*a.r);
// reference translate
y2=-1*y2;
var p2 = { // center
x: x2,
y: y2,
r: 10
};
console.log("Place P2 at: ("+x2+","+y2+")");
// Line tangent end POINT 3
x3=x1;
d_xy=Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2));
console.log("Distance x1 to x2: "+d_xy+" dx "+d_x+" dy "+d_y);
// p3 reference
y3=y1-d_xy;
var p3 = { // center
x: x3,
y: y3,
r: 10
};
console.log("Place P3 at: ("+x3+","+y3+")");
var helpers = [ bint,bk,aint,ak,p1,p2,p3];
// var helpers = [p1];
var hcs = d3.scale.category20b();
lavaPathE="M "+x2+" "+y2+" Q "+x1+" "+y1+" "+x3+" "+y3; // pt move start
m1=-x1;
n1=y1;
m2=-x2;
n2=y2;
m3=-x3;
n3=y3;
lavaPathE+="M "+m2+" "+n2+" Q "+m1+" "+n1+" "+m3+" "+n3; // pt move start
console.log("So lava: "+lavaPathE);
// lavapathE += "Q "+x2+" "+x2+" "; // pt control
// 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;
lavaPath_stoke=10;
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", "#000")
.style("stroke-width", lavaPath_stoke)
lavaPath.attr("d", lavaPathE)
svg.selectAll("line.help")
.data(linerr)
//.data([{r:100}])
.enter()
.append("line")
// .attr("x1", a.x)
// .attr("y1", a.y)
// .attr("x2", b.x)
// .attr("y2", b.y)
.attr("x1", function(d) { return d.x1 })
.attr("y1", function(d) { return d.y1 })
.attr("x2", function(d) { return d.x2 })
.attr("y2", function(d) { return d.y2 })
.style("stroke", function(d,i) { return 1; })
// .style("stroke-width", function(d,i) { return 100; }) ;
.style("stroke-width", function(d,i) { return rect_w*2+lavaPath_stoke; }) ;
// help circles
svg.selectAll("circle.help")
.data(helpers)
.enter()
.append("circle")
.classed("help", true)
.attr("transform", function() {
var translate = "translate(" + [a.x, a.y] + ")";
var rotate = "rotate(" + [angle, 0, 0] + ")";
return translate + rotate;
})
.attr("cx", function(d) { return d.x })
.attr("cy", function(d) {return d.y })
.attr("r", function(d) { return Math.abs(d.r) })
.style("fill", function(d,i) { return hcs(i); })
.style("fill-opacity", 0.5)
.style("stroke", function(d,i) { return hcs(i); })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment