My attempt at a SVG lava lamp using the gooey effect
Purely aesthetic and maybe nostalgic
A minor adptation of Nadieh Bremer's previous work:
http://www.visualcinnamon.com/2016/06/fun-data-visualizations-svg-gooey-effect.html
My attempt at a SVG lava lamp using the gooey effect
Purely aesthetic and maybe nostalgic
A minor adptation of Nadieh Bremer's previous work:
http://www.visualcinnamon.com/2016/06/fun-data-visualizations-svg-gooey-effect.html
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"charset="utf-8"></script> | |
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans" /> | |
<link rel="stylesheet" type="text/css" href="./lavaLamp.css"> | |
</head> | |
<body> | |
<div id="gooContainer"> | |
<div class='podium'></div> | |
<div class='block'> | |
<div class='instructions'>Select a Color</div> | |
<select id="color-select" onchange="changeColor()"> | |
<option value="green" selected="selected">Green</option> | |
<option value="purple">Purple</option> | |
<option value="red">Red</option> | |
<option value="gray">Gray</option> | |
</select> | |
</div> | |
</div> | |
</body> | |
<script language="javascript" type="text/javascript" src='./lavaLamp.js'></script> | |
</html> |
body { | |
text-align: center; | |
background-color: #fbfbfb; | |
font-family:"Open Sans"; | |
font-size: 14px; | |
} | |
.podium{ | |
position: absolute; | |
width: 35%; | |
height: 5%; | |
left:32%; | |
bottom:7%; | |
background-color:black; | |
border-radius: 5px; | |
} | |
.block{ | |
position: absolute; | |
width: 110px; | |
height:80px; | |
left:44.3%; | |
bottom:10%; | |
background-color:black; | |
border-radius: 5px; | |
} | |
.instructions{ | |
color:white; | |
margin-top: 15px; | |
margin-bottom: 5px; | |
} |
var margin = {top: 10,right: 0,bottom: 50,left: 0}; | |
var width = 700 - margin.left - margin.right - 10, | |
height = 500 - margin.top - margin.bottom - 20; | |
//SVG container | |
var svg = d3.select('#gooContainer') | |
.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 + ")"); | |
//SVG filter for the gooey effect | |
//Code taken from http://tympanus.net/codrops/2015/03/10/creative-gooey-effects/ | |
var defs = svg.append("defs"); | |
var filter = defs.append("filter").attr("id","gooeyCodeFilter"); | |
filter.append("feGaussianBlur") | |
.attr("in","SourceGraphic") | |
.attr("stdDeviation","10") | |
//to fix safari: http://stackoverflow.com/questions/24295043/svg-gaussian-blur-in-safari-unexpectedly-lightens-image | |
.attr("color-interpolation-filters","sRGB") | |
.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 19 -9") | |
.attr("result","gooey"); | |
//Create gradients | |
var gradients ={ | |
green:["#0AAF00","#00ff0e","#aaff5b","#f7ffa7"], | |
purple:["#520076","#c53ffe","#e297fe","#f4d6ff"], | |
red:["#950c14","#fb3930","#fb673c","#fcaa44"], | |
gray:["#2a2a2a","#545454","#7e7e7e","#d3d3d3"] | |
} | |
defs.append("linearGradient") | |
.attr("id", "lavaGradient") | |
.attr("gradientUnits", "userSpaceOnUse") | |
.attr("y1", -height/2*0.85).attr("x1", 0) | |
.attr("y2", height/2*0.85).attr("x2", 0) | |
.selectAll("stop") | |
.data(d3.range(gradients.green.length)) | |
.enter().append("stop") | |
.attr("offset", function(d,i) { return (i/(gradients.green.length-1)*100) + "%"; }) | |
.attr("stop-color", function(d) { return gradients.green[d]; }); | |
defs.append("clipPath") | |
.attr("id", "clip") | |
.append("ellipse") | |
.attr("cx",width/2) | |
.attr("cy",height/2) | |
.attr("rx",width/12) | |
.attr("ry",height/2); | |
defs.append("clipPath") | |
.attr("id", "clip_cap") | |
.append("ellipse") | |
.attr("cx",width/2) | |
.attr("cy",(height/2)) | |
.attr("rx",(width/12)+2) | |
.attr("ry",(height/2)+2); | |
svg.append("ellipse") | |
.attr("class","water") | |
.attr("cx",width/2) | |
.attr("cy",height/2) | |
.attr("rx",width/12) | |
.attr("ry",height/2) | |
.style("fill", "#AAD4E0"); | |
//First append a group for the clip path, then a new group that can be transformed | |
var circleWrapper = svg.append("g") | |
.attr("clip-path", "url(#clip") | |
.style("clip-path", "url(#clip)") //make it work in safari | |
.append("g") | |
.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")") | |
.style("filter", "url(#gooeyCodeFilter)"); | |
//Create dataset with random radius | |
randStart = []; | |
for(var i = 0; i < 20; i++) { | |
randStart.push({ | |
r: 15 + Math.random()*10 | |
}); | |
} | |
var circle = circleWrapper.selectAll(".dots") | |
.data(randStart) | |
.enter().append("circle") | |
.attr("class", "dots") | |
.attr("cx", 0) | |
.attr("cy", function(d){return (height/2)-d.r;}) | |
.attr("r", function(d){return d.r}) | |
.style("fill", "url(#lavaGradient)") | |
.style("opacity", 1) | |
.each(move); | |
var footer = circleWrapper.selectAll(".footer") | |
.data([{r:50}]) | |
.enter().append("circle") | |
.attr("class", "footer") | |
.attr("cx", 0) | |
.attr("cy", function(d){return (height/2)-(d.r)}) | |
.attr("r", function(d){return d.r}) | |
.style("fill", "url(#lavaGradient)") | |
.style("opacity", 1); | |
var header = circleWrapper.selectAll(".header") | |
.data([{r:50}]) | |
.enter().append("circle") | |
.attr("class", "header") | |
.attr("cx", 0) | |
.attr("cy", function(d){return (-height/2)+d.r}) | |
.attr("r", function(d){return d.r}) | |
.style("fill", "url(#lavaGradient)") | |
.style("opacity", 1); | |
svg.append("ellipse") | |
.attr("class","ellipse") | |
.attr("cx",width/2) | |
.attr("cy",height/2) | |
.attr("rx",width/12) | |
.attr("ry",height/2) | |
.style("stroke", "#6C6C6C") | |
.style("stroke-width", "4px") | |
.style("fill", "none"); | |
svg.append("rect") | |
.attr("class","cap") | |
.attr("clip-path", "url(#clip_cap") | |
.style("clip-path", "url(#clip_cap)") //make it work in safari | |
.attr("x",width/4) | |
.attr("y",-10) | |
.attr("height",75) | |
.attr("width",width) | |
.style("fill", "black"); | |
function changeColor(){ | |
var selectedColor = document.getElementById("color-select") | |
.options[document.getElementById("color-select").selectedIndex].value; | |
d3.select("#lavaGradient") | |
.selectAll("stop") | |
.transition("change-color").duration(3000) | |
.attr("stop-color", function(d) { return gradients[selectedColor][d]; }); | |
} | |
function move(d) { | |
var currenty = parseFloat(d3.select(this).attr("cy")); | |
var newx = (Math.random() <0.5)?-Math.random()*50:Math.random()*50; | |
var newy = currenty*-1; | |
//Transition the circle to its new location | |
d3.select(this) | |
.transition("move") | |
.duration(8000+8000*Math.random()) | |
.ease("easeInQuart") | |
.attr("cy", newy) | |
.attr("cx", newx) | |
.attr("r",function(){return 15 + Math.random()*10}) | |
.each("end", move) | |
} |