2012-07-19 31 views
11

¿Alguien ha intentado usar una svg en la biblioteca de lienzos al crear visualizaciones de d3.js? He tratado de utilizar canvg.js y d3.js para convertir SVG en el lienzo desde el interior de un androide vista web 2.3 aplicación, pero cuando llamo:SVG a Canvas con d3.js

svg.selectAll(".axis") 
     .data(d3.range(angle.domain()[1])) 
    .enter().append("g") 
     .attr("class", "axis") 
     .attr("transform", function(d) { return "rotate(" + angle(d) * 180/Math.PI + ")"; }) 
    .call(d3.svg.axis() 
     .scale(radius.copy().range([-5, -outerRadius])) 
     .ticks(5) 
     .orient("left")) 
    .append("text") 
     .attr("y", 
     function (d) { 
      if (window.innerWidth < 455){ 
      console.log("innerWidth less than 455: ",window.innerWidth); 
      return -(window.innerHeight * .33); 
      } 
      else{ 
      console.log("innerWidth greater than 455: ",window.innerWidth); 
      return -(window.innerHeight * .33); 
      } 
     }) 
     .attr("dy", ".71em") 
     .attr("text-anchor", "middle") 
     .text(function(d, i) { return capitalMeta[i]; }) 
     .attr("style","font-size:12px;"); 

me sale el error: TypeError no detectada: No se puede llamar al método ' setProperty 'of null http://mbostock.github.com/d3/d3.js?2.5.0:1707

¿Funcionaría algún tipo de aplicación de navegador sin cabeza, o un analizador js del lado del servidor? ¿Alguien encontró esto antes?

+0

Esta es una gran pregunta, me gustaría que alguien podría responder a ella. – Apollo

Respuesta

0

¿Has probado el mismo código en un navegador compatible con SVG para ver si hay un problema con la vista web? Luego intente this example usando canvg o this one usando la serialización DOM. Para la representación del lado del servidor, puede comenzar con this example para saber cómo renderizarlo en el lado del servidor de Canvas utilizando Node.js.

1

No he probado una biblioteca, pero he renderizado un SVG producido por d3 en un lienzo después de la publicación this en MDN.

Este código es un mish-mash rápido del MDN y algo de jQuery, que tendrá que ordenar, y no tiene ningún error, ni comprobación de plataforma, pero funciona, y espero que ayude .

$(document.body).append(
    '<canvas id="canvas" width="'+diameter+'" height="'+diameter+'"></canvas>' 
); 

// https://developer.mozilla.org/en/docs/HTML/Canvas/Drawing_DOM_objects_into_a_canvas 
var el = $($('svg')[0]); 
var svgMarkup = '<svg xmlns="http://www.w3.org/2000/svg"' 
+ ' class="' + el.attr('class') +'"' 
+ ' width="' + el.attr('width') +'"' 
+ ' height="' + el.attr('height') +'"' 
+ '>' 
+ $('svg')[0].innerHTML.toString()+'</svg>'; 
var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d"); 
var DOMURL = this.URL || this.webkitURL || this; 
var img = new Image(); 
var svg = new Blob([svgMarkup], {type: "image/svg+xml;charset=utf-8"}); 
var url = DOMURL.createObjectURL(svg); 
img.onload = function() { 
    ctx.drawImage(img, 0, 0); 
    alert('ok'); 
    DOMURL.revokeObjectURL(url); 
}; 
img.src = url; 
11

Ésta es una forma que puede escribir su SVG a la lona (y luego guardar el resultado como un png o lo que sea):

// Create an export button 
d3.select("body") 
    .append("button") 
    .html("Export") 
    .on("click",svgToCanvas); 

var w = 100, // or whatever your svg width is 
    h = 100; 

// Create the export function - this will just export 
// the first svg element it finds 
function svgToCanvas(){ 
    // Select the first svg element 
    var svg = d3.select("svg")[0][0], 
     img = new Image(), 
     serializer = new XMLSerializer(), 
     svgStr = serializer.serializeToString(svg); 

    img.src = 'data:image/svg+xml;base64,'+window.btoa(svgStr); 

    // You could also use the actual string without base64 encoding it: 
    //img.src = "data:image/svg+xml;utf8," + svgStr; 

    var canvas = document.createElement("canvas"); 
    document.body.appendChild(canvas); 

    canvas.width = w; 
    canvas.height = h; 
    canvas.getContext("2d").drawImage(img,0,0,w,h); 
    // Now save as png or whatever 
}; 
+0

¡Gran respuesta! También agregué una solución a continuación (basada en la suya) que extrae estilos de hojas de estilo CSS externas. – Constantino

+0

@ace ¿Puedo tener el código completo, por favor, realmente lo necesito – sg28

+0

@ace, tal vez un plnkr/fiddle – sg28

4

La respuesta por @ace es muy bueno, sin embargo, doesn' Manejar el caso de hojas de estilo CSS externas. Mi ejemplo a continuación automáticamente dará un estilo a la imagen generada exactamente como se ve el SVG original, incluso si está tirando estilos de hojas de estilo separadas.

// when called, will open a new tab with the SVG 
// which can then be right-clicked and 'save as...' 
function saveSVG(){ 

    // get styles from all required stylesheets 
    // http://www.coffeegnome.net/converting-svg-to-png-with-canvg/ 
    var style = "\n"; 
    var requiredSheets = ['phylogram_d3.css', 'open_sans.css']; // list of required CSS 
    for (var i=0; i<document.styleSheets.length; i++) { 
     var sheet = document.styleSheets[i]; 
     if (sheet.href) { 
      var sheetName = sheet.href.split('/').pop(); 
      if (requiredSheets.indexOf(sheetName) != -1) { 
       var rules = sheet.rules; 
       if (rules) { 
        for (var j=0; j<rules.length; j++) { 
         style += (rules[j].cssText + '\n'); 
        } 
       } 
      } 
     } 
    } 

    var svg = d3.select("svg"), 
     img = new Image(), 
     serializer = new XMLSerializer(), 

    // prepend style to svg 
    svg.insert('defs',":first-child") 
    d3.select("svg defs") 
     .append('style') 
     .attr('type','text/css') 
     .html(style); 


    // generate IMG in new tab 
    var svgStr = serializer.serializeToString(svg.node()); 
    img.src = 'data:image/svg+xml;base64,'+window.btoa(unescape(encodeURIComponent(svgStr))); 
    window.open().document.write('<img src="' + img.src + '"/>'); 
}; 

Y, para ser completa, el botón que llama a la función:

// save button 
d3.select('body') 
    .append("button") 
    .on("click",saveSVG) 
    .attr('class', 'btn btn-success') 
+0

Esto es muy útil, pero su ejemplo se confunde sobre requiredSheets vs document.styleSheets, que estaba dando lugar a algunos errores para mi. Los arreglé quitando 'var requiredSheets ...' y 'if (requiredSheets.indexOf ...' (lo que significa que puedo eliminar 'var sheetName ...'). Es decir, requiredSheets es innecesario, causa errores y puede ser eliminado con seguridad. –

+0

@Constantino: 'height' y' width' nunca se usan, ¿por qué se les asignan valores? –

+0

Vaya, ese es un viejo código de copiar y pegar ... – Constantino