Skip to content

Instantly share code, notes, and snippets.

@duhaime
Forked from newby-jay/LICENSE
Created January 1, 2018 15:46
Show Gist options
  • Save duhaime/d06a4c823da7d55c0bbb0cb2724d43e9 to your computer and use it in GitHub Desktop.
Save duhaime/d06a4c823da7d55c0bbb0cb2724d43e9 to your computer and use it in GitHub Desktop.
Vector field flow visualization
// Jay Newby 2014
// http://people.mbi.ohio-state.edu/newby.23/
// http://www.math.utah.edu/~newby/
// https://github.com/newby-jay
// Based on the global weather visualization,
// http://earth.nullschool.net/ by Cameron Beccario
//////////////////////////////////////////////////
(function animation() {
// vector field data
var gamma = 2, c = 10, dt = 0.005,
X0 = [], Y0 = [], // to store initial starting locations
X = [], Y = [], // to store current point for each curve
xb = 1.5, yb = 1.3;
//// curve ////
var N = 50, // 25^2 curves
// discretize the vfield coords
xp = d3.range(N).map(
function (i) {
return xb*(-1 + i*2/N);
}),
yp = d3.range(N).map(
function (i) {
return yb*(-1 + i*2/N);
});
// array of starting positions for each curve on a uniform grid
for (var i = 0; i < N; i++) {
for (var j = 0; j < N; j++) {
X.push(xp[j]), Y.push(yp[i]);
X0.push(xp[j]), Y0.push(yp[i]);
}
}
// vfield
function F(x, y) {
var rho = Math.sqrt(x*x + y*y),
r = rho - 1,
a = gamma*(1 - rho*rho),
b = -gamma*c*r*r + 1;
return [x*a - b*y, y*a + b*x];
}
//// frame setup
var width = 960,
height = 500,
mw = 0, // if we want a margin
g = d3.select("#animation").node().getContext("2d"); // initialize a "canvas" element
g.fillStyle = "rgba(0, 0, 0, 0.05)"; // for fading curves
g.lineWidth = 0.7;
g.strokeStyle = "#FF8000"; // html color code
//// mapping from vfield coords to web page coords
var xMap = d3.scale.linear()
.domain([-xb, xb])
.range([mw, width - mw]),
yMap = d3.scale.linear()
.domain([-yb, yb])
.range([height - mw, mw]);
//// animation setup
var animAge = 0,
frameRate = 30, // ms per timestep (yeah I know it's not really a rate)
M = X.length,
MaxAge = 100, // # timesteps before restart
age = [];
for (var i=0; i<M; i++) {age.push(randage());}
var drawFlag = true;
// setInterval(function () {if (drawFlag) {draw();}}, frameRate);
d3.timer(function () {if (drawFlag) {draw();}}, frameRate);
d3.select("#animation")
.on("click", function() {drawFlag = (drawFlag) ? false : true;})
function randage() {
// to randomize starting ages for each curve
return Math.round(Math.random()*100);
}
// for info on the global canvas operations see
// http://bucephalus.org/text/CanvasHandbook/CanvasHandbook.html#globalcompositeoperation
g.globalCompositeOperation = "source-over";
function draw() {
g.fillRect(0, 0, width, height); // fades all existing curves by a set amount determined by fillStyle (above), which sets opacity using rgba
for (var i=0; i<M; i++) { // draw a single timestep for every curve
var dr = F(X[i], Y[i]);
g.beginPath();
g.moveTo(xMap(X[i]), yMap(Y[i])); // the start point of the path
g.lineTo(xMap(X[i]+=dr[0]*dt), yMap(Y[i]+=dr[1]*dt)); // the end point
g.stroke(); // final draw command
if (age[i]++ > MaxAge) {
// incriment age of each curve, restart if MaxAge is reached
age[i] = randage();
X[i] = X0[i], Y[i] = Y0[i];
}
}
}
})()
<html lang="en">
<head></head>
<style>
body {
height: 100%;
width: 100%;
background: #000;
}
#animation {
position: absolute;
top: 0px;
left: 0px;
background: #000;
}
</style>
<body>
<canvas id="animation" width="960" height="500"></canvas>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="flow_anim.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment