Skip to content

Instantly share code, notes, and snippets.

@siordache
Last active August 10, 2018 19:07
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 siordache/63c832377f7d25a0cf2ab5ae979a5cfa to your computer and use it in GitHub Desktop.
Save siordache/63c832377f7d25a0cf2ab5ae979a5cfa to your computer and use it in GitHub Desktop.
Parametric curves
license: apache-2.0

An example of drawing parametric curves in d3.js.

<!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>
#plot {
fill: none;
stroke-width: 2px;
stroke-linecap: round;
}
.sliderTable td {
padding-left: 5em;
padding-bottom: 5em;
}
.sliderTable input {
width: 360px;
}
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