2011-03-05 107 views
10

我正在使用SVG & JS在Web應用程序上工作。事情進展順利,但我對數據處理有些困惑。通過JavaScript訪問SVG數據

用戶創建的對象數據動態地附加到SVG根目錄。 Where &這個SVG數據如何存儲,&我該如何訪問它?我想閱讀它的原因是我想將這個SVG數據轉換成HTML5畫布(使用Google的canvg),最後將其轉換爲一個PNG圖像存儲在我們的數據庫中供參考。

任何指導將不勝感激。

回答

19

當Web瀏覽器加載SVG文件時,它(粗略地)分析字節流併爲SVG文件在內存中創建DOM結構。正是在腳本動態創建並向文檔添加新元素時修改了這種內存中表示。

您可以在這裏看到的這是一個非常簡單的例子:
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 reference以獲取有關可用屬性和方法的更多信息,或者僅使用DOM 2 Core方法來提取屬性。爲了簡單起見,您可能需要使用後者。

    例如,既可以通過var cx = kid.cx.baseVal.value;訪問當前(非SMIL動畫)使用SVG DOM的圓的cx也可以更簡單地做var cx = kid.getAttribute('cx');

    這將是簡單的,其中SVG和Canvas也有類似的命令(例如rectline),工作一點點,他們不完全匹配(如circlearcTopolyline一系列lineTo命令) ,併爲path元素及其many drawing commands做了大量工作。

  2. this answerthis paper,使用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塊外定義的樣式(如在我的例子),所以他們不會應用在圖像中。

    注意,每this question/answer(礦),則必須之前設置onload屬性如果你想IE9的兼容性,設置src到數據URL。

    不幸的是,由於什麼可能會或可能不會a bug,繪製一個數據URL圖像畫布造成的起源,清潔標誌被設置爲false,這意味着你將無法調用toDataURL()上畫布,並讓你的PNG回來。所以...

  3. 我想爲您的客戶端修改的SVG-> Canvas-> PNG-on-server的特定需求,您需要使用上面的第一步序列化svg_xml,然後將該原始源傳遞給canvg

或者,你可能會考慮每個序列化上面的SVG和提交直接到你的服務器,做server-side SVG-to-PNG conversion

+0

這很奇妙的解釋。非常感謝Phrogz。 – Kayote 2011-03-07 14:03:36

+0

精彩的回答!你還可以指出爲什麼類似* var svg = document.getElementById('svg')*將無法工作...... – 2012-10-30 09:20:49

+0

@KeyBrdBasher這將工作只是找到,假設你有' '在你的頁面上。如果您沒有ID,或者更簡單(在現代瀏覽器上)var svg = document.querySelector('svg')',您可以使用'getElementsByTagName('svg')[0]'。 – Phrogz 2012-10-30 12:54:09

1

在@Phrogz答覆中提到WebKit的錯誤似乎已固定在新的版本,所以我發現不需要人工分析一個解決方案是

// 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 http://stackoverflow.com/questions/4216927/problem-saving-as-png-a-svg-generated-by-raphael-js-in-a-canvas 
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(但這需要添加所需的元數據,這可能會導致缺少問題)。