下のtext要素をクリックしてごらん、なんと編集できるよ!!
私はtext要素。でも編集できるよ! (クリックしてみ)
わかる人向け: 仕組みを一言でいうと
contentEditableなHTML要素の下にtext要素を配置し、このセットをforeignObjectへ入れてSVG 要素下に吊るす.
仕組み
contentEditable
HTML5 にはcontentEditable という属性がある。
<div contenteditable>編集可能</div>
のように属性を付与すると、
divが編集可能 (クリックしてみ)
になる.
SVG のcontentEditable
contentEditableがSVG で使えれば万々 歳、なのだが、使えない...
(次のSVG に導入しようぜ、という提案はされてたりする Add `contenteditable` attribute for SVG text elements · Issue #332 · w3c/svgwg · GitHub )
\\動かない例
<svg>
<text contenteditable>SVGは編集不可 (クリックしても無駄無駄、無駄ァ)</text>
</svg>
SVG は編集不可 (クリックしても無駄無駄、無駄ァ)
しかし嬉しいことに、contentEditableなHTML要素の下にSVG 要素を配置すると, contentEditableが引き継がれる
https://github.com/w3c/svgwg/issues/332 (標準化された動作じゃない...と思う)
なので
<div contenteditable>
<text>divに入れるとSVGを編集可能</text> // SVGのtext要素
</div>
とすると、
divに入れるとSVG を編集可能 (クリックしてみ)
になる.
やったねたえちゃん、SVG が編集できるよ
foreignObject
ここで問題になるのが<svg >下のHTML要素 .
おそらくこのページに来た人は、SVG で作りこんだ図に編集可能textを入れ込みたいのだと思う.
つまり、<svg >要素下にrectやらcircleやら置いてあることになる.
textを編集可能にするために、上記の<div contenteditable>を利用すればよいわけだが...
<svg >下にHTML要素(例えば<div>)を置くことはできない javascript - How to append div tag into a SVG rect element? - Stack Overflow
そこで登場するのがforeignObject .
この要素を配置するとあら不思議、HTML要素をforeignObject下に配置しても無問題!!
よって
<svg>
<foreignObject>
<div contenteditable>
<text>私はtext要素。でも編集できるよ! (クリックしてみ)</text>
</div>
</foreignObject>
</svg>
のようにすれば、
私はtext要素。でも編集できるよ! (クリックしてみ)
となる。
問題点
contentEditableはあくまでHTML属性
SVG の仕様で定められた、互換性のあるものではない
foreignObject要素への対応
一部のブラウザでforeignObject要素を適切に処理できない場合があるとかないとか
まとめ
foreignObject下にcontentEditable HTML要素、その下にtextを置けば編集できる
互換性などの点でベストとはとても言い難いよ、でも便利だね
おまけ
d3.jsと組み合わせると
HTML, non-contentEditable
HTML contentEditable
HTML, non-contentEditable. But enabled by d3.js!!
<div id="divv2">HTML, non-contentEditable. But enabled by d3.js!!</div>
d3.select("#divv2").attr("contenteditable", true);
d3.select("#svgEdit" )
.append("foreignObject" )
.attr("width" , 600)
.attr("height" , 50)
.append("xhtml:div" )
.attr("contenteditable" , true )
.append("text" )
.text("dynamic editable text by d3.js!!!" );