Built with blockbuilder.org
forked from walkerjeffd's block: Spinning Ovals II
license: mit |
Built with blockbuilder.org
forked from walkerjeffd's block: Spinning Ovals II
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.5/dat.gui.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
.stop-left { | |
stop-color: rgba(0, 192, 191, 1); /* Indigo */ | |
} | |
.stop-right { | |
stop-color: rgba(44, 161, 252, 1); /* Teal */ | |
} | |
.outlined { | |
fill: none; | |
stroke: url(#mainGradient); | |
} | |
ellipse { mix-blend-mode: normal; } | |
.isolate { isolation: isolate; } | |
</style> | |
</head> | |
<body> | |
<script> | |
var gui = new dat.GUI(); | |
var ellipseFactor = 0.92352 , | |
speed = 10000, | |
omega = 180, | |
scale = 1, | |
strokeWidth = 38, | |
blur = 0, | |
n = 2, | |
minRadius = 100, | |
radiusFactor = 1.04, | |
pulseFactor = 4; | |
var opacity = 0.4; | |
// var opacity = 1/n; | |
gui.add(window, "n", 1, 20).step(1).onChange(restart); | |
gui.add(window, "speed", 100, 20000).step(100); | |
gui.add(window, "strokeWidth", 0, 100).step(10); | |
gui.add(window, "ellipseFactor", 0.1, 2).step(0.01); | |
gui.add(window, "opacity", 0, 1).step(0.01); | |
gui.add(window, "blur", 0, 10).step(0.1); | |
gui.add(window, "pulseFactor", 0, 100); | |
gui.add(window, "radiusFactor", 1, 2).step(0.01); | |
gui.add(window, "omega", 0, 360).step(1); | |
var width = 960, | |
height = 500; | |
var svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height) | |
.append('g') | |
.attr('class', 'isolate') | |
.attr('transform', 'scale(' + scale + ')') | |
var defs = svg.append('defs'); | |
// Color gradient | |
var mainGradient = defs.append('linearGradient') | |
.attr('id', 'mainGradient'); | |
mainGradient.append('stop') | |
.attr('class', 'stop-left') | |
.attr('offset', '0'); | |
mainGradient.append('stop') | |
.attr('class', 'stop-right') | |
.attr('offset', '1'); | |
// Filter for the outside glow | |
var filter = defs.append('filter') | |
.attr('id', 'glow'); | |
var feGaussianBlur = filter.append('feGaussianBlur') | |
.attr('stdDeviation', blur) | |
.attr('result','coloredBlur'); | |
var feMerge = filter.append('feMerge'); | |
feMerge.append('feMergeNode') | |
.attr('in', 'coloredBlur'); | |
feMerge.append('feMergeNode') | |
.attr('in', 'SourceGraphic'); | |
// Shapes | |
var ellipse; | |
function restart() { | |
console.log("restart", n); | |
var data = d3.range(n); | |
svg.selectAll('ellipse').remove(); | |
var ellipseSel = svg.selectAll('ellipse') | |
.data(data); | |
ellipse = ellipseSel | |
.enter() | |
.append('ellipse') | |
.classed('outlined', true) | |
.style('filter', 'url(#glow)') | |
.style('opacity', opacity) | |
.style('stroke-width', strokeWidth) | |
.attr('cx', width / 2) | |
.attr('cy', height / 2) | |
.attr('rx', 100 * ellipseFactor) | |
.attr('ry', 100) | |
ellipseSel.exit().remove(); | |
ellipse.each(function (d) { | |
var theta = d / n * omega; | |
d3.select(this) | |
.attr('transform', 'rotate(' + theta + ',' + width/2 + ',' + height/2 + ')'); | |
}); | |
} | |
restart(); | |
d3.timer(function (elapsed) { | |
feGaussianBlur.attr('stdDeviation', blur); | |
ellipse | |
.style('opacity', opacity) | |
.style('stroke-width', strokeWidth) | |
.attr('rx', 100 * ellipseFactor); | |
ellipse.each(function (d) { | |
var theta = elapsed % speed / speed * 360 + d / n * omega, | |
r = minRadius + (minRadius * radiusFactor - minRadius) * (Math.sin(((elapsed % speed * pulseFactor) / speed) * 2 * Math.PI) / 2 + 0.5); | |
d3.select(this) | |
.attr('transform', 'rotate(' + theta + ',' + (width/2) + ',' + (height/2) + ')') | |
.attr('rx', r * ellipseFactor) | |
.attr('ry', r); | |
}) | |
}) | |
</script> | |
</body> |