これを想定して:
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("svg").append('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
});
</script>
</head>
<body>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px">
</svg>
</body>
何も表示されないのはなぜですか?
マークアップ文字列を$
に渡すと、ブラウザの<div>
(または<tr>
などの特別な場合に適したコンテナー)のinnerHTML
プロパティを使用してHTMLとして解析されます。 innerHTML
はSVGやその他のHTML以外のコンテンツを解析できません。また、たとえできたとしても、<circle>
がSVG名前空間にあるはずだと判断することはできません。
innerHTML
はSVGElementでは使用できません。これはHTMLElementのプロパティのみです。現在、コンテンツをSVGElementに解析するinnerSVG
プロパティやその他の方法(*)もありません。このため、DOMスタイルのメソッドを使用する必要があります。 jQueryでは、SVG要素の作成に必要な名前空間付きメソッドに簡単にアクセスできません。本当にjQueryはSVGで使用するように設計されておらず、多くの操作が失敗する可能性があります。
HTML5は、将来、プレーンHTML(<svg>
)ドキュメント内でxmlns
なしでtext/html
を使用できるようにすることを約束します。ただし、これは単なるパーサーハック(**)です。SVGコンテンツはHTML要素ではなく、SVG名前空間のSVGElementのままなので、innerHTML
を使用することはできません HTMLドキュメントの一部のようなlook。
ただし、現在のブラウザでは、XHTML(適切にapplication/xhtml+xml
として提供されます。ローカルテスト用に.xhtmlファイル拡張子で保存)を使用してSVGを取得する必要がありますまったく働かない。 (とにかく理にかなっています。SVGは適切なXMLベースの標準です。)これは、スクリプトブロック内で<
シンボルをエスケープ(またはCDATAセクションで囲む)し、XHTML xmlns
宣言を含める必要があることを意味します。例:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head>
</head><body>
<svg id="s" xmlns="http://www.w3.org/2000/svg"/>
<script type="text/javascript">
function makeSVG(tag, attrs) {
var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
for (var k in attrs)
el.setAttribute(k, attrs[k]);
return el;
}
var circle= makeSVG('circle', {cx: 100, cy: 50, r:40, stroke: 'black', 'stroke-width': 2, fill: 'red'});
document.getElementById('s').appendChild(circle);
circle.onmousedown= function() {
alert('hello');
};
</script>
</body></html>
*:まあ、DOM Level 3 LSの parseWithContext がありますが、ブラウザのサポートは非常に貧弱です。編集して追加します。ただし、SVGElementにマークアップを挿入することはできませんが、innerHTML
を使用して新しいSVGElementをHTMLElementに挿入し、目的のターゲットに転送できます。ただし、少し遅くなります。
<script type="text/javascript"><![CDATA[
function parseSVG(s) {
var div= document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+s+'</svg>';
var frag= document.createDocumentFragment();
while (div.firstChild.firstChild)
frag.appendChild(div.firstChild.firstChild);
return frag;
}
document.getElementById('s').appendChild(parseSVG(
'<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" onmousedown="alert(\'hello\');"/>'
));
]]></script>
**:HTML5の作成者がXMLを怖がっており、XMLベースの機能をHTMLであるこっけいな混乱に陥れることにしたと思われる方法が嫌いです。 XHTMLはこれらの問題を数年前に解決しました。
受け入れられた答え は複雑すぎる方法を示しています。 Forrestoが his answer で主張しているように、「DOMエクスプローラーで追加するようですが、画面上では追加しないようです "で、この理由はhtmlとsvg。
最も簡単な回避策は、svg全体を「更新」することです。円(または他の要素)を追加した後、これを使用します。
$("body").html($("body").html());
これがトリックです。円は画面上にあります。
または、必要に応じて、コンテナdivを使用します。
$("#cont").html($("#cont").html());
そして、コンテナdiv内にsvgをラップします。
<div id="cont">
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px">
</svg>
</div>
機能的な例:
http://jsbin.com/ejifab/1/edit
この手法の利点:
$('svg').prepend('<defs><marker></marker><mask></mask></defs>');
。$("#cont").html($("#cont").html());
を使用して要素が追加され、画面に表示されると、jQueryを使用して属性を編集できます。編集:
上記の手法は、「ハードコーディング」またはDOM操作(= document.createElementNSなど)SVGのみで機能します。 Raphaelを要素の作成に使用する場合(私のテストによれば)、$("#cont").html($("#cont").html());
を使用すると、RaphaelオブジェクトとSVG DOM間のリンクが切断されます。これを回避するには、$("#cont").html($("#cont").html());
を使用せず、代わりにダミーのSVGドキュメントを使用します。
このダミーのSVGは、最初はSVGドキュメントのテキスト表現であり、必要な要素のみが含まれています。例えばRaphaelドキュメントにフィルター要素を追加するには、ダミーを<svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg>
のようにします。テキスト表現は、最初にjQueryの$( "body")。append()メソッドを使用してDOMに変換されます。 (フィルター)要素がDOMにある場合、標準のjQueryメソッドを使用して照会し、Raphaelによって作成されたメインのSVGドキュメントに追加できます。
なぜこのダミーが必要なのですか? Raphaelが作成したドキュメントに厳密にフィルター要素を追加しないのはなぜですか?たとえばを使用して試してみると$("svg").append("<circle ... />")
、html要素として作成され、回答に記載されているように画面上に何も表示されません。 しかし、SVGドキュメント全体が追加される場合、ブラウザはSVGドキュメント内のすべての要素の名前空間変換を自動的に処理します。
テクニックを理解する例:
// Add Raphael SVG document to container element
var p = Raphael("cont", 200, 200);
// Add id for easy access
$(p.canvas).attr("id","p");
// Textual representation of element(s) to be added
var f = '<filter id="myfilter"><!-- filter definitions --></filter>';
// Create dummy svg with filter definition
$("body").append('<svg id="dummy" style="display:none"><defs>' + f + '</defs></svg>');
// Append filter definition to Raphael created svg
$("#p defs").append($("#dummy filter"));
// Remove dummy
$("#dummy").remove();
// Now we can create Raphael objects and add filters to them:
var r = p.rect(10,10,100,100);
$(r.node).attr("filter","url(#myfilter)");
このテクニックの完全なデモはこちらにあります: http://jsbin.com/ilinan/1/edit 。
(Raphaelを使用しているときに$("#cont").html($("#cont").html());
が動作しない理由は(まだ)わかりません。非常に短いハックです。)
人気が高まっている D ライブラリは、svgの追加/操作の奇妙な点を非常にうまく処理します。ここで説明したjQueryハックとは対照的に、使用を検討してください。
HTML
<svg xmlns="http://www.w3.org/2000/svg"></svg>
Javascript
var circle = d3.select("svg").append("circle")
.attr("r", "10")
.attr("style", "fill:white;stroke:black;stroke-width:5");
JQueryは、要素を<svg>
に追加できません(DOMエクスプローラーで要素を追加するようですが、画面では追加しません)。
1つの回避策は、ページに必要なすべての要素に<svg>
を追加し、.attr()
を使用して要素の属性を変更することです。
$('body')
.append($('<svg><circle id="c" cx="10" cy="10" r="10" fill="green" /></svg>'))
.mousemove( function (e) {
$("#c").attr({
cx: e.pageX,
cy: e.pageY
});
});
誰かがこのメソッドに言及しているのを見たことはありませんが、この場合はdocument.createElementNS()
が役立ちます。
正しい名前空間を持つ通常のDOMノードとしてVanilla Javascriptを使用して要素を作成し、そこからjQuery化できます。そのようです:
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
var $circle = $(circle).attr({ //All your attributes });
$(svg).append($circle);
唯一の欠点は、適切な名前空間を使用して各SVG要素を個別に作成する必要があることです。そうしないと機能しません。
私が持っているすべてのブラウザ(Chrome 49、Edge 25、Firefox 44、IE11、Safari 5 [Win]、Safari 8(MacOS))で動作する簡単な方法を見つけました。
// Clean svg content (if you want to update the svg's objects)
// Note : .html('') doesn't works for svg in some browsers
$('#svgObject').empty();
// add some objects
$('#svgObject').append('<polygon class="svgStyle" points="10,10 50,10 50,50 10,50 10,10" />');
$('#svgObject').append('<circle class="svgStyle" cx="100" cy="30" r="25"/>');
// Magic happens here: refresh DOM (you must refresh svg's parent for Edge/IE and Safari)
$('#svgContainer').html($('#svgContainer').html());
.svgStyle
{
fill:cornflowerblue;
fill-opacity:0.2;
stroke-width:2;
stroke-dasharray:5,5;
stroke:black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="svgContainer">
<svg id="svgObject" height="100" width="200"></svg>
</div>
<span>It works if two shapes (one square and one circle) are displayed above.</span>
私はFirefoxで2つのことをして円を見ることができます:
1)ファイルの名前をhtmlからxhtmlに変更する
2)スクリプトを変更
<script type="text/javascript">
$(document).ready(function(){
var obj = document.createElementNS("http://www.w3.org/2000/svg", "circle");
obj.setAttributeNS(null, "cx", 100);
obj.setAttributeNS(null, "cy", 50);
obj.setAttributeNS(null, "r", 40);
obj.setAttributeNS(null, "stroke", "black");
obj.setAttributeNS(null, "stroke-width", 2);
obj.setAttributeNS(null, "fill", "red");
$("svg")[0].appendChild(obj);
});
</script>
@ chris-dolphinの回答に基づいていますが、ヘルパー関数を使用しています:
// Creates svg element, returned as jQuery object
function $s(elem) {
return $(document.createElementNS('http://www.w3.org/2000/svg', elem));
}
var $svg = $s("svg");
var $circle = $s("circle").attr({...});
$svg.append($circle);
追加する必要がある文字列がSVGであり、適切なネームスペースを追加する場合、文字列をXMLとして解析し、親に追加できます。
var xml = jQuery.parseXML('<circle xmlns="http://www.w3.org/2000/svg" cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
$("svg").append(xml.documentElement))
Bobinceが受け入れた答えは、短くてポータブルなソリューションです。 SVGを追加するだけでなく、それを操作する必要がある場合は、 JavaScriptライブラリ "Pablo" (私が書いた)を試すことができます。 jQueryユーザーには馴染みがあります。
コード例は次のようになります。
$(document).ready(function(){
Pablo("svg").append('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
});
マークアップを指定せずに、その場でSVG要素を作成することもできます。
var circle = Pablo.circle({
cx:100,
cy:50,
r:40
}).appendTo('svg');
Ajaxを使用して、別のページからsvg要素をロードする方が良いかもしれません。
$('.container').load(href + ' .svg_element');
Hrefは、svgのあるページの場所です。これにより、htmlコンテンツの置き換えによって生じる可能性のある不安的な影響を回避できます。また、ロード後にsvgをアンラップすることを忘れないでください:
$('.svg_element').unwrap();
これは今日FF 57で機能しています:
function () {
// JQuery, today, doesn't play well with adding SVG elements - tricks required
$(selector_to_node_in_svg_doc).parent().prepend($(this).clone().text("Your"));
$(selector_to_node_in_svg_doc).text("New").attr("x", "340").text("New")
.attr('stroke', 'blue').attr("style", "text-decoration: line-through");
}
作ります:
var svg; // if you have variable declared and not assigned value.
// then you make a mistake by appending elements to that before creating element
svg.appendChild(document.createElement("g"));
// at some point you assign to svg
svg = document.createElementNS('http://www.w3.org/2000/svg', "svg")
// then you put it in DOM
document.getElementById("myDiv").appendChild(svg)
// it wont render unless you manually change myDiv DOM with DevTools
// to fix assign before you append
var svg = createElement("svg", [
["version", "1.2"],
["xmlns:xlink", "http://www.w3.org/1999/xlink"],
["aria-labelledby", "title"],
["role", "img"],
["class", "graph"]
]);
function createElement(tag, attributeArr) {
// .createElementNS NS is must! Does not draw without
let elem = document.createElementNS('http://www.w3.org/2000/svg', tag);
attributeArr.forEach(element => elem.setAttribute(element[0], element[1]));
return elem;
}
// extra: <circle> for example requires attributes to render. Check if missing.