SVG к холсту с d3.js

Кто-нибудь пытался использовать svg в библиотеке canvas при создании визуализации d3.js? Я попытался использовать canvg.js и d3.js для преобразования svg в canvas из приложения web-приложения приложения android 2.3, но когда я звоню:

  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;");

Я получаю сообщение об ошибке: Uncaught TypeError: Невозможно вызвать метод setProperty из null http://mbostock.github.com/d3/d3.js?2.5.0:1707

Будет ли какое-нибудь приложение без браузера браузера или парсер JS на стороне сервера? Кто-нибудь сталкивался с этим раньше?

Ответ 1

Здесь вы можете написать свой svg на холст (а затем сохранить результат как png или что-то еще):

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

Ответ 2

Ответ от @ace очень хороший, однако он не обрабатывает внешние таблицы стилей CSS. Мой пример ниже автоматически сгенерирует сгенерированное изображение точно так, как выглядит оригинальный SVG, даже если он потянет стили из отдельных таблиц стилей.

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

И, чтобы быть полным, кнопка, вызывающая функцию:

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

Ответ 3

Я не пробовал библиотеку, но предоставил SVG, созданный d3, на холст, после этого сообщения в MDN.

Этот код является быстрым mish-mash из MDN и некоторого jQuery, который вам нужно будет убрать, и у него нет ошибок или проверки, но он работает, и я надеюсь, что это поможет.

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

Ответ 4

Вы пробовали один и тот же код в браузере, поддерживающем SVG, чтобы узнать, есть ли проблема с webview? Затем попробуйте этот пример, используя canvg или этот, используя сериализацию DOM, Для рендеринга на стороне сервера вы можете начать с в этом примере для того, как отобразить его на холсте на стороне сервера, используя Node.js.