A heart created with D3 and a nice formula found on Wolfram to celebrate Valentine's Day!
forked from nbremer's block: Valentine's day Heart curve
xxxxxxxxxx
<html>
<head>
<title>D3.js Valentines day</title>
<style>
body{
}
chart{
display: block;
margin-left:auto;
margin-right: auto;
}
text {
text-anchor: middle;
fill: #8A0707;
font-size: 28px;
/*font-weight: 700;*/
opacity: 0.9;
}
path{
stroke: #8A0707;
stroke-width: 1;
fill: none;
opacity: 0.4;
}
circle {
fill: #8A0707;
opacity: 0.9;
}
</style>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
window.onerror = function() {
location.reload();
}
var margin = {top: 10, right: 10, bottom: 10, left: 10},
docHeight = $(document).height() - margin.left - margin.right,
docWidth = $(document).width() - margin.top - margin.bottom;
var minSize = Math.min(500,(docWidth-40),(docHeight-40)),
width = minSize,
height = minSize;
//Circle ranges
var circeRanges = [8 * width/2000, 30 * width/2000];
var forceRanges = [6 * width/2000, 10 * width/2000];
//But adjusted for D3 and made to move along a path
var ID = 0, //makes all particles unique
counter = 0, //counter for the infinity path
colors = [ '#69D2E7', '#A7DBD8', '#E0E4CC', '#F38630', '#FA6900', '#FF4E50', '#F9D423' ], //first colors
colorMode = "screen", //first blend mode
particles = [];
//Create the datapoints with x en y positions for the circles
//Formula from https://mathworld.wolfram.com/HeartCurve.html
var x, y;
var infScale = width/2*0.7;
var data = [];
for (var i = 0; i < 30; i++) {
x = 16 * Math.pow(Math.sin(i),3);
y = 13 * Math.cos(i) - 5* Math.cos(2*i) - 2 * Math.cos(3*i) - Math.cos(4*i)
data[i] = [x*infScale,y*infScale];
}//for i
//Scales
var xScale = d3.scale.linear()
.domain([d3.min(data, function(d) { return d[0]; }), d3.max(data, function(d) { return d[0]; })])
.range([ 0, width ]);
var yScale = d3.scale.linear()
.domain([d3.min(data, function(d) { return d[1]; }), d3.max(data, function(d) { return d[1]; })])
.range([ height, 0 ]);
//Initiate the SVG
var chart = d3.select('#chart')
.append('svg')
.attr('width', docWidth)
.attr('height', docHeight)
.attr('class', 'chart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Initiate the group that will hold all the dots and lines
var svg = chart.append('g')
.attr('transform', 'translate(' + (docWidth/2-width/2) + ',' + (docHeight/2-height/2) + ')')
.attr('width', width)
.attr('height', height);
///////////////////////////////////////////////////////////////////////////
//////////////////// Make the circles move in a pattern ///////////////////
///////////////////////////////////////////////////////////////////////////
//Wrapper for the circles
var circleWrapper = svg.append("g")
.attr("class", "circleWrapper")
.style("isolation", "isolate");
function runInfinity() {
//Create new particles
for (var j = 0; j < Math.round(Math.random()*16); j++) spawn(data[counter].x, data[counter].y);
//Remove non-alive particles
particles = particles.filter(function(d) { return d.alive; });
//DATA JOIN
//Join new data with old elements, if any
var circleGroup = circleWrapper.selectAll(".particle")
.data(particles, function(d) { return d.id; });
//UPDATE
circleGroup
.style("mix-blend-mode", colorMode)
.each(move)
.transition("move").duration(50).ease("linear")
.attr("cx", function (d) { return xScale(d[0]); } )
.attr("cy", function (d) { return yScale(d[1]); } )
.attr("r", function(d) { return d.radius; });
//ENTER
circleGroup
.enter().append("circle")
.attr("class", "particle")
.attr("cx", function (d) { return xScale(d[0]); } )
.attr("cy", function (d) { return yScale(d[1]); } )
.style("fill", function(d) { return d.color; })
.style("mix-blend-mode", colorMode)
.attr("r", function(d) { return d.radius; });
//EXIT
circleGroup.exit().remove();
counter = (counter + 1)%data.length;
}//runInfinity
//Create an interval that runs along the infinity path
var loopInfinity = setInterval(runInfinity , 50);
//Create a particle
//Code heavily based on https://codepen.io/soulwire/pen/foktm
//Calculates new position
function move(d) {
d.x += d.vx;
d.y += d.vy;
d.vx *= d.drag;
d.vy *= d.drag;
d.theta += getRandomNumber( -0.5, 0.5 ) * d.wander;
d.vx += Math.sin( d.theta ) * 0.5;
d.vy += Math.cos( d.theta ) * 0.5;
d.radius *= d.age;
d.alive = d.radius > 0.5;
}//move
function spawn ( x, y ) {
//Play around with these numbers to get different effects
particle = {
x: x,
y: y,
id: ID,
alive: true,
radius: getRandomNumber( circeRanges[0], circeRanges[1] ),
wander: getRandomNumber( 1, 1.5 ),
color: colors[ Math.round( getRandomNumber(0, colors.length-1)) ],
drag: getRandomNumber( 0.2, 0.99 ),
age: getRandomNumber( 0.92, 0.98 ),
theta: getRandomNumber( 0, 2 * Math.PI ),
force: getRandomNumber( forceRanges[0], forceRanges[1] )
};
ID += 1;
particle.vx = Math.sin( particle.theta ) * particle.force;
particle.vy = Math.cos( particle.theta ) * particle.force;
particles.push( particle );
}//spawn
function getRandomNumber(start, end) {
return ((Math.random() * (end-start)) + start);
}
</script>
</body>
</html>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js
https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js