2013-10-12 34 views
0

我想動態渲染一些SVG與knockoutJS。換句話說,ajax響應會返回有效的SVG,並且我希望svgweb動態顯示它。使用SVGWeb與KnockoutJS - 動態添加SVG


注意 - 這個問題被寫與回答回答自己的問題功能,這樣我就可以有希望救下的人一個小時左右的搜索。

回答

1

this answer描述,您需要使用appendChild方法svgweb自曝。請注意,它接受實際的節點,而不僅僅是文本。

爲了使事情變得簡單,您可以去掉任何從您的ajax響應中傳出的<xml><doctype>節點。然後,包裝用jQuery剝離文本之後,結果的第0節點應該是可以傳遞給appendChild

下面的淘汰賽擴展包裝了這個功能有效的SVG節點。

ko.bindingHandlers.renderSvg = { 
    init: renderSvg, 
    update: renderSvg 
}; 

function renderSvg(element, valueAccessor, allBindingsAccessor, viewModel) { 
    var rawVal = valueAccessor(); 
    var svgText = ko.utils.unwrapObservable(rawVal); 

    if (!svgText) { 
     element.innerHTML = ''; 
    } else { 
     //clear out previous content 
     element.innerHTML = ''; 

     //strip out any `<xml>` or <!doctype> tags that come over 
     if (svgText.indexOf('<svg') > 0){ 
      svgText = svgText.substr(svgText.indexOf('<svg')); 
     } 
     window.svgweb.appendChild($(svgText)[0], element); 
    } 
}; 

當然,被稱爲有:

<div data-bind="renderSvg: mySvgField"></div> 

編輯

原來包裝是SVG字符串使用jQuery,並試圖追加的結果會引起問題。我發現的修補程序是用jQuery包裝父級$ svg,然後使用jQuery遍歷所有子級。天真的1級搜索對我來說已經足夠了。顯然更復雜的用例需要遞歸搜索。更新後的代碼如下。

function renderSvg(element, valueAccessor, allBindingsAccessor, viewModel) { 
    var rawVal = valueAccessor(); 
    var svgText = ko.utils.unwrapObservable(rawVal); 

    if (!svgText) { 
     element.innerHTML = ''; 
    } else { 
     element.innerHTML = ''; 

     if (svgText.indexOf('<svg') > 0){ 
      svgText = svgText.substr(svgText.indexOf('<svg')); 
     } 

     if (!$.browser.msie || $.browser.version > 8){ 
      //normal browsers 
      window.svgweb.appendChild($(svgText)[0], element); 
     } else { 
      //IE 8 
      var $svg = $(svgText); 
      var svg = document.createElementNS(svgns, 'svg'); 

      svg.setAttribute('width', $svg.attr('width')); 
      svg.setAttribute('height', $svg.attr('height')); 

      $.each($svg.children(), function(i, el){ 
       var path = document.createElementNS(svgns, el.tagName); 

       for (var i = 0, allAttributes = el.attributes, len = allAttributes.length; i < len; i++){ 
        path.setAttribute(allAttributes.item(i).nodeName, allAttributes.item(i).nodeValue); 
       } 
       svg.appendChild(path); 
      }); 
      window.svgweb.appendChild(svg, element); 
     } 
    } 
}