下のtext要素をクリックしてごらん、なんと編集できるよ!!
わかる人向け: 仕組みを一言でいうと
contentEditableなHTML要素の下にtext要素を配置し、このセットをforeignObjectへ入れてSVG要素下に吊るす.
仕組み
contentEditable
HTML5にはcontentEditableという属性がある。
<div contenteditable>編集可能</div>
のように属性を付与すると、
になる.
SVGのcontentEditable
contentEditableがSVGで使えれば万々歳、なのだが、使えない...
(次のSVGに導入しようぜ、という提案はされてたりする Add `contenteditable` attribute for SVG text elements · Issue #332 · w3c/svgwg · GitHub)
\\動かない例 <svg> <text contenteditable>SVGは編集不可 (クリックしても無駄無駄、無駄ァ)</text> </svg>
しかし嬉しいことに、contentEditableなHTML要素の下にSVG要素を配置すると, contentEditableが引き継がれる
https://github.com/w3c/svgwg/issues/332 (標準化された動作じゃない...と思う)
なので
<div contenteditable> <text>divに入れるとSVGを編集可能</text> // SVGのtext要素 </div>
とすると、
になる.
やったねたえちゃん、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>
のようにすれば、
となる。
問題点
- contentEditableはあくまでHTML属性
- SVGの仕様で定められた、互換性のあるものではない
- foreignObject要素への対応
- 一部のブラウザでforeignObject要素を適切に処理できない場合があるとかないとか
まとめ
- foreignObject下にcontentEditable HTML要素、その下にtextを置けば編集できる
- 互換性などの点でベストとはとても言い難いよ、でも便利だね
おまけ
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!!!");