I just saw Stack Overflow's invitation in Spanish to participate in the New Year's contest for the best questions and answers tagged algorithms . And since Valentine's Day is approaching, I would like to collect algorithms to draw hearts in CSS, on canvas, in SVG or whatever you think.
Update
@Trauma comments:
Ok, the contest is fine, a prize is a prize and such, but... shouldn't it be a good question in itself? Because as it is... it leaves a lot to be desired
This comment made me think that I would have to add some code to my question so here I go:
The algorithm that I use to draw a heart is quite versatile since I can use it in CSS, in canvas and in SVG:
First I am creating an array of points
function corazon(r, paso) {
let puntos = [];
for (var a = 0; a < 2 * Math.PI; a += paso) {
let p = {};
p.x = cx + 16 * r * (Math.sin(a) * Math.sin(a) * Math.sin(a));
p.y =
cy -
13 * r * Math.cos(a) +
5 * r * Math.cos(2 * a) +
2 * r * Math.cos(3 * a) +
1 * r * Math.cos(4 * a);
puntos.push(p);
}
return puntos;
}
I found this formula here Draw a parametric heart-shaped curve in C#
The function function corazon()
returns an array of points and I'm going to use these points to draw a heart using the HTML5 canvas, SVG and finally CSS and the propertybox-shadow
on canvas
// inicia el canvas
const c = document.getElementById("canv");
const ctx = c.getContext("2d");
const cw = (c.width = 200);
const ch = (c.height = 200);
const cx = cw / 2,
cy = ch / 2;
// define el grosor de línea
ctx.lineWidth = 4;
// define el color de línea
ctx.strokeStyle = "crimson";
// el algoritmo del corazón
function corazon(r, paso) {
let puntos = [];
for (var a = 0; a < 2 * Math.PI; a += paso) {
let p = {};
p.x = cx + 16 * r * (Math.sin(a) * Math.sin(a) * Math.sin(a));
p.y =
cy -
13 * r * Math.cos(a) +
5 * r * Math.cos(2 * a) +
2 * r * Math.cos(3 * a) +
1 * r * Math.cos(4 * a);
puntos.push(p);
}
return puntos;
}
function dibujarCorazonEnCanvas() {
// crea un array vacío para guardar los puntos
let puntos = corazon(5, 0.05);
// empieza el trazado
ctx.beginPath();
// mueve el puntero al primer punto del array
ctx.moveTo(puntos[0].x, puntos[0].y);
// dibuja el corazon
puntos.forEach(p => {
ctx.lineTo(p.x, p.y);
});
// cierra el trazado
ctx.closePath();
// dibuja el corazón
ctx.stroke();
}
dibujarCorazonEnCanvas();
canvas{
border: 1px solid #d9d9d9;
}
<canvas id='canv'></canvas>
in SVG
// el centro del lienzo SVG
const cx = 100,cy = 100;
function corazon(r, paso) {
let puntos = [];
for (var a = 0; a < 2 * Math.PI; a += paso) {
let p = {};
p.x = cx + 16 * r * (Math.sin(a) * Math.sin(a) * Math.sin(a));
p.y =
cy -
13 * r * Math.cos(a) +
5 * r * Math.cos(2 * a) +
2 * r * Math.cos(3 * a) +
1 * r * Math.cos(4 * a);
puntos.push(p);
}
return puntos;
}
function dibujarCorazonEnSVG() {
// crea el array de los puntos
let puntos = corazon(5, 0.05);
// crea una cadena de texto para el atributo d de un trazado path
let d = `M${puntos[0].x},${puntos[0].y}L`;
puntos.forEach(p => {
d += `${p.x},${p.y} `;
});
// establece el valor del atributo d
corazonSVG.setAttributeNS(null, "d", d);
}
dibujarCorazonEnSVG();
svg{
border: 1px solid #d9d9d9;
}
path {
fill: none;
stroke: crimson;
stroke-width: 4px;
}
<svg id="svg" viewBox = "0 0 200 200" width="200">
<path id="corazonSVG" d="" />
</svg>
in css
I'm going to use the same algorithm to draw a heart using box-shadow
. I am going to use JavaScript to calculate the value of box-shadow
.
// crea una nueva hoja de estilos y la agrega al head
const s = document.createElement("style");
document.head.appendChild(s);
// el centro del div
const cx = 100,cy = 100;
// el algoritmo del corazón
function corazon(r, paso) {
let puntos = [];
for (var a = 0; a < 2 * Math.PI; a += paso) {
let p = {};
p.x = cx + 16 * r * (Math.sin(a) * Math.sin(a) * Math.sin(a));
p.y =
cy -
13 * r * Math.cos(a) +
5 * r * Math.cos(2 * a) +
2 * r * Math.cos(3 * a) +
1 * r * Math.cos(4 * a);
puntos.push(p);
}
return puntos;
}
function dibujarCorazonBoxShadow() {
// crea el array de los puntos
let puntos = corazon(5, 0.01);
// un array par los fragmentos de reglas css para box-shadow
let reglas = [];
// para cada punto en el array
puntos.forEach(p => {
reglas.push(`${p.x}px ${p.y}px 0px 1px crimson`);
});
// construye el valor de box-shadow utilizando la propiedad textContent de la nueva hoja de estilo
s.textContent = "div::before{box-shadow:";
s.textContent += reglas.join();
s.textContent += ";}";
}
dibujarCorazonBoxShadow();
div {
border: 1px solid #d9d9d9;
width: 200px;
height: 200px;
position: relative;
}
div::before {
content: "";
width: 1px;
height: 1px;
border-radius: 50%;
position: absolute;
top: 0px;
left: 0px;
}
<div></div>