Dibujar un archivo SVG en un lienzo HTML5

130

¿Existe una forma predeterminada de dibujar un archivo SVG en un lienzo HTML5? Google Chrome admite cargar el SVG como una imagen (y simplemente usarlo drawImage), pero la consola del desarrollador sí lo advierte resource interpreted as image but transferred with MIME type image/svg+xml.

Sé que una posibilidad sería convertir el SVG en comandos de lienzo (como en esta pregunta ), pero espero que no sea necesario. No me interesan los navegadores antiguos (por lo tanto, si FireFox 4 e IE 9 son compatibles con algo, eso es lo suficientemente bueno).

Randy Voet
fuente
44
Esta pregunta tiene la respuesta con una demostración en vivo stackoverflow.com/questions/5495952/…
Drew LeSueur

Respuestas:

121

EDITAR Dec 16th, 2019

Path2D es compatible con todos los principales navegadores ahora

EDITAR 5 de noviembre de 2014

Ahora puede usar ctx.drawImagepara dibujar HTMLImageElements que tienen una fuente .svg en algunos pero no en todos los navegadores . Chrome, IE11 y Safari funcionan, Firefox funciona con algunos errores (pero todas las noches los ha solucionado).

var img = new Image();
img.onload = function() {
    ctx.drawImage(img, 0, 0);
}
img.src = "http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg";

Ejemplo en vivo aquí . Deberías ver un cuadrado verde en el lienzo. El segundo cuadrado verde en la página es el mismo <svg>elemento insertado en el DOM para referencia.

También puede usar los nuevos objetos Path2D para dibujar rutas SVG (cadena). En otras palabras, puedes escribir:

var path = new Path2D('M 100,100 h 50 v 50 h 50');
ctx.stroke(path);

Ejemplo en vivo de eso aquí.


Antigua respuesta de posteridad:

No hay nada nativo que le permita utilizar de forma nativa las rutas SVG en el lienzo. Debes convertirte o usar una biblioteca para hacerlo por ti.

Sugeriría buscar en canvg:

http://code.google.com/p/canvg/

http://canvg.googlecode.com/svn/trunk/examples/index.htm

Simon Sarris
fuente
44
¿Por qué se necesita esto? SVG parece dibujar perfectamente en un canvase con solo drawImage. Pero todavía recibo esa advertencia. ¿De dónde viene?
shoosh
1
Simon, lo que estás diciendo no es correcto. Y en segundo lugar, es un error confirmado en Chrome.
Mathias Lykkegaard Lorenzen
44
Parece que a Wikimedia no le gusta que uses el SVG. Cambié en snapsvg.io/assets/images/logo.svg como el primer SVG disponible que encontré. Trabajó en FF. jsfiddle.net/Na6X5/331
Thomas
1
También puede usar los URI de datos para hacer esto: jsfiddle.net/020k543w
Giratorio
9
Nota: debido a un error de FireFox de larga data, lamentablemente, los svgs que carecen de las etiquetas de ancho y alto no se mostrarán en el lienzo. Además, el ancho y la altura no deben estar en porcentajes.
Hatoru Hansou
26

Lo siento, no tengo suficiente reputación para comentar sobre la respuesta de @Matyas, pero si la imagen del svg también está en base64, se dibujará en la salida.

Manifestación:

var svg = document.querySelector('svg');
var img = document.querySelector('img');
var canvas = document.querySelector('canvas');

// get svg data
var xml = new XMLSerializer().serializeToString(svg);

// make it base64
var svg64 = btoa(xml);
var b64Start = 'data:image/svg+xml;base64,';

// prepend a "header"
var image64 = b64Start + svg64;

// set it as the source of the img element
img.onload = function() {
    // draw the image onto the canvas
    canvas.getContext('2d').drawImage(img, 0, 0);
}
img.src = image64;
svg, img, canvas {
  display: block;
}
SVG

