A flock of paper planes created with D3.js
A Pen by Apon Palanuwech on CodePen.
A flock of paper planes created with D3.js
A Pen by Apon Palanuwech on CodePen.
<div class="debug">Hey</div> | |
<!-- Drop shadow --> | |
<filter id="dropshadow" height="130%"> | |
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/> <!-- stdDeviation is how much to blur --> | |
<feOffset dx="2" dy="2" result="offsetblur"/> <!-- how much to offset --> | |
<feMerge> | |
<feMergeNode/> <!-- this contains the offset blurred image --> | |
<feMergeNode in="SourceGraphic"/> <!-- this contains the element that the filter is applied to --> | |
</feMerge> | |
</filter> |
// paper plane by Apon Palanuwech | |
// apon.io | |
var log = $('.debug'); | |
var c = { | |
svgEl: null, | |
planeArray: [] | |
}; | |
c.init = function() { | |
// append svg | |
c.svgEl = d3.select('body').append('svg').attr({ | |
width: '100%', | |
height: '100%' | |
}); | |
var numPlane = 10; | |
/* for(var i = 0; i < numPlane;i++) { | |
c.planeArray[i] = Plane.create(); | |
} | |
for(var j = 0; j < numPlane;j ++) { | |
Plane.fly(j, randNum(5000) + 3000); | |
}*/ | |
d3.timer(function() { | |
if(c.planeArray.length < 100) { | |
log.html(c.planeArray.length); | |
c.planeArray.push(Plane.create()); | |
Plane.fly(c.planeArray.length-1, randNum(10000) + 3000); | |
} | |
for(var i = 0;i < numPlane; i++) { | |
var t = d3.transform($('g').eq(i).attr("transform")); | |
if(t.translate[0] > window.innerWidth) { | |
c.planeArray.splice(i, 1); | |
$('g').eq(i).remove(); | |
$('.planePath').eq(i).remove(); | |
} | |
} | |
}); | |
}; | |
var Plane = {}; | |
// create path for plane | |
Plane.create = function() { | |
// three trinagle plane | |
function generateForm() { | |
var t1, t2, t3; | |
var Sx = 0, Sy = -10, scale = randNum(2)+0.5, cockpit = { | |
x: 56, | |
y: 5 | |
}; | |
t1 = 'M'+Sx+' '+Sy+'L'+(Sx+cockpit.x)*scale+' '+(Sy+cockpit.y)*scale+'L'+Sx+' '+(Sy+24)*scale; | |
t2 = 'M'+Sx+' '+Sy+'L'+(Sx+cockpit.x)*scale+' '+(Sy+cockpit.y)*scale+'L'+(Sx+12)*scale+' '+(Sy+24)*scale; | |
t3 = 'M'+Sx+' '+Sy+'L'+(Sx+cockpit.x)*scale+' '+(Sy+cockpit.y)*scale+'L'+(Sx-12)*scale+' '+(Sy+12)*scale; | |
return { | |
t1: t1, | |
t2: t2, | |
t3: t3 | |
}; | |
} | |
var t = generateForm(); | |
var tc = randomColor(); | |
var group = c.svgEl.append('g'); | |
// append behind wing | |
group.append('path') | |
.attr({ | |
d: t.t3 | |
}) | |
.style({ | |
fill: tc.c1 | |
}); | |
// a | |
// append torso | |
group.append('path') | |
.attr({ | |
d: t.t1 | |
}) | |
.style({ | |
fill: tc.c2 | |
}); | |
// append above wing | |
group.append('path') | |
.attr({ | |
d: t.t2 | |
}) | |
.style({ | |
fill: tc.c3 | |
}); | |
// return | |
return group; | |
}; | |
Plane.fly = function(num, duration) { | |
var myPath = c.svgEl.append("path") | |
.data([generatePath()]) | |
.attr({ | |
class: 'planePath', | |
d: d3.svg.line() | |
.tension(0) // Catmull–Rom | |
.interpolate("basis") | |
}); | |
c.planeArray[num] | |
.transition() | |
.duration(duration) | |
.ease("linear") | |
.attrTween("transform", translateAlong(c.planeArray[num].node().getBBox(), myPath.node())); | |
}; | |
c.init(); | |
// helper | |
function generatePath() { | |
var pathArray = []; | |
for(var i = 0; i < 5;i++) { | |
pathArray.push([i*500 - randNum(400), randNum(700)]); | |
} | |
return pathArray; | |
} | |
function translateAlong(el, path) { | |
var l = path.getTotalLength(); | |
var t0 = 0; | |
return function(i) { | |
return function(t) { | |
var p0 = path.getPointAtLength(t0 * l);//previous point | |
var p = path.getPointAtLength(t * l);////current point | |
var angle = Math.atan2(p.y - p0.y, p.x - p0.x) * 180 / Math.PI;//angle for tangent | |
t0 = t; | |
//Shifting center to center of rocket | |
var centerX = p.x - el.width, | |
centerY = p.y - el.height; | |
return "translate(" + centerX + "," + centerY + ")rotate(" + angle + " " + el.width + " " + el.height + ")"; | |
}; | |
}; | |
} | |
function randNum(num) { | |
return Math.floor(Math.random() * num) + 1; | |
} | |
function randomColor() { | |
var c1, c2, c3; | |
var rand = Math.floor(Math.random() * 120) +120; | |
c1 = 'hsl('+rand+',75%,30%)'; | |
c2 = 'hsl('+rand+',75%,55%)'; | |
c3 = 'hsl('+rand+',75%,80%)'; | |
return { | |
c1: c1, | |
c2: c2, | |
c3: c3 | |
}; | |
} |
* { | |
margin: 0;padding: 0; | |
} | |
.debug { | |
position: fixed; | |
top:0; left:0; | |
color: #fff; | |
font-size: 2em; | |
z-index:9999; | |
background: #000; | |
width: 200px; | |
height: 40px; | |
} | |
svg { | |
background: black; | |
} | |
g { | |
opacity: 0.95; | |
} | |
path { | |
fill: none; | |
/* stroke: #000; */ | |
/* stroke-width: 3px; */ | |
} |