D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
IsaKiko
Full window
Github gist
SVG inline only Gooey Effect
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 style='width:200px; margin:auto;'> <button style="font-size:1rem; color:white; font-weight:bold; padding:10px; border:0px; background-color:lightblue" id='button'>Click me!</button> </div> <script> pairs = [ {"x1":[50,55],"y1":[20,30],"x2":[70,40],"y2":[20,40],"key":'one'}, {"x1":[50,45],"y1":[20,30],"x2":[80,45],"y2":[30,10],"key":'two'}, {"x1":[50,30],"y1":[20,30],"x2":[60,30],"y2":[40,35],"key":'three'} ] d3.functor = function functor(v) { return typeof v === "function" ? v : function() { return v; }; }; var svg = d3.select("body").append("svg") .attr('id','svg') .attr("width", "100%") .attr("height", "800") .attr("viewBox", "0 0 100 100"); // goop generation for pairs of circles function goopTransform() { //set defaults var r1 = function(d) { return d.r1; }, r2 = function(d) { return d.r2; }, c1x = function(d) { return d.c1x; }, c2x = function(d) { return d.c2x; }, c1y = function(d) { return d.c1y; }, c2y = function(d) { return d.c2y; }; //returned function to generate goop path function gooptrans(d) { var r1 = d3.functor(d.c1.r).call(this, d), c1x = d3.functor(d.c1.x).call(this, d), c2x = d3.functor(d.c2.x).call(this, d), c1y = d3.functor(d.c1.y).call(this, d), c2y = d3.functor(d.c2.y).call(this, d), r2 = d3.functor(d.c2.r).call(this, d); var pi = 3.14159 var angle = Math.atan2((c2y-c1y),(c2x-c1x))/pi*180 var transform = 'translate(' + (c1x-r1) + ' ' + (c1y-r1) + ') ' + ' rotate(' + angle + ' ' +r1 + ' ' + r1 + ' )' return transform; } gooptrans.r1 = function(value) { if (!arguments.length) return r1; r1 = value; return gooptrans; }; gooptrans.r2 = function(value) { if (!arguments.length) return r2; r2 = value; return gooptrans; }; gooptrans.c1x = function(value) { if (!arguments.length) return c1x; c1x = value; return gooptrans; }; gooptrans.c2x = function(value) { if (!arguments.length) return c2x; c2x = value; return gooptrans; }; gooptrans.c1y = function(value) { if (!arguments.length) return c1y; c1y = value; return gooptrans; }; gooptrans.c2y = function(value) { if (!arguments.length) return c2y; c2y = value; return gooptrans; }; return gooptrans; } function goopGen() { //set defaults var r1 = function(d) { return d.r1; }, r2 = function(d) { return d.r2; }, c1x = function(d) { return d.c1x; }, c2x = function(d) { return d.c2x; }, c1y = function(d) { return d.c1y; }, c2y = function(d) { return d.c2y; }; //return function to generate goop path function goop(d) { var r1 = d3.functor(d.c1.r).call(this, d), c1x = d3.functor(d.c1.x).call(this, d), c2x = d3.functor(d.c2.x).call(this, d), c1y = d3.functor(d.c1.y).call(this, d), c2y = d3.functor(d.c2.y).call(this, d), r2 = d3.functor(d.c2.r).call(this, d); var pi = 3.14159 var dist = Math.sqrt((c2x-c1x)*(c2x-c1x)+(c2y-c1y)*(c2y-c1y)) var alpha1 = pi/4; var alpha2 = pi/4; var t1 = -Math.exp(-(dist-Math.log(0.75*r1)-Math.cos(alpha1)*r1-Math.cos(alpha2)*r2))+0.75*r1 var t2 = -Math.exp(-(dist-Math.log(0.75*r2)-Math.cos(alpha1)*r1-Math.cos(alpha2)*r2))+0.75*r2 var t1 = t(dist)[0] var t2 = t(dist)[1] function t(dist){ function sigmoid(dist_real){ return 0.7/(1+Math.exp(-dist_real)) } var dist_real = dist-r1-r2 var t1 = -Math.exp(-(dist-Math.log(sigmoid(dist_real)*r1)-Math.cos(alpha1)*r1-Math.cos(alpha2)*r2))+sigmoid(dist_real)*r1 var t2 = -Math.exp(-(dist-Math.log(sigmoid(dist_real)*r2)-Math.cos(alpha1)*r1-Math.cos(alpha2)*r2))+sigmoid(dist_real)*r2 return [t1, t2] } c12startx = r1+Math.cos(alpha1)*r1; c12starty = r1- Math.sin(alpha1)*r1; c12endx = r1+dist-Math.cos(alpha2)*r2; c12endy = r1-Math.sin(alpha2)*r2; c21startx = r1+dist-Math.cos(alpha2)*r2; c21starty = r1+Math.sin(alpha2)*r2; c21endx = r1+Math.cos(alpha1)*r1; c21endy = r1+Math.sin(alpha1)*r1; var pathM = 'M ' + c21endx + ' ' + c21endy; var pathA11 = "A" + r1 + "," + r1 + " 0 0,1 " + ' 0,' + r1 var pathA12 = "A" + r1 + "," + r1 + " 0 0,1 " + c12startx + ', '+ c12starty var pathC12 = 'C ' + (c12startx+t1) + ' ' + (c12starty+t1) + ', ' + (c12endx-t2) + ' ' + (c12endy+t2) + ', ' + c12endx + ' ' + c12endy; var pathA21 = "A" + r2 + ',' + r2 + ' 0 0,1 ' + (r1+dist+r2) + ',' + r1 var pathA22 = "A" + r2 + ',' + r2 + ' 0 0,1 ' + c21startx + ', '+ c21starty var pathC21 = 'C ' + (c21startx-t2) + ' ' + (c21starty-t2) + ', ' + (c21endx+t1) + ' ' + (c21endy-t1) + ', ' + c21endx + ' ' + c21endy; var path = pathM +' ' + pathA11 + ' ' + pathA12 + ' ' + pathC12 + ' ' + pathA21 + ' ' + pathA22 + ' ' + pathC21; return path; } //getter-setter methods goop.r1 = function(value) { if (!arguments.length) return r1; r1 = value; return goop; }; goop.r2 = function(value) { if (!arguments.length) return r2; r2 = value; return goop; }; goop.c1x = function(value) { if (!arguments.length) return c1x; c1x = value; return goop; }; goop.c2x = function(value) { if (!arguments.length) return c2x; c2x = value; return goop; }; goop.c1y = function(value) { if (!arguments.length) return c1y; c1y = value; return goop; }; goop.c2y = function(value) { if (!arguments.length) return c2y; c2y = value; return goop; }; return goop; } function gradGen(col1,col2, id, el){ while (el.tagName.toLowerCase() != 'svg'){ el = el.parentNode; }; var node = d3.select(el); var grad = node.insert('defs',':first-child').append('linearGradient').attr('id', id) console.log(col1) grad.append('stop') .style('stop-color', col1) .attr('offset', '0%'); grad.append('stop') .style('stop-color', col2) .attr('offset', '100%'); var ret_string = 'url(#'+id+')'; return ret_string; } var myG = goopGen() .c1x(function(d) { return d.c1.x; }) .c2x(function(d) { return d.c2.x; }) .c1y(function(d) { return d.c1.y; }) .c2y(function(d) { return d.c2.y; }) .r1(function(d) { return d.c1.r; }) .r2(function(d) { return d.c2.r; }); var myT = goopTransform() .c1x(function(d) { return d.c1.x; }) .c2x(function(d) { return d.c2.x; }) .c1y(function(d) { return d.c1.y; }) .c2y(function(d) { return d.c2.y; }) var data = pairs.map(function(el){ var col1 = 'hsl(' + (100+Math.round(el.x1[1])/10*36) + ',50%, 50%)' var col2 = 'hsl(' + (100+Math.round(el.x1[0])/10*36) + ',50%, 50%)' d = { id : 'id' + el.key, c1: { x: Math.round(el.x1[0]), y: Math.round(el.y1[0]), r: 3.5, col: col1 }, c2: { x: Math.round(el.x1[1]), y: Math.round(el.y1[1]), r: 4.5, col: col2 } } return d }) update_plot(); function update_plot(){ svg.selectAll("path.goop") .data(data, function(d){return d.id}) .enter().append("path") .attr("class", "goop") .attr("d", myG) .attr("transform", myT) .style('opacity','.55') .style('fill', function(d){var url = (gradGen(d.c1.col, d.c2.col, d.id, this)); return url}) } var button = document.getElementById('button'); button.addEventListener('click', toggle) var tog = 0 function toggle() { if (tog == 0){ tog = 1 data = pairs.map(function(el){ var col1 = 'hsl(' + (100+Math.round(el.x1[1])/10*36) + ',50%, 50%)' var col2 = 'hsl(' + (100+Math.round(el.x1[0])/10*36) + ',50%, 50%)' d = { id : 'id' + el.key, c1: { x: Math.round(el.x2[0]), y: Math.round(el.y2[0]), r: 5, col: col1 }, c2: { x: Math.round(el.x2[1]), y: Math.round(el.y2[1]), r: 4, col: col2 } } return d }) } else { tog = 0 data = pairs.map(function(el){ var col1 = 'hsl(' + (100+Math.round(el.x1[1])/10*36) + ',50%, 50%)' var col2 = 'hsl(' + (100+Math.round(el.x1[0])/10*36) + ',50%, 50%)' d = { id : 'id' + el.key, c1: { x: Math.round(el.x1[0]), y: Math.round(el.y1[0]), r: 3.5, col: col1 }, c2: { x: Math.round(el.x1[1]), y: Math.round(el.y1[1]), r: 4.5, col: col2 } } return d }) } svg.selectAll("path.goop") .data(data, function(d){return d.id}) .transition() .ease(d3.easeCubic) .duration(2000) .attr("d", myG) .attr("transform", myT) } </script> </body>
https://d3js.org/d3.v4.min.js