<svg height="40">
  <rect width="40" height="40" style="fill:rgb(255,0,255);" />
  <image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAEX0lEQVQ4jUWUyW6cVRCFv7r3/kO3u912nNgZgESAAgGBCJgFgxhW7FkgxAbxMLwBEmIRITbsQAgxCEUiSIBAYIY4g1EmYjuDp457+Lv7n+4tFjbwAHVOnVPnlLz75ht67OhhZg/M0p6d5tD9C8SNBBs5XBJhI4uNLC4SREA0UI9yJr2c4e6QO+v3WF27w+rmNrv9Pm7hxDyHFg5yYGEOYxytuRY2SYiSCIwgRgBQIxgjEAKuZWg6R9S0SCS4qKLZElY3HC5tp7QPtmlMN7HOETUTXBJjrEGsAfgPFECsQbBIbDGJZUYgGE8ugQyPm+o0STtTuGZMnKZEjRjjLIgAirEOEQEBDQFBEFFEBWLFtVJmpENRl6hUuFanTRAlbTeZarcx0R6YNZagAdD/t5N9+QgCYAw2jrAhpjM3zaSY4OJGTDrVwEYOYw2qioigoviq5MqF31m9fg1V5fCx+zn11CLNVnufRhBrsVFE1Ihpthu4KDYYwz5YQIxFBG7duMZnH31IqHL6wwnGCLFd4pez3/DaG2/x4GNPgBhEZG/GGlxkMVFkiNMYay3Inqxed4eP33uf7Y0uu90xWkGolFAru7sZn5w5w921m3u+su8vinEO02hEWLN/ANnL2rkvv2an2yd4SCKLM0JVBsCgAYZZzrnPP0eDRzXgfaCuPHXwuEYjRgmIBlQVVLl8/hKI4fRzz3L6uWe5+PMvnHz6aa4uX+D4yYe5vXaLH86eoyoLjLF476l9oKo9pi5HWONRX8E+YznOef7Vl1h86QWurlwjbc+QpikPPfoIcZLS39pmMikp8pzae6q6oqgriqrGqS+xeLScoMYSVJlfOMTl5RXW1+5w5fJVnFGWf1/mxEMnWPppiclkTLM5RdJoUBYFZVlQ5DnZMMMV167gixKLoXXsKGqnOHnqOJ/+/CfZ+XUiZ0jTmFv5mAvf/YjEliQ2vPD8Ir6qqEcZkzt38cMRo5WruFvfL9FqpyRxQhj0qLOax5I2S08+Tu/lFiGUGOPormxwuyfMnjrGrJa88uIixeYWl776lmrzNjmw8vcG8sU7ixpHMXFsCUVg9tABjEvRgzP82j7AhbyiX5Qcv2+Bvy7dYGZ1k7efeQB/Y4PBqGBtdYvb3SFzLcfqToZc/OB1zYeBSpUwLBlvjZidmWaSB1yaYOfn6LqI/r0hyU6P+cRSlhXjbEI2zvnt7y79oqQ3qeg4g6vKjCIXehtDmi6m0UnxVnCRkPUHVNt9qkLJxgXOCYNOg34v48raPaamU2o89/KKsQ9sTSpc0JK7NwdcX8s43Ek5cnSOLC/Z2R6Rj0ra0w2W1/t0xyWn51uk2Ri1QtSO6OU5d7OSi72cQeWxKG7p/Dp//JXTy6C1Pcbc6DMpPRtjTxChEznWhwVZUCKrjCrPoPDczHLmnLBdBgZlRRWUEBR3ZKrme5TlrTGlV440Y1IrXM9qQGi6mkG5V6uza7tUIeCDElTZ1L26elX+fcH/ACJBPYTJ4X8tAAAAAElFTkSuQmCC" height="20px" width="20px" x="10" y="10"></image>
</svg>
<hr/><br/>

IMAGE
<img/>
<hr/><br/>
   
CANVAS
<canvas></canvas>
<hr/><br/>

Henrique Campos
fuente
1
Lo mismo con las fuentes, deben integrarse en el SVG: jsfiddle.net/ykx7kp8L/121
Sphinxxx
1
es posible que pueda iterar a través de las imgetiquetas en el svg, y luego dibujar imágenes en el lienzo por separado después.
luckydonald
24

Puede dibujar fácilmente svgs simples en un lienzo:

  1. Asignación de la fuente del svg a una imagen en formato base64
  2. Dibujando la imagen en un lienzo

Nota: El único inconveniente del método es que no puede dibujar imágenes incrustadas en el svg. (ver demo)

Demostración:

(Tenga en cuenta que la imagen incrustada solo es visible en el svg)

var svg = document.querySelector('svg');
var img = document.querySelector('img');
var canvas = document.querySelector('canvas');

// get svg data
var xml = new XMLSerializer().serializeToString(svg);

// make it base64
var svg64 = btoa(xml);
var b64Start = 'data:image/svg+xml;base64,';

// prepend a "header"
var image64 = b64Start + svg64;

// set it as the source of the img element
img.src = image64;

// draw the image onto the canvas
canvas.getContext('2d').drawImage(img, 0, 0);
svg, img, canvas {
  display: block;
}
SVG

<svg height="40">
  <rect width="40" height="40" style="fill:rgb(255,0,255);" />
  <image xlink:href="https://en.gravatar.com/userimage/16084558/1a38852cf33713b48da096c8dc72c338.png?size=20" height="20px" width="20px" x="10" y="10"></image>
</svg>
<hr/><br/>

IMAGE
<img/>
<hr/><br/>
   
CANVAS
<canvas></canvas>
<hr/><br/>

Matyas
fuente
2
¿Hay alguna forma de solucionar el problema que mencionaste? Imagen incrustada en svg.
Vijay Baskaran
Lo sentimos, pero no he encontrado una solución al problema de la imagen incrustada.
Matyas
Bueno. Gracias Matyas :)
Vijay Baskaran
6

Mozilla tiene una forma simple de dibujar SVG en el lienzo llamada " Dibujar objetos DOM en un lienzo "

Nati Krisi
fuente
Esto tiene el mismo inconveniente que en el primer método de @ Simon: no funciona en Firefox, Chrome OK.
amergin
3
Tu enlace ya no funciona. Todavía estoy interesado en Mozilla Way
Alirezak
6

Como Simon dice anteriormente, usar drawImage no debería funcionar. Pero, usando la biblioteca canvg y:

var c = document.getElementById('canvas');
var ctx = c.getContext('2d');
ctx.drawSvg(SVG_XML_OR_PATH_TO_SVG, dx, dy, dw, dh);

Esto viene del enlace que Simon proporciona arriba, que tiene una serie de otras sugerencias y señala que desea vincular o descargar canvg.js y rgbcolor.js. Estos le permiten manipular y cargar un SVG, ya sea a través de URL o usando código SVG en línea entre etiquetas svg, dentro de las funciones de JavaScript.

Max West
fuente