30

Acabo de ver la invitación de Stack Overflow en español para participar en el concurso de Año Nuevo a las mejores preguntas y respuestas con la etiqueta algoritmos. Y como que se acerca San Valentin me gustaría recoger algoritmos para dibujar corazones en CSS, en canvas, en SVG o en lo que os parezca.

Actualización

@Trauma comenta:

Vale que el concurso está bien, un premio es un premio y tal, pero ... ¿ no debería ser por si misma una buena pregunta ? Porque así como está ... deja bastante que desear

Este comentario me hizo pensar que tendría que agregar algo de código a mi pregunta así que ahí voy:

El algoritmo que utilizo para dibujar un corazón es bastante versátil ya que lo puedo utilizar en CSS, en canvas y en SVG:

Primero estoy creando un array de puntos

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;
}

Esta fórmula la encontré aquí Draw a parametric heart-shaped curve in C#

La función function corazon() devuelve un array de puntos y voy a utilizar estos puntos para dibujar un corazón utilizando el canvas de HTML5, SVG y por último CSS y la propiedad box-shadow

En 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>

En 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>

En CSS

Voy a utilizar el mismo algoritmo para dibujar un corazón utilizando box-shadow. Voy a utilizar JavaScript para calcular el valor de 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>
enxaneta
  • 3,708
  • 2
  • 9
  • 20
  • @Trauma He actualizado mi pregunta con un ejemplo. Tenía intención de agregarlo más tarde porque ahora tengo miedo que la gente piense que es una pregunta demasiado verbosa y no se animarán a contestarla. Espero que tengas una respuesta preparada para mi. Quiero ver tu corazón. – enxaneta Jan 16 '19 at 15:56
  • 2
    Ahora está mucho *mas mejor*, tienes mi +1. El JavaScript no es precisamente mi fuerte ... en fin, veremos que se puede hacer ❤❤❤ – Trauma Jan 16 '19 at 17:04
  • 1
    - Este es un ejemplo de el algoritmo de corazon revisalo https://github.com/leios/simuleios/tree/master/heart – kevin a Jan 16 '19 at 15:29
  • @Trauma Y mi +1? mi respuesta fué buena :D – AndresChica Jan 16 '19 at 19:01
  • Hay muy buenas respuestas, ¿por que ninguna ha sido aceptada? – the-breaker Sep 02 '19 at 19:08

9 Answers9

22

Cómo dibujar un corazón explicado con primitivas, Saludos

function clearDash(el) {
  var pathLength = el.getTotalLength() || el.node().getTotalLength();

  el.setAttribute('stroke-dasharray', pathLength);
  el.setAttribute('stroke-dashoffset', pathLength);
}

clearDash(document.querySelector('.heart__circle1'));
clearDash(document.querySelector('.heart__circle2'));
clearDash(document.querySelector('.heart__heart'));

var timeline = anime.timeline({ autoplay: true, direction: 'normal', loop: true });

