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).


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


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


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


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

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.