An example of drawing parametric curves in d3.js.
Last active
August 10, 2018 19:07
-
-
Save siordache/63c832377f7d25a0cf2ab5ae979a5cfa to your computer and use it in GitHub Desktop.
Parametric curves
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: apache-2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>Silly curves</title> | |
<link rel="stylesheet" href="plot.css"> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script src="plot.js"></script> | |
</head> | |
<body> | |
<div class="mainTable"> | |
<table> | |
<tr> | |
<td class="graphCell"><graph></graph></td> | |
<td> | |
<table class="sliderTable"> | |
<tr> | |
<td> | |
Transition duration | |
<div><input type="range" min="10" max="10000" value="500" class="slider" id="transitionDuration"></div> | |
</td> | |
</tr> | |
<tr> | |
<td> | |
Transition delay | |
<div><input type="range" min="500" max="10000" value="1500" class="slider" id="transitionDelay"></div> | |
</td> | |
</tr> | |
<tr> | |
<td> | |
Density | |
<div><input type="range" min="10" max="250" value="55" class="slider" id="density"></div> | |
</td> | |
</tr> | |
</table> | |
</td> | |
</tr> | |
</table> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#plot { | |
fill: none; | |
stroke-width: 2px; | |
stroke-linecap: round; | |
} | |
.sliderTable td { | |
padding-left: 5em; | |
padding-bottom: 5em; | |
} | |
.sliderTable input { | |
width: 360px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var w = 500, h = 500; | |
var ux1, ux2, uy1, uy2, ax1, ax2, ay1, ay2, bx1, bx2, by1, by2; | |
var data = []; | |
window.onload = function(e) { | |
d3.select("graph") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h) | |
.append("path") | |
.attr("stroke", getRandomColor) | |
.attr("d", getLineFunction()) | |
.attr("id", "plot") | |
.transition() | |
.ease(d3.easeLinear) | |
.on("start", tick); | |
}; | |
function tick() { | |
generateParameters(); | |
var linePath = document.getElementById('plot'); | |
d3.active(linePath) | |
.attr("stroke", getRandomColor) | |
.attr("d", getLineFunction()) | |
.transition() | |
.duration(getTransitionDuration()) | |
.delay(getTransitionDelay()) | |
.on("start", tick); | |
} | |
function getLineFunction() { | |
data.length = 0; | |
var steps = 2 * w; | |
for(var i = 0; i < steps; i = i+1) { | |
var t = i * 2 * Math.PI / steps; | |
data.push({"x": xFn(t), "y": yFn(t)}); | |
}; | |
data.push({"x": xFn(0), "y": yFn(0)}); | |
var maxx = d3.max(data, function(d) { return d.x; }); | |
var maxy = d3.max(data, function(d) { return d.y; }); | |
var minx = d3.min(data, function(d) { return d.x; }); | |
var miny = d3.min(data, function(d) { return d.y; }); | |
xscale = d3.scaleLinear().domain([minx, maxx]).range([10, w-10]); | |
yscale = d3.scaleLinear().domain([miny, maxy]).range([10, h-10]); | |
var lineFunction = d3.line() | |
.x(function(d) { return xscale(d.x); }) | |
.y(function(d) { return yscale(d.y); }) | |
.curve(d3.curveCatmullRom.alpha(0.5)); | |
return lineFunction(data); | |
}; | |
function xFn(t) { | |
return ux1 * Math.sin(ax1 * t + bx1) + ux2 * Math.sin(ax2 * t + bx2); | |
} | |
function yFn(t) { | |
return uy1 * Math.cos(ay1 * t + by1) + uy2 * Math.cos(ay2 * t + by2); | |
} | |
function generateParameters() { | |
ux1 = 0.3 + Math.random(); | |
ux2 = 0.3 + Math.random(); | |
uy1 = 0.3 + Math.random(); | |
uy2 = 0.3 + Math.random(); | |
ax1 = getRandomInt(5, 33); | |
var density = getDensity(); | |
ax2 = getRandomCoprime(ax1, density, (2 * density + 1)); | |
ay1 = Math.abs(getRandomInt(1,2) * ax1 - ax2); | |
ay2 = ax1 + ax2 - ay1; | |
bx1 = getRandomAngle(); | |
bx2 = getRandomAngle(); | |
by1 = getRandomAngle(); | |
by2 = getRandomAngle(); | |
} | |
function getRandomColor() { | |
var letters = '0123456789ABCDEF'; | |
var color = '#'; | |
for (var i = 0; i < 6; i++) { | |
color += letters[getRandomInt(0, 15 + i % 2)]; | |
} | |
return color; | |
} | |
function getRandomAngle() { | |
return -Math.PI/2 + Math.PI * Math.random(); | |
} | |
function getRandomInt(min, max) { | |
return min + Math.floor(Math.random() * Math.floor(max - min)); | |
} | |
function getRandomCoprime(k, min, max) { | |
while(true) { | |
var m = getRandomInt(min,max); | |
if(gcd(m,k) == 1) return m; | |
}; | |
} | |
function gcd(a, b) { | |
return b == 0 ? a : gcd(b, a % b); | |
} | |
function getTransitionDuration() { | |
return document.getElementById('transitionDuration').value; | |
} | |
function getTransitionDelay() { | |
return document.getElementById('transitionDelay').value; | |
} | |
function getDensity() { | |
return Number(document.getElementById('density').value); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment