Доступ к данным SVG через JavaScript - PullRequest
11 голосов
/ 05 марта 2011

Я работаю над веб-приложением, использующим SVG & JS. Все идет хорошо, но меня немного смущает обработка данных.

Данные для объектов, создаваемых пользователями, динамически добавляются в корень SVG. Где и как хранятся данные SVG, и как я могу получить к ним доступ? Причина, по которой я хочу это прочитать, заключается в том, что я хочу преобразовать эти данные SVG в холст HTML5 (используя canvg от Google) и, наконец, превратить его в изображение png, которое будет храниться в нашей базе данных для справки.

Любое руководство будет высоко ценится.

Ответы [ 2 ]

20 голосов
/ 06 марта 2011

Когда веб-браузер загружает файл SVG, он (приблизительно) анализирует поток байтов и создает структуру DOM в памяти для файла SVG.Именно это представление в памяти изменяется, когда скрипт динамически создает и добавляет новые элементы в документ.

Здесь вы можете увидеть очень простой пример:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
SVGфайл загружается с кругом на заднем плане для лица, а затем JavaScript динамически создает глаза и нос и добавляет их в качестве дочерних элементов элемента SVG.

Есть три способа, которыми я знаю, что вы можете получить доступ к этой информациии поместите его в холст:

  1. Вы можете самостоятельно пройти DOM-элементы и выполнить команды рисования контекста холста:

    var svg = document.getElementsByTagName('svg')[0];
    var kids = svg.childNodes;
    for (var i=0,len=kids.length;i<len;++i){
      var kid = kids[i];
      if (kid.nodeType!=1) continue; // skip anything that isn't an element
      switch(kid.nodeName){
        case 'circle':
          // ...
        break;
        case 'path':
          // ...
        break;
        // ...
      }
    }
    

    См. SVGСсылка DOM для получения дополнительной информации о доступных свойствах и методах или просто использование методов DOM 2 Core для получения свойств.Для простоты вы можете использовать последнее.

    Например, вы можете либо получить доступ к текущему (не SMIL-анимированному) cx круга, используя SVG DOM через var cx = kid.cx.baseVal.value;, либо вы можете большепросто сделайте var cx = kid.getAttribute('cx');.

    Это будет просто, когда SVG и Canvas имеют похожие команды (например, rect или line), небольшая работа, где они не совпадают точно (например,circle против arcTo, polyline в виде последовательности lineTo команд) и много работы для элемента path и его многих команд рисования .

  2. За этот ответ и этот документ , используйте интерфейс XMLSerializer, чтобы вернуть SVG в качестве разметки, используйте его непосредственно как источник imgи затем drawImage это на холст.Используя мой пример выше:

    var svg_xml = (new XMLSerializer).serializeToString(svg);
    console.log(svg_xml);
    // "<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" viewBox="-350 -250 700 500">
    // <circle r="200" class="face" fill="red"/>
    // <path fill="none" class="face" transform="translate(-396,-230)" d="M487.41,282.411c-15.07,36.137-50.735,61.537-92.333,61.537         c-41.421,0-76.961-25.185-92.142-61.076"/>
    // <circle cx="-60" cy="-50" r="20" fill="#000"/>
    // <circle cx="60" cy="-50" r="20" fill="#000"/>
    // </svg>"
    var ctx = myCanvas.getContext('2d');
    var img = new Image;
    img.onload = function(){ ctx.drawImage(img,0,0); };
    img.src = "data:image/svg+xml;base64,"+btoa(svg_xml);
    

    Если у вас есть SVG в XHTML (как в моем примере), сериализация не будет захватывать стили, определенные за пределами блока SVG (как в моем примере), и поэтому они не будут

    Обратите внимание, что для этот вопрос / ответ (мой), вы должны установить атрибут onload до того, как вы установите srcк URL-адресу данных, если вы хотите совместимости с IE9.

    К сожалению, из-за того, что может или не может быть ошибка , рисование изображения URL-адреса на холсте вызывает флаг origin-cleanбыть установленным на false, что означает, что вы не сможете вызвать toDataURL() на холсте и получить свой PNG обратно.Итак ...

  3. Полагаю, для ваших конкретных потребностей в SVG-> Canvas-> PNG-на-сервере, модифицированном клиентом, вам потребуется использовать первый шаг, описанный выше, для сериализации svg_xml и затем передайте этот необработанный источник в canvg .

В качестве альтернативы, вы можете рассмотреть сериализацию SVG в соответствии с вышеприведенным и передать ее непосредственно на сервер и выполнить преобразование SVG в PNG на стороне сервера .

1 голос
/ 16 марта 2013

Ошибка webkit, упомянутая в ответе @Phrogz, по-видимому, была исправлена ​​в более поздних версиях, поэтому я нашел решение, которое не требует ручного анализа:

// from http://bl.ocks.org/biovisualize/1209499
// via https://groups.google.com/forum/?fromgroups=#!topic/d3-js/RnORDkLeS-Q
var xml = d3.select("svg")
  .attr("title", "test2")
  .attr("version", 1.1)
  .attr("xmlns", "http://www.w3.org/2000/svg")
  .node().parentNode.innerHTML;

// from http://webcache.googleusercontent.com/search?q=cache:http://phpepe.com/2012/07/export-raphael-graphic-to-image.html
// via /2600282/problema-sohraneniya-kak-png-svg-sgenerirovannogo-raphael-js-na-holste
var canvas = document.getElementById("myCanvas")
canvg(canvas, svgfix(xml));
document.location.href = canvas.toDataURL();

, для которого требуется https://code.google.com/p/svgfix/ и https://code.google.com/p/canvg/ и использует d3.js для получения источника svg, что также должно быть выполнимо без d3.js (но при этом необходимо добавить необходимые метаданные, которые могут привести к проблемам при отсутствии).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...