knockoutJS を使用して SVG を動的にレンダリングしようとしています。つまり、有効な SVG を含む ajax 応答が返されており、svgweb で動的に表示する必要があります。
注- この質問は「自分の質問に答える」機能を使用して作成および回答されたので、次の人が 1 時間ほど検索する時間を節約できることを願っています。
knockoutJS を使用して SVG を動的にレンダリングしようとしています。つまり、有効な SVG を含む ajax 応答が返されており、svgweb で動的に表示する必要があります。
注- この質問は「自分の質問に答える」機能を使用して作成および回答されたので、次の人が 1 時間ほど検索する時間を節約できることを願っています。
この回答で説明されているように、svgweb が公開するappendChildメソッドを使用する必要があります。テキストだけでなく 、実際のノードを受け入れることに注意してください。
作業を簡単にするために、ajax 応答から渡されたノード<xml>
またはノードを取り除くことができます。<doctype>
次に、削除されたテキストを jQuery でラップした後、結果の 0 番目のノードは、に渡すことができる有効な svg ノードである必要があります。appendChild
以下のノックアウト拡張機能は、この機能をまとめたものです。
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 でラップし、結果を追加しようとすると問題が発生することが判明しました。私が見つけた修正は、親 $svg を jQuery でラップし、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);
}
}
}