0

knockoutJS を使用して SVG を動的にレンダリングしようとしています。つまり、有効な SVG を含む ajax 応答が返されており、svgweb で動的に表示する必要があります。


- この質問は「自分の質問に答える」機能を使用して作成および回答されたので、次の人が 1 時間ほど検索する時間を節約できることを願っています。

4

1 に答える 1

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);
        }
    }
}
于 2013-10-12T20:05:25.690 に答える