2012-07-19 14 views
11

Qualcuno ha provato a utilizzare una libreria svg su tela durante la creazione di visualizzazioni d3.js? Ho cercato di usare canvg.js e d3.js per convertire svg tela all'interno di un androide WebView 2.3 applicazione, ma quando chiamo:SVG su tela 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;"); 

ottengo l'errore: TypeError Uncaught: Impossibile chiamare il metodo ' setProperty 'di null http://mbostock.github.com/d3/d3.js?2.5.0:1707

Sarebbe una specie di applicazione browser senza testa o un parser lato server js? Qualcuno l'ha già incontrato prima?

+0

Questa è una grande domanda così, vorrei che qualcuno avrebbe rispondere. – Apollo

risposta

0

Hai provato lo stesso codice su un browser che supporta SVG per vedere se si tratta di un problema con Webview? Quindi provare this example utilizzando canvg o this one utilizzando la serializzazione DOM. Per il rendering lato server, è possibile iniziare con this example per come eseguirne il rendering su tela lato server utilizzando Node.js.

1

Non ho provato una libreria, ma ho reso un SVG prodotto da d3 su una tela dopo il post this su MDN.

Questo codice è un rapido miscuglio di MDN e alcuni jQuery, che sarà necessario riordinare e non ha errori o controllo di piattaforma, ma funziona, e spero che aiuti .

$(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

Ecco un modo si potrebbe scrivere il vostro svg tela (e quindi salvare il risultato come un png o qualsiasi altra cosa):

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

Ottima risposta! Ho anche aggiunto una soluzione di seguito (in base alla tua) che richiama gli stili da fogli di stile CSS esterni. – Constantino

+0

@ace posso avere il codice completo, per favore, ne ho davvero bisogno – sg28

+0

@ace, forse un plnkr/fiddle – sg28

4

La risposta da @ace è molto buona, tuttavia doesn' t gestire il caso di fogli di stile CSS esterni. Il mio esempio qui di seguito modellerà automaticamente l'immagine generata esattamente come appare l'SVG originale, anche se sta tracciando stili da fogli di stile separati.

// 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 + '"/>'); 
}; 

E, per essere completa, il pulsante che chiama la funzione:

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

Questo è molto utile, ma il tuo esempio è confuso su requiredSheets vs document.styleSheets, che stava portando ad alcuni errori per me. Li ho risolti rimuovendo 'var requiredSheets ...' e 'if (requiredSheets.indexOf ...' (il che significa che posso rimuovere 'var sheetName ...'). Cioè, requiredSheets non è necessario, causa bug e può –

+0

@Constantino: 'height' e' width' non vengono mai utilizzati - perché sono assegnati valori? –

+0

Oops, questo è un vecchio codice copia e incolla ... – Constantino