Simple gooey effect with 2 circles.
All stolen from Lucas Bebber's post and Nadieh Bremer's post(s) and translated to V4 (phew)...
Built with blockbuilder.org
license: mit |
Simple gooey effect with 2 circles.
All stolen from Lucas Bebber's post and Nadieh Bremer's post(s) and translated to V4 (phew)...
Built with blockbuilder.org
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
</head> | |
<body> | |
<div id="container"></div> | |
<script> | |
var margin = { top: 50, right: 50, bottom: 50, left: 50 }, | |
width = 1000 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var svg = d3.select('#container') | |
.append('svg') | |
.attr('width', width + margin.left + margin.right) | |
.attr('height', height + margin.top + margin.bottom) | |
.append('g') | |
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') | |
.attr('filter', 'url(#goo)'); // goo needs to be attached to parent object | |
// add the defs | |
var defs = svg.append('defs'); | |
var filter = defs.append('filter').attr('id','goo'); | |
filter.append('feGaussianBlur') | |
.attr('in','SourceGraphic') | |
.attr('stdDeviation','15') | |
.attr('result','blur'); | |
filter.append('feColorMatrix') | |
.attr('in','blur') | |
.attr('mode','matrix') | |
.attr('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 25 -9') | |
.attr('result','goo'); | |
// both optional for circles | |
// this is necessary for squares | |
// filter.append('feComposite') | |
// .attr('in','SourceGraphic') | |
// .attr('in2','goo') | |
// .attr('operator','atop'); | |
// or this, which seems unnecessary for circles and allows for nicer colour-merging | |
// filter.append('feBlend') | |
// .attr('in','SourceGraphic') | |
// .attr('in2','goo'); | |
svg.append('circle') | |
.attr('class', 'circleCenter') | |
.attr('cx', width/2) | |
.attr('cy', height/2) | |
.attr('r', 40) | |
.style('fill', 'tomato'); | |
svg.append('circle') | |
.attr('class', 'circleFly') | |
.attr('cx', width/2) | |
.attr('cy', height/2) | |
.attr('r', 40) | |
.style('fill', 'tomato') | |
.transition() | |
.on('start', repeat); | |
var ease = d3.easeCubic; | |
function repeat() { | |
var coords = randCoord(200,150) ; | |
d3.active(this) // returns the active transition on this node, which will always be the latest as the node listener triggers this function continuously | |
.attr('cx', width/2) | |
.attr('cy', height/2) | |
.attr('r', 40) // reset position | |
.transition().duration(1000).ease(ease) | |
.attr('cx', width/2 + coords[0]) | |
.attr('cy', height/2 + coords[1]) | |
.attr('r', 20) // transition to this | |
.transition().duration(1000).ease(ease) | |
.on('start', repeat); // kickstart process | |
} // repeat() | |
function randCoord(x,y) { | |
x = Math.round(Math.random()) ? - Math.floor((Math.random()) * x) : Math.floor((Math.random()) * x); | |
y = Math.round(Math.random()) ? - Math.floor((Math.random()) * y) : Math.floor((Math.random()) * y); | |
return [x,y]; | |
} // takes 2 maximum limits by which we want the bubbles to fly off and returns a randomised distance | |
</script> | |
</body> |