timeline
.add({
  targets: '.heart__box',
  strokeDashoffset: {
    value: [anime.setDashoffset, 0],
    duration: 800,
    easing: 'easeInOutQuad'
  },
  opacity: {
    value: [1, 0.3],
    duration: 600,
    delay: 2600,
    easing: 'easeInOutQuad'
  },
})
.add({
  targets: '.heart__circle1',
  strokeDashoffset: {
    value: [anime.setDashoffset, 0],
    duration: 800,
    delay: 800,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
.add({
  targets: '.heart__circle2',
  strokeDashoffset: {
    value: [anime.setDashoffset, 0],
    duration: 800,
    delay: 800,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
.add({
  targets: '.heart__circle1',
  translateX: {
    value: [0, 17.5],
    duration: 800,
    delay: 1600,
    easing: 'easeInOutQuad'
  },
  opacity: {
    value: [1, 0.3],
    duration: 600,
    delay: 2600,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
.add({
  targets: '.heart__circle2',
  translateY: {
    value: [0, -17.5],
    duration: 800,
    delay: 1600,
    easing: 'easeInOutQuad'
  },
  opacity: {
    value: [1, 0.3],
    duration: 600,
    delay: 2600,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
.add({
  targets: '.heart',
  rotate: {
    value: [0, '-45deg'],
    duration: 800,
    delay: 2400,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
.add({
  targets: '.heart__heart',
  strokeDashoffset: {
    value: [anime.setDashoffset, 0],
    duration: 800,
    delay: 3200,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
.add({
  targets: '.heart__heart2',
  opacity: {
    value: [0, 1],
    duration: 800,
    delay: 4000,
    easing: 'easeInOutQuad'
  },
  offset: 0
})
;
body {
  text-align: center;
  font-family: 'Helvetica Neue', Helvetica, Arial;
}

.heart__heart2 {
  opacity: 0
}
<svg class="heart" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
      <g stroke-width="2">
        <path class="heart__box" d="M31 31h38v38H31z" fill="none" stroke="#a9a9a9"/>
        <path class="heart__circle1" d="M69 50a19 19 0 0 1-19 19 19 19 0 0 1-19-19 19 19 0 0 1 19-19 19 19 0 0 1 19 19z" fill="none" stroke="#a9a9a9"/>
        <path class="heart__circle2" d="M69 50a19 19 0 0 1-19 19 19 19 0 0 1-19-19 19 19 0 0 1 19-19 19 19 0 0 1 19 19z" fill="none" stroke="#a9a9a9"/>
        <path class="heart__heart" d="M31.07 68.93V31.07s1.51-17.455 19.117-17.455c17.608 0 18.563 17.635 18.563 17.635s17.678 1 17.678 18.497c0 17.498-17.5 19.253-17.5 19.253z" stroke="#E52231" fill="none"/>
        <path class="heart__heart2" d="M31.07 68.93V31.07s1.51-17.455 19.117-17.455c17.608 0 18.563 17.635 18.563 17.635s17.678 1 17.678 18.497c0 17.498-17.5 19.253-17.5 19.253z" fill="#E52231"/>
      </g>
    </svg>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.0.0/anime.min.js"></script>
    <script src="heart.js"></script>
AndresChica
  • 415
  • 4
  • 6
14

En R hay varias formas que se pueden ver aquí, la que mas me convence es la que usa una ecuación parámetrica en particular para construir un "cardioide":

t <- seq(0, 2*pi, by=0.1)
x <- 16*sin(t)^3
y <- 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t)

plot(x, y, type="l")
polygon(x, y, col="hotpink")

introducir la descripción de la imagen aquí

Explicación:

  • Con t <- seq(0, 2*pi, by=0.1) generamos una secuencia de números que van de 0 a 2 veces pi en pasos de 0.1
  • Aplicando sobre la secuencia, las formulas para x e y generamos estos valores que representarán los puntos externos de la forma
  • Con plot(x, y, type="l") vamos dibujando líneas a partir de cada pareja de puntos x, y. Con polygon(x, y, col="hotpink") creamos un polígono con la forma dada por los puntos y lo rellenamos con color.
Patricio Moracho
  • 54,367
  • 12
  • 35
  • 68
12

Otra opción es el path con Bezier Curve de Ricardo Cabello en uno de sus demos de como crear shapes con THREE.js.

Aquí un demo que hice usando esa figura agregándole algo de extrude para darle volúmen y multiplicándola:

class LoveScene {
  constructor() {
    this.numHearts = 1000;
    this.colors = {
      red: 0xcc0000,
      choco: 0x3f2c1e
    }
    this.extrudeSettings = {
      amount: 8,
      bevelEnabled: true,
      bevelSegments: 2,
      steps: 2,
      bevelSize: 20,
      bevelThickness: 20
    };

    this.mouseX = 0;
    this.mouseY = 0;
  
 this.isTweening = false;

    this.init();
  }

  init() {
    this.setup();
    this.makeLove();
    this.bindEvents();
    this.animate();
  }

  setup() {
    // renderer --------------
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    this.renderer.setSize(
      window.innerWidth,
      window.innerHeight
    );
    this.renderer.setPixelRatio(window.devicePixelRatio);
    document.body.appendChild(this.renderer.domElement);

    // scene --------------
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color(this.colors.red);
    this.scene.fog = new THREE.FogExp2(
      this.colors.red,
      0.002
    );

    // camera -------------------
    let fieldOfView = 60,
      aspect = window.innerWidth / window.innerHeight,
      nearPlane = 1,
      farPlane = 1000;

    this.camera = new THREE.PerspectiveCamera(
      fieldOfView,
      aspect,
      nearPlane,
      farPlane
    );
    this.camera.position.x = 2000;
    this.camera.position.y = 2000;
    this.camera.position.z = 2000;
    this.camera.lookAt(new THREE.Vector3());
  }

  appearScene() {
    this.renderer.domElement.style.opacity = 1;
  }

  makeLove() {
    this.makeHeartsAtmosphere();
    this.makeLights();
    this.makeTweenEntry();
  }

  makeHeartsAtmosphere() {
    let atmosphere = new THREE.Object3D();
    this.scene.add(atmosphere);

    let heartShape = new THREE.Shape();
    heartShape.moveTo(25, 25);
    heartShape.bezierCurveTo(25, 25, 20, 0, 0, 0);
    heartShape.bezierCurveTo(-30, 0, -30, 35, -30, 35);
    heartShape.bezierCurveTo(-30, 55, -10, 77, 25, 95);
    heartShape.bezierCurveTo(60, 77, 80, 55, 80, 35);
    heartShape.bezierCurveTo(80, 35, 80, 0, 50, 0);
    heartShape.bezierCurveTo(35, 0, 25, 25, 25, 25);

    let geometry = new THREE.ExtrudeBufferGeometry(
      heartShape,
      this.extrudeSettings
    );

    let material = new THREE.MeshPhongMaterial({
      color: this.colors.choco,
      flatShading: true
    });

    // make atmosphere
    for (let i = 0; i < this.numHearts; i++) {

      let heart = new THREE.Mesh(
        geometry,
        material
      );

      heart.position.set(
        (Math.random() - 0.5) * 1000,
        (Math.random() - 0.5) * 1000,
        (Math.random() - 0.5) * 1000
      );

      heart.scale.set(.5, .5, .5);

      heart.rotation.x = Math.PI;
      heart.rotation.y = Math.random() * Math.PI;

      atmosphere.add(heart);

    }
  }

  makeLights() {
    let light1 = new THREE.DirectionalLight(0xffffff);
    light1.position.set(1, 1, 1);
    this.scene.add(light1);

    let light2 = new THREE.DirectionalLight(0x002288);
    light2.position.set(-1, -1, -1);
    this.scene.add(light2);

    let ambient = new THREE.AmbientLight(this.colors.choco, 0.1);
    this.scene.add(ambient);
  }

  makeTweenEntry() {
  this.isTweening = true;
    this.appearScene();

    new TWEEN.Tween(this.camera.position)
      .to({ x: 0, y: 0, z: 100 }, 8000)
      .easing(TWEEN.Easing.Quintic.Out)
      .delay(2000)
   .onComplete(() => this.isTweening = false)
      .start();
  }

  animate() {
    this.renderer.render(this.scene, this.camera);

    TWEEN.update();
    // this.controls.update();

    this.camera.position.x += (this.mouseX - this.camera.position.x) * .01;
    this.camera.position.y += (- this.mouseY - this.camera.position.y) * .01;
    this.camera.lookAt(this.scene.position);

    window.requestAnimationFrame(this.animate.bind(this));
  }

  bindEvents() {
    window.addEventListener('resize', this.onWindowResize.bind(this), false);
    document.addEventListener('mousemove', this.onDocumentMouseMove.bind(this), false);
  }

  onWindowResize() {
    let width = window.innerWidth,
      height = window.innerHeight;

    this.renderer.setSize(
      width,
      height
    );

    this.camera.aspect = width / height;
    this.camera.updateProjectionMatrix();
  }

  onDocumentMouseMove(event) {
  if (this.isTweening) return;
  
    this.mouseX = (event.clientX - (window.innerWidth / 2));
    this.mouseY = (event.clientY - (window.innerHeight / 2));
  }
}

new LoveScene();
html, body { 
  margin: 0; 
  width: 100%; 
  height: 100%; 
  overflow: hidden; 
}

canvas { 
  width: 100%; 
  height: 100%; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
TheFrost
  • 121
  • 4
11

introducir la descripción de la imagen aquí

Dejo mi aporte de un corazón con brillo en SVG jeje

body{
  background: #333;
}
<svg width="200" height="200">
  <radialGradient id="grad" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
      <stop offset="0%" style="stop-color:rgb(255,255,255);stop-opacity:1" />
      <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
  </radialGradient>
  <circle cx="53" cy="51" r="35" fill="red" />
  <circle cx="106" cy="51" r="35" fill="red" />
  <rect x=40 y="20" width="70" height="70" fill="red" transform="translate(30) rotate(45, 35, 35)"></rect>
  <circle cx="50" cy="50" r="20" fill="url(#grad)">
</svg>

no es un algoritmo como tal, solo una forma de dibujar un corazón con gradient.

https://codepen.io/memoadian/pen/vvMZOK

DjCrazy
  • 4,786
  • 3
  • 13
  • 33
memoadian
  • 694
  • 3
  • 15
8

El viejo y querido Codepen

Fuente de ejemplo:

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>CSS3 Heart</title>
  
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<style>
    @keyframes beat {
0% {transform: scale(1) rotate(225deg); box-shadow:0 0 40px #d5093c;}
50% {transform: scale(1.1) rotate(225deg); box-shadow:0 0 70px #d5093c;}
100% {transform: scale(1) rotate(225deg); box-shadow:0 0 40px #d5093c;}
}

#background {
position:fixed;
top:0;
left:0;
z-index:-1;
width:100%;
height:100%;
background: #ffa5a5;
background: -moz-linear-gradient(top, #ffa5a5 0%, #ffd3d3 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffa5a5), color-stop(100%,#ffd3d3));
background: -webkit-linear-gradient(top, #ffa5a5 0%,#ffd3d3 100%);
background: linear-gradient(top, #ffa5a5 0%,#ffd3d3 100%);
}
#chest {
position:relative;
width:500px;
height:500px;
margin:0 auto;
}
.heart {
position:absolute;
z-index:2;
background: -moz-linear-gradient(-90deg, #F50A45 0%, #d5093c 40%);
background: -webkit-gradient(linear, right 50%, left 50%, color-stop(0%,#F50A45), color-stop(40%,#d5093c));
background: -webkit-linear-gradient(-90deg, #F50A45 0%,#d5093c 40%);
background: linear-gradient(-90deg, #F50A45 0%,#d5093c 40%);
-webkit-animation: beat 0.7s ease 0s infinite normal;
-moz-animation: beat 0.7s ease 0s infinite normal;
animation: beat 0.7s ease 0s infinite normal;
}
.heart.center {
background: -moz-linear-gradient(-45deg, #B80734 0%, #d5093c 40%);
background: -webkit-gradient(linear, left top, right bottom, color-stop(0%,#B80734), color-stop(40%,#d5093c));
background: -webkit-linear-gradient(-45deg, #B80734 0%,#d5093c 40%);
background: linear-gradient(-45deg, #B80734 0%,#d5093c 40%);
}
.heart.top {
z-index:3;
}
.side {
top:100px;
width:220px;
height:220px;
border-radius: 220px;
}
.center {
width:210px;
height:210px;
bottom:100px;
left:145px;
font-size:0;
text-indent:-9999px;
}
.left {
left:62px;
}
.right {
right:62px;
}
</style>

  
  <style>
  /* NOTE: The styles were added inline because Prefixfree needs access to your styles and they must be inlined if they are on local disk! */
  @keyframes beat {
0% {transform: scale(1) rotate(225deg); box-shadow:0 0 40px #d5093c;}
50% {transform: scale(1.1) rotate(225deg); box-shadow:0 0 70px #d5093c;}
100% {transform: scale(1) rotate(225deg); box-shadow:0 0 40px #d5093c;}
}

#background {
position:fixed;
top:0;
left:0;
z-index:-1;
width:100%;
height:100%;
background: #ffa5a5;
background: -moz-linear-gradient(top, #ffa5a5 0%, #ffd3d3 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffa5a5), color-stop(100%,#ffd3d3));
background: -webkit-linear-gradient(top, #ffa5a5 0%,#ffd3d3 100%);
background: linear-gradient(top, #ffa5a5 0%,#ffd3d3 100%);
}
#chest {
position:relative;
width:500px;
height:500px;
margin:0 auto;
}
.heart {
position:absolute;
z-index:2;
background: -moz-linear-gradient(-90deg, #F50A45 0%, #d5093c 40%);
background: -webkit-gradient(linear, right 50%, left 50%, color-stop(0%,#F50A45), color-stop(40%,#d5093c));
background: -webkit-linear-gradient(-90deg, #F50A45 0%,#d5093c 40%);
background: linear-gradient(-90deg, #F50A45 0%,#d5093c 40%);
-webkit-animation: beat 0.7s ease 0s infinite normal;
-moz-animation: beat 0.7s ease 0s infinite normal;
animation: beat 0.7s ease 0s infinite normal;
}
.heart.center {
background: -moz-linear-gradient(-45deg, #B80734 0%, #d5093c 40%);
background: -webkit-gradient(linear, left top, right bottom, color-stop(0%,#B80734), color-stop(40%,#d5093c));
background: -webkit-linear-gradient(-45deg, #B80734 0%,#d5093c 40%);
background: linear-gradient(-45deg, #B80734 0%,#d5093c 40%);
}
.heart.top {
z-index:3;
}
.side {
top:100px;
width:220px;
height:220px;
border-radius: 220px;
}
.center {
width:210px;
height:210px;
bottom:100px;
left:145px;
font-size:0;
text-indent:-9999px;
}
.left {
left:62px;
}
.right {
right:62px;
}
</style>

<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>

</head>

<body>

  <div id="background"></div>
<div id="chest">
  <div class="heart left side top"></div>
  <div class="heart center">&hearts;</div>
  <div class="heart right side"></div>
</div>
  <script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>

  

</body>

</html>
Juan
  • 1,664
  • 3
  • 23
  • 35
7

Agrego el código logo. Lo generé automáticamente usando una librería mía que convierte un path svg a comandos logo.

Esta es la imagen svg que utilicé, tal cual como la bajé de flaticon:

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 viewBox="0 0 51.997 51.997" style="enable-background:new 0 0 51.997 51.997;" xml:space="preserve">
<g>
<path d="M51.911,16.242C51.152,7.888,45.239,1.827,37.839,1.827c-4.93,0-9.444,2.653-11.984,6.905
    c-2.517-4.307-6.846-6.906-11.697-6.906c-7.399,0-13.313,6.061-14.071,14.415c-0.06,0.369-0.306,2.311,0.442,5.478
    c1.078,4.568,3.568,8.723,7.199,12.013l18.115,16.439l18.426-16.438c3.631-3.291,6.121-7.445,7.199-12.014
    C52.216,18.553,51.97,16.611,51.911,16.242z M49.521,21.261c-0.984,4.172-3.265,7.973-6.59,10.985L25.855,47.481L9.072,32.25
    c-3.331-3.018-5.611-6.818-6.596-10.99c-0.708-2.997-0.417-4.69-0.416-4.701l0.015-0.101C2.725,9.139,7.806,3.826,14.158,3.826
    c4.687,0,8.813,2.88,10.771,7.515l0.921,2.183l0.921-2.183c1.927-4.564,6.271-7.514,11.069-7.514
    c6.351,0,11.433,5.313,12.096,12.727C49.938,16.57,50.229,18.264,49.521,21.261z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Esta es la misma imagen en png

heart

Este es el código en python que utilizo para convertir el path svg a logo. Genero dos scripts, el primero es para MSWLogo y el segundo para otros intérpretes

from SvgPath2Logo import SvgPath2Logo

path = """
    M51.911,16.242C51.152,7.888,45.239,1.827,37.839,1.827c-4.93,0-9.444,2.653-11.984,6.905
    c-2.517-4.307-6.846-6.906-11.697-6.906c-7.399,0-13.313,6.061-14.071,14.415c-0.06,0.369-0.306,2.311,0.442,5.478
    c1.078,4.568,3.568,8.723,7.199,12.013l18.115,16.439l18.426-16.438c3.631-3.291,6.121-7.445,7.199-12.014
    C52.216,18.553,51.97,16.611,51.911,16.242z M49.521,21.261c-0.984,4.172-3.265,7.973-6.59,10.985L25.855,47.481L9.072,32.25
    c-3.331-3.018-5.611-6.818-6.596-10.99c-0.708-2.997-0.417-4.69-0.416-4.701l0.015-0.101C2.725,9.139,7.806,3.826,14.158,3.826
    c4.687,0,8.813,2.88,10.771,7.515l0.921,2.183l0.921-2.183c1.927-4.564,6.271-7.514,11.069-7.514
    c6.351,0,11.433,5.313,12.096,12.727C49.938,16.57,50.229,18.264,49.521,21.261z
"""

s = SvgPath2Logo()

#comandos para mslogo
f = open('heart_mswlogo.lgo', 'wb')
f.write(s.toLogo(path, SvgPath2Logo.MSWLOGO,  2))
f.close()

#para otros interpretes de logo
f = open('heart_xlogo.lgo', 'wb')
f.write(s.toLogo(path, SvgPath2Logo.XLOGO,  2))
f.close()

Este es el script generado para MSWLogo

    ;Code generated for MSWLogo

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Basic Functions                                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to dot_product :ux :uy :vx :vy
    output arccos (:ux*:vx+:uy*:vy)/((sqrt :ux*:ux+:uy*:uy)*(sqrt :vx*:vx+:vy*:vy))
end


;draws a cubic bezier curve from current point to (x, y)
;@param x1, y1 are the first control point
;@param x2, y2 are the second control point
;@param n is the number of points
to cubic_bezier :x1 :y1 :x2 :y2 :x :y :n

    make "dt (1.0/(:n-1))

    for [i 0 :n 1] [
        make "t :i*:dt

        ;calculating coefficients
        make "cx 3.0*(:x1-(first pos))
        make "bx 3.0*(:x2-:x1)-:cx
        make "ax :x-(first pos)-:cx-:bx

        make "cy 3.0*(:y1-(last pos))
        make "by 3.0*(:y2-:y1)-:cy
        make "ay :y-(last pos)-:cy-:by

        make "rx :ax*:t*:t*:t+:bx*:t*:t+:cx*:t+(first pos)
        make "ry :ay*:t*:t*:t+:by*:t*:t+:cy*:t+(last pos)

        ;goto new point
        setxy :rx :ry

        ;save the second control point
        make "lx1 :x2
        make "ly1 :y2
    ]
end


;draws an arc
;@param (cx, cy) is the center
;@param rx radius x
;@param ry radius y
;@param rt is the angle from the x-axis of the current coordinate system to the x-axis of the ellipse
;@param o which is the start angle of the elliptical arc prior to the stretch and rotate operations
;@param do is the difference between the initial and final angle
;see also http://www.w3.org/TR/SVG/implnote.html#ArcParameterizationAlternatives
to draw_arc :cx :cy :rx :ry :rt :o :do

    ;make angle positive and less or equal than 360
    make "o (remainder (int :o) 360)

    if :o<0 [
        make "o :o+360
    ]

    ;set turning sense
    ifelse :do<0 [
        make "i -1
    ] [
        make "i 1
    ]

    ;draw arc
    for [a :o :o+:do :i] [
        ;calculate point
        make "px (cos :rt)*:rx*(cos :a)-(sin :rt)*:ry*(sin :a)+:cx
        make "py (sin :rt)*:rx*(cos :a)+(cos :rt)*:ry*(sin :a)+:cy

        ;goto the point
        setxy :px :py
    ]

end


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;SVG Functions                                                         ;
;http://www.w3.org/TR/SVG/paths.html                                   ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


to absolute_moveto :x :y
  penup
  setxy :x :y
  pendown
  make "x0 (first pos)
  make "y0 (last pos)
end


to relative_moveto :x :y
  absolute_moveto :x+(first pos) :y+(last pos)
end


to closepath
  setxy :x0 :y0
end


to absolute_horizontal_lineto :x
  setx :x
end


to relative_horizontal_lineto :x
  absolute_horizontal_lineto :x+(first pos)
end


to absolute_vertical_lineto :y
  sety :y
end


to relative_vertical_lineto :y
  absolute_vertical_lineto :y+(last pos)
end


to absolute_lineto :x :y
  setxy :x :y
end


to relative_lineto :x :y
  absolute_lineto :x+(first pos) :y+(last pos)
end


to absolute_cubic_bezier :x1 :y1 :x2 :y2 :x :y
    ;n=1000 to ensure that the curve is smooth
    cubic_bezier :x1 :y1 :x2 :y2 :x :y 1000
end


to relative_cubic_bezier :x1 :y1 :x2 :y2 :x :y
    absolute_cubic_bezier :x1+(first pos) :y1+(last pos) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos)
end


to absolute_smooth_cubic_bezier :x2 :y2 :x :y
    absolute_cubic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x2 :y2 :x :y
end


to relative_smooth_cubic_bezier :x2 :y2 :x :y
    absolute_cubic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos)
end


to absolute_quadratic_bezier :x1 :y1 :x :y
    ;quadratic bezier expressed as cubic bezier
    ;http://fontforge.github.io/bezier.html
    ;see also "Converting TrueType to PostScript"
    absolute_cubic_bezier (first pos)+(:x1-(first pos))*2/3 (last pos)+(:y1-(last pos))*2/3 :x+(:x1-:x)*2/3 :y+(:y1-:y)*2/3 :x :y
end


to relative_quadratic_bezier :x1 :y1 :x2 :y2 :x :y
    absolute_quadratic_bezier :x1+(first pos) :y1+(last pos) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos)
end


to absolute_smooth_quadratic_bezier :x :y
    absolute_quadratic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x :y
end


to relative_smooth_quadratic_bezier :x :y
    absolute_quadratic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x+(first pos) :y+(last pos)
end


;see also http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
to absolute_arc :rx :ry :rt :fa :fs :x2 :y2

    ;auxiliar calcs
    make "rt (remainder (int :rt) 360)
    make "x1 (first pos)
    make "y1 (last pos)
    make "tx1 (cos :rt)*(:x1-:x2)/2+(sin :rt)*(:y1-:y2)/2
    make "ty1 -(sin :rt)*(:x1-:x2)/2+(cos :rt)*(:y1-:y2)/2


    ;Correction of out-of-range rx and ry
    make "rx (abs :rx)
    make "ry (abs :ry)
    make "d (sqrt (:tx1*:tx1/(:rx*:rx)+:ty1*:ty1/(:ry*:ry)))
    make "rx :d*:rx
    make "ry :d*:ry

    ;auxiliar calcs    
    make "sq (sqrt abs (((:rx*:rx*:ry*:ry-:rx*:rx*:ty1*:ty1-:ry*:ry*:tx1*:tx1)/(:rx*:rx*:ty1*:ty1+:ry*:ry*:tx1*:tx1))))
    if :fa=:fs [
        make "sq -:sq
    ]    
    make "tcx :sq*:rx*:ty1/:ry
    make "tcy :sq*-:ry*:tx1/:rx

    ;calculating coefficients
    make "cx (cos :rt)*:tcx-(sin :rt)*:tcy+(:x1+:x2)/2
    make "cy (sin :rt)*:tcx+(cos :rt)*:tcy+(:y1+:y2)/2
    make "o dot_product 1 0 (:tx1-:tcx)/:rx (:ty1-:tcy)/:ry
    make "do (remainder (int (dot_product (:tx1-:tcx)/:rx (:ty1-:tcy)/:ry (-:tx1-:tcx)/:rx (-:ty1-:tcy)/:ry)) 360)

    ;draw
    draw_arc :cx :cy :rx :ry :rt -:o -:do
end


to relative_arc :rx :ry :rt :fa :fs :x2 :y2 
    absolute_arc :rx :ry :rt :fa :fs (first pos)+:x2 (last pos)+:y2
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Draw                                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

absolute_moveto 103.822 -32.484
absolute_cubic_bezier 102.304 -15.776 90.478 -3.654 75.678 -3.654
relative_cubic_bezier -9.86 -0.0 -18.888 -5.306 -23.968 -13.81
relative_cubic_bezier -5.034 8.614 -13.692 13.812 -23.394 13.812
relative_cubic_bezier -14.798 -0.0 -26.626 -12.122 -28.142 -28.83
relative_cubic_bezier -0.12 -0.738 -0.612 -4.622 0.884 -10.956
relative_cubic_bezier 2.156 -9.136 7.136 -17.446 14.398 -24.026
relative_lineto 36.23 -32.878
relative_lineto 36.852 32.876
relative_cubic_bezier 7.262 6.582 12.242 14.89 14.398 24.028
absolute_cubic_bezier 104.432 -37.106 103.94 -33.222 103.822 -32.484
closepath
absolute_moveto 99.042 -42.522
relative_cubic_bezier -1.968 -8.344 -6.53 -15.946 -13.18 -21.97
absolute_lineto 51.71 -94.962
absolute_lineto 18.144 -64.5
relative_cubic_bezier -6.662 6.036 -11.222 13.636 -13.192 21.98
relative_cubic_bezier -1.416 5.994 -0.834 9.38 -0.832 9.402
relative_lineto 0.03 0.202
absolute_cubic_bezier 5.45 -18.278 15.612 -7.652 28.316 -7.652
relative_cubic_bezier 9.374 -0.0 17.626 -5.76 21.542 -15.03
relative_lineto 1.842 -4.366
relative_lineto 1.842 4.366
relative_cubic_bezier 3.854 9.128 12.542 15.028 22.138 15.028
relative_cubic_bezier 12.702 -0.0 22.866 -10.626 24.192 -25.454
absolute_cubic_bezier 99.876 -33.14 100.458 -36.528 99.042 -42.522
closepath

Este es el código generado para otros intérpretes

    ;Code generated for Generic logo interpreters
;You can run it in http://www.calormen.com/jslogo or https://turtleacademy.com.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Basic Functions                                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


to arcsin :a
  if :a=-1 [
    output -90
  ]
  if :a=1 [
    output 90
  ]
  output arctan :a/(sqrt 1-:a^2)
end


to arccos :a
  if :a=0 [
    output 90
  ]

  ifelse :a<0 [
      output 180+(arctan (sqrt 1-:a^2)/:a)
  ] [
      output arctan (sqrt 1-:a^2)/:a    
  ]
end


to dot_product :ux :uy :vx :vy
    output arccos (:ux*:vx+:uy*:vy)/((sqrt :ux^2+:uy^2)*(sqrt :vx^2+:vy^2))
end


;draws a cubic bezier curve from current point to (x, y)
;@param x1, y1 are the first control point
;@param x2, y2 are the second control point
;@param n is the number of points
to cubic_bezier :x1 :y1 :x2 :y2 :x :y :n

    make "dt (1.0/(:n-1))

    for [i 0 :n 1] [
        make "t :i*:dt

        ;calculating coefficients
        make "cx 3.0*(:x1-(first pos))
        make "bx 3.0*(:x2-:x1)-:cx
        make "ax :x-(first pos)-:cx-:bx

        make "cy 3.0*(:y1-(last pos))
        make "by 3.0*(:y2-:y1)-:cy
        make "ay :y-(last pos)-:cy-:by

        make "rx :ax*:t^3+:bx*:t^2+:cx*:t+(first pos)
        make "ry :ay*:t^3+:by*:t^2+:cy*:t+(last pos)

        ;goto new point
        setxy :rx :ry

        ;save the second control point
        make "lx1 :x2
        make "ly1 :y2
    ]
end


;draws an arc
;@param (cx, cy) is the center
;@param rx radius x
;@param ry radius y
;@param rt is the angle from the x-axis of the current coordinate system to the x-axis of the ellipse
;@param o which is the start angle of the elliptical arc prior to the stretch and rotate operations
;@param do is the difference between the initial and final angle
;see also http://www.w3.org/TR/SVG/implnote.html#ArcParameterizationAlternatives
to draw_arc :cx :cy :rx :ry :rt :o :do

    ;make angle positive and less or equal than 360
    make "o :o%360

    if :o<0 [
        make "o :o+360
    ]

    ;set turning sense
    ifelse :do<0 [
        make "i -1
    ] [
        make "i 1
    ]

    ;draw arc
    for [a :o :o+:do :i] [
        ;calculate point
        make "px (cos :rt)*:rx*(cos :a)-(sin :rt)*:ry*(sin :a)+:cx
        make "py (sin :rt)*:rx*(cos :a)+(cos :rt)*:ry*(sin :a)+:cy

        ;goto the point
        setxy :px :py
    ]

end


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;SVG Functions                                                         ;
;http://www.w3.org/TR/SVG/paths.html                                   ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


to absolute_moveto :x :y
  penup
  setxy :x :y
  pendown
  make "x0 (first pos)
  make "y0 (last pos)
end


to relative_moveto :x :y
  absolute_moveto :x+(first pos) :y+(last pos)
end


to closepath
  setxy :x0 :y0
end


to absolute_horizontal_lineto :x
  setx :x
end


to relative_horizontal_lineto :x
  absolute_horizontal_lineto :x+(first pos)
end


to absolute_vertical_lineto :y
  sety :y
end


to relative_vertical_lineto :y
  absolute_vertical_lineto :y+(last pos)
end


to absolute_lineto :x :y
  setxy :x :y
end


to relative_lineto :x :y
  absolute_lineto :x+(first pos) :y+(last pos)
end


to absolute_cubic_bezier :x1 :y1 :x2 :y2 :x :y
    ;n=1000 to ensure that the curve is smooth
    cubic_bezier :x1 :y1 :x2 :y2 :x :y 1000
end


to relative_cubic_bezier :x1 :y1 :x2 :y2 :x :y
    absolute_cubic_bezier :x1+(first pos) :y1+(last pos) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos)
end


to absolute_smooth_cubic_bezier :x2 :y2 :x :y
    absolute_cubic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x2 :y2 :x :y
end


to relative_smooth_cubic_bezier :x2 :y2 :x :y
    absolute_cubic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos)
end


to absolute_quadratic_bezier :x1 :y1 :x :y
    ;quadratic bezier expressed as cubic bezier
    ;http://fontforge.github.io/bezier.html
    ;see also "Converting TrueType to PostScript"
    absolute_cubic_bezier (first pos)+(:x1-(first pos))*2/3 (last pos)+(:y1-(last pos))*2/3 :x+(:x1-:x)*2/3 :y+(:y1-:y)*2/3 :x :y
end


to relative_quadratic_bezier :x1 :y1 :x2 :y2 :x :y
    absolute_quadratic_bezier :x1+(first pos) :y1+(last pos) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos)
end


to absolute_smooth_quadratic_bezier :x :y
    absolute_quadratic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x :y
end


to relative_smooth_quadratic_bezier :x :y
    absolute_quadratic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x+(first pos) :y+(last pos)
end


;see also http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
to absolute_arc :rx :ry :rt :fa :fs :x2 :y2


    ;auxiliar calcs
    make "rt :rt%360
    make "x1 (first pos)
    make "y1 (last pos)
    make "tx1 (cos :rt)*(:x1-:x2)/2+(sin :rt)*(:y1-:y2)/2
    make "ty1 -(sin :rt)*(:x1-:x2)/2+(cos :rt)*(:y1-:y2)/2


    ;Correction of out-of-range rx and ry
    make "rx (abs :rx)
    make "ry (abs :ry)
    make "d (sqrt (:tx1^2/:rx^2+:ty1^2/:ry^2))
    make "rx :d*:rx
    make "ry :d*:ry

    ;auxiliar calcs    
    make "sq (sqrt abs (((:rx^2*:ry^2-:rx^2*:ty1^2-:ry^2*:tx1^2)/(:rx^2*:ty1^2+:ry^2*:tx1^2))))
    if :fa=:fs [
        make "sq -:sq
    ]    
    make "tcx :sq*:rx*:ty1/:ry
    make "tcy :sq*-:ry*:tx1/:rx

    ;calculating coefficients
    make "cx (cos :rt)*:tcx-(sin :rt)*:tcy+(:x1+:x2)/2
    make "cy (sin :rt)*:tcx+(cos :rt)*:tcy+(:y1+:y2)/2
    make "o dot_product 1 0 (:tx1-:tcx)/:rx (:ty1-:tcy)/:ry
    make "do (dot_product (:tx1-:tcx)/:rx (:ty1-:tcy)/:ry (-:tx1-:tcx)/:rx (-:ty1-:tcy)/:ry)%360

    ;draw
    draw_arc :cx :cy :rx :ry :rt -:o -:do
end


to relative_arc :rx :ry :rt :fa :fs :x2 :y2 
    absolute_arc :rx :ry :rt :fa :fs (first pos)+:x2 (last pos)+:y2
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Draw                                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

absolute_moveto 103.822 -32.484
absolute_cubic_bezier 102.304 -15.776 90.478 -3.654 75.678 -3.654
relative_cubic_bezier -9.86 -0.0 -18.888 -5.306 -23.968 -13.81
relative_cubic_bezier -5.034 8.614 -13.692 13.812 -23.394 13.812
relative_cubic_bezier -14.798 -0.0 -26.626 -12.122 -28.142 -28.83
relative_cubic_bezier -0.12 -0.738 -0.612 -4.622 0.884 -10.956
relative_cubic_bezier 2.156 -9.136 7.136 -17.446 14.398 -24.026
relative_lineto 36.23 -32.878
relative_lineto 36.852 32.876
relative_cubic_bezier 7.262 6.582 12.242 14.89 14.398 24.028
absolute_cubic_bezier 104.432 -37.106 103.94 -33.222 103.822 -32.484
closepath
absolute_moveto 99.042 -42.522
relative_cubic_bezier -1.968 -8.344 -6.53 -15.946 -13.18 -21.97
absolute_lineto 51.71 -94.962
absolute_lineto 18.144 -64.5
relative_cubic_bezier -6.662 6.036 -11.222 13.636 -13.192 21.98
relative_cubic_bezier -1.416 5.994 -0.834 9.38 -0.832 9.402
relative_lineto 0.03 0.202
absolute_cubic_bezier 5.45 -18.278 15.612 -7.652 28.316 -7.652
relative_cubic_bezier 9.374 -0.0 17.626 -5.76 21.542 -15.03
relative_lineto 1.842 -4.366
relative_lineto 1.842 4.366
relative_cubic_bezier 3.854 9.128 12.542 15.028 22.138 15.028
relative_cubic_bezier 12.702 -0.0 22.866 -10.626 24.192 -25.454
absolute_cubic_bezier 99.876 -33.14 100.458 -36.528 99.042 -42.522
closepath

En la primera parte de los scripts se incluyen funciones generales y al final se incluyen los comandos que realizan el dibujo en sí

Este es el resultado de ejecutar el segundo script en https://www.calormen.com/jslogo/

interprete logo online

Acá explico como funciona la biblioteca http://lopezezequiel.com/svgpath2logo/

Acá esta el repo https://github.com/lopezezequiel/SvgPath2Logo

lopezezequiel
  • 344
  • 1
  • 7
7

Corazon en HTML CSS

corazon que late en mouse hover !

A la clase Corazon se le da una medida teniendo en cuenta el siguiente dato :

width = 100%
height = 85%

el margen es a eleccion, en este caso lo use mas que nada para centrarlo.

a este punto creamos 2 rectangulos, aprovechando el :before y el :after, a estos les agregamos el radius a los angulos superiores, que tienen que tener un radius que tiene que ser la mitad del width (no funciona con el 50%).

el width de los rectangulos es la mitad del width de la clase corazon. mientras al height se le saca, mas o menos un 5% de la altura de la clase.

despues se rotean gracias al transform: rotate() nuestros before y after uno de 45deg y el otro de -45deg. recordar que el after, que en este caso esta girado de -45deg, tiene que tener la propriedad left con un valor equivalente a su width.

Le agregamos tambien el box-shadow para hacer mas atractiva nuestra figura, aca es a gusto proprio.

y le agregamos una animacion en hover que aumente su medida, en los porcentajes : 0% 20% 40% y 100%.

.corazon{
    position: relative;
    width : 400px;
    height: 340px;
    margin: 5% auto;
}
.corazon:before,
.corazon:after{
  position: absolute;
  width: 200px;
  height: 320px;
  content: "";
  background-color: red;
  border-top-left-radius: 100px;
  border-top-right-radius: 100px;
}
.corazon:before{
  transform: rotate(45deg);
  transform-origin: 100% 100%;
  box-shadow: 5px -3px 10px;
}
.corazon:after{
  left: 200px;
  transform: rotate(-45deg);
  transform-origin: 0 100%;
  box-shadow: inset 6px 8px 20px rgba(255,255,255,0.6);
}
.corazon:hover{
  animation: corazon 0.8s linear infinite;
}

@keyframes corazon{
   0%{transform: scale(1,1)}
   20%{transform: scale(1.1,1.1)}
   40%{transform: scale(1.3,1.3)}
   100%{transform: scale(1,1)}
}
<div class="corazon"></div>

espero que les guste !!

Federico
  • 1,471
  • 7
  • 23
6

introducir la descripción de la imagen aquí

Una forma de dibujar un corazón via css:

.corazon{
        position: relative;
        transform: rotate(-5deg);
        width: 125px;
        margin: 40px auto;
        animation: corazon 1s infinite;
    }
    .corazon:before{
        content:'';
        background: linear-gradient(to bottom, #ff4f81, #FF5F81 21%, #ff4f81);
        width: 100px;
        height: 80px;
        display: inline-block;
        border-radius: 50% 50% 0 50% / 50% 0 50% 50%;
        transform: rotate(45deg);
    }
    .corazon:after{
        content:'';
        background: linear-gradient(45deg, #ff4f81, #FF5F81 31%, #ff4f81);
        width: 100px;
        height: 80px;
        display: inline-block;
        border-radius: 50% 50% 0 50% / 50% 0 50% 50%;
        transform: rotate(145deg);
        clip-path: polygon(0 -100%, 0 100%, 45% 100%, 100% 0);
        position: absolute;
        left: 24px;
    }

    @keyframes corazon {
        0% {transform: rotate(-5deg);}
        50% {transform: rotate(0) scale(1.05);}
        1000% {transform: rotate(-5deg);}
    }
<div class="corazon"></div>

https://codepen.io/maquetadorweb/pen/pqXeqo


enxaneta
  • 3,708
  • 2
  • 9
  • 20
Ignasi
  • 59
  • 2
  • responder con solo enlaces se considera de baja calidad –  Jan 18 '19 at 11:07
  • se te agradece la intención, pero es necesario que le des editar a esta publicación y añadas todo lo relevante aquí si es tu código y si es de un tercero dejes los créditos correspondientes –  Jan 18 '19 at 11:08
3

1. Un algoritmo para utilizar en SVG y Canvas

Este es un algoritmo que utiliza Ana Tudor en algunos pens. He adaptado este algoritmo para utilizarlo en SVG y en canvas:

function corazon(r){
// una función que devuelve un objeto que puede ser utilizado para dibujar un corazón utilixando curvas Bézier (cubicas y cuadraticas)
// el centro del corazón se encuentra en un punto cuyas coordenadas son x=0, y=0
  let o = {}
  o.ymm =-.225*r;
 o.yum =-.625*r;
 o.xo  = .625*r;
 o.yuo =-.625*r;
 o.ymo =-.2*r;
 o.ylo = .25*r;
 o.ylm = .5625*r;
  return o;
} 

// SVG

function corazonSVG(r){
// una función que dibuja un corazón 
// devuelve el valor del atributo d para un elemento path
   let o = corazon(r);
   let d = `M0,${o.ymm} 
           C0,${o.yum} ${o.xo},${o.yuo} ${o.xo},${o.ymo} 
           Q${o.xo},${o.ylo} 0,${o.ylm}
           Q${-o.xo},${o.ylo} ${-o.xo},${o.ymo}
           C${-o.xo},${o.yuo}  0,${o.yum} 0,${o.ymm}`;
   return d; 
}

// establece el valor del atributo d del path elCorazonSVG
elCorazonSVG.setAttributeNS(null,"d", corazonSVG(100))


// CANVAS

let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");

let cw = canvas.width = 200,cx = cw/2;
let ch = canvas.height = 200,cy = ch/2;

ctx.lineWidth = 3;
ctx.strokeStyle = "crimson"

ctx.translate(cx,cy)
corazonCanvas(100,ctx)

function corazonCanvas(r,ctx){
  // una función que dibuja un corazón en canvas
  let o = corazon(r);
  ctx.beginPath()
  ctx.moveTo(0,o.ymm);
  ctx.bezierCurveTo(0,o.yum,o.xo,o.yuo,o.xo,o.ymo);
  ctx.quadraticCurveTo(o.xo,o.ylo,0,o.ylm);
  ctx.quadraticCurveTo(-o.xo,o.ylo,-o.xo,o.ymo);
  ctx.bezierCurveTo(-o.xo,o.yuo,0,o.yum,0,o.ymm);
  ctx.stroke();
}
svg,canvas{border:1px solid; width:200px}
path{fill:none; stroke:crimson; stroke-width:3}
<svg viewBox="-100 -100 200 200">
<path id="elCorazonSVG" />    
</svg>

<canvas></canvas>

2. Otra manera de dibujar un corazón en CSS

En este caso utilizo dos elementos div con bordes redondeados. Esto crea dos óvalos que estoy girando hacia la derecha y hacia la izquierda. Puede cambiar el valor de la variable --h para generar corazones de varios tamaños.

.corazon{
    --h: 70;/*cambia esto para cambiar el tamaño del corazón*/
    /* este es el tamaño del corazón en vh. Si prefieres que sea en píxeles cambia 1vh por 1px */

 width:calc(var(--h) * .9 * 1vh);
 height:calc(var(--h) * 1vh);
 top:0;bottom:0;
 left:0;right:0;
  margin:auto;
 position:absolute;
 }

.corazon div{
 background:#ff0000;
 width:calc((2*var(--h) / 3) * 1vh);
 height:calc(var(--h) * 1vh);
 display:block;
 position:absolute;
 border-radius:50%;
 }

.izquierda {
  left:0;
  transform:rotate(-30deg);
}

.derecha{
  right:0;
  transform:rotate(30deg);
}
<div class="corazon">
 <div class="izquierda"></div>
 <div class="derecha"></div>
</div>
enxaneta
  • 3,708
  • 2
  • 9
  • 20