読者です 読者をやめる 読者になる 読者になる

銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

SVGの重なり順序を操作する「svg-z-order」

JavaScriptで、SVG要素の重なり順(Z-Order)を操作するモジュール svg-z-order をnpmで公開したのでご紹介。

SVGの図形の要素はドキュメント内での定義順に、奥から手前へ向けて描画されますが、 これを変更するには要素を並べ替えるしかありません。 HTML/CSSのz-indexスタイルのような方法が(今のところ?)無いのです。

並べ替えはSVGに限らず、DOMのNodeクラスinsertBeforeメソッドを使うのですが、数値指定の z-index ほど、お手軽ではありませんので、この(↓)モジュールを作りました。

f:id:takamints:20170423172653p:plain

使い方

特定要素を最前面へ持ってくるコードを、ちょっと冗長に書いてみた。

//モジュール取得
var svgz = require("svg-z-order");// (1)

//SVG要素 g#foo を最前面へ表示
var g = svg.getElementById("foo");
var svgzG = svgz.element(g); //(2)
svgzG.toTop(); //(3)
 
// D3.jsで使う(4)
var d3 = require("d3");
var d3g = d3.select("#foo");
svgz.element(d3g.node()).toTop();
  1. モジュールをインポートして、
  2. element メソッドで、DOM要素を参照するインスタンスを作り
  3. 最前面へ表示します。
  4. D3.jsを使っていますが、例として書いているだけで、依存関係はありません。

上の例では、Browserifyを使って、 var svgz = require("svg-z-orger");でモジュールを取り込んでいますが、 HTMLで<script src="svg-z-order.js"/>としている場合は、 (2)の行の svgz.element(g) を、 svgz_element(g) に変更して下さい。 requireできない環境ではグローバルスコープに定義します。

API

element(e:Element)

SVG要素を参照する SVGZElement クラスのインスタンスを返します。 Z-Orderを操作するAPIは SVGZElementクラスのメソッドです。

パラメータ

  • e:Element - 参照するDOM要素を指定します。

SVGZElementクラス

SVGZElement.toTop()

参照している要素を最前面に移動。

SVGZElement.toBottom()

参照している要素を最背面に移動。

SVGZElement.moveUp(e:Element / n:number)

参照している要素を上(前面)へ移動。

パラメータ

  • e:Element - この要素よりも上になるように移動します。
  • n:number - 要素の並びの中でこの回数分だけ上へ移動します。

要素を指定したときはその要素よりも上へ。数値指定した場合は、その回数だけ上へ移動。

SVGZElement.moveDown(e:Element / n:number)

参照している要素を下(背面)へ移動。

パラメータ

  • e:Element - この要素よりも下になるように移動します。
  • n:number - 要素の並びの中でこの回数分だけ下へ移動します。

要素を指定したときはその要素よりも下へ。数値指定の場合は、その回数だけ下へ移動。

サンプル

ドロップダウンでメソッドを選んで、円をクリックするとメソッドを適用します。

コードはこちら:/sample/web/index.js

リポジトリ

www.npmjs.com

github.com

いくつになってもお勉強

JavaScriptのプログラムからSVG要素を最前面へもってくる方法を検索したら、結構微妙な情報が出てきました。

曰く、

  1. SVG単体では不可能なので、HTMLのDIVにSVGを書いて重ね合わせて、DIVのz-indexで制御するしかありません。
  2. 対象のSVG要素をディープコピーして appendChild 。元要素は removeChild。

こういう情報を見て、当初「なるほどヤヤコシイなー」と思ったのですが、どうにも納得がいきませんで、いろいろやってみているとDOMの標準機能で可能と判明。

いくつになってもお勉強です。

微妙な説明を信じちゃうのは、Node.appendChildNode.insertBeforeは、既にDOMツリーにある要素を移動してくれるということをしっかり認識できていないということでしょう。自分も今まで「追加、挿入」ってイメージしか持っていませんでしたので。

広告を非表示にする