inet-henge が出力する SVG の変更点
TL; DR
問題: リンクラベルがノードの裏に回ってしまう
これまでのinet-hengeには、上のように「リンクラベルがノードの裏に回ってしまって読めない」問題がありました。
下の2点を満たすためにやむなくこうなっていたものです。
線をノードの裏に隠すために先に定義すると、リンクラベルは線にひきずられてノードの裏に回ってしまっていました。
解決策: リンクを 線レイヤー / ラベルレイヤー に分割する
次のような修正を入れました。
- リンク(線)
- ノード
- リンクラベル(テキスト)
の順に定義することで、リンクラベルだけをノードの表に描画します。SVGに z-index
プロパティがないためこうするしかありませんが、
例: 線をポイントしたとき、ラベルを強調したい
のようなことをCSSで実現できなくなってしまいます。 この部分は後述します。
この修正により、inet-henge が出力する SVG DOM が変わっています。
CSS を適用している場合は、修正する必要があるかもしれません。
SVG DOM
参考までに、SVG DOM の変更点を抜粋します。
これまで
<svg width="960" height="600"> <g> <g transform="translate(-1339.7071035665983,-516.1007538206986) scale(3.4533582342976468)"> <rect width="9600" height="6000" transform="translate(-4800, -3000)" style="opacity: 0;"></rect> <!-- グループ定義 --> <g class="group pop03" transform="translate(462.13786327372185, 31.609395906680902)"> <rect rx="8" ry="8" width="224.02789064247673" height="218.51666231118884" style="fill: rgb(255, 127, 14);"></rect> <text>POP03</text> </g> <!-- リンク定義 --> <g class="path-group"> <line class="link pop03-bb01 pop03-bb02 pop03-bb01-pop03-bb02 " x1="493.13786327372185" y1="183.41381777944147" x2="574.8771135543029" y2="229.12605821786974" stroke="#7a4e4e" stroke-width="3" id="link2" transform="translate(0, 0)"></line> <path class="path" d="M 493.13786327372185 183.41381777944147 L 574.8771135543029 229.12605821786974" id="path2" transform="translate(0, 0)"></path> <text class="path-label" pointer-events="none" style="visibility: visible;" transform="rotate(0)"> <textPath xlink:href="#path2"> <tspan x="20" dy="1.5em" class="interface">ge-0/0/0</tspan> </textPath> </text> <text class="path-label" pointer-events="none" style="visibility: visible;" transform="rotate(0)"> <textPath xlink:href="#path2" class="reverse" text-anchor="end" startOffset="100%"> <tspan x="-20" dy="1.5em" class="interface">Te0/0/0/0</tspan> </textPath> </text> </g> <!-- ノード定義 --> <g id="pop03-bb02" name="POP03-bb02" transform="translate(547.8771135543029, 212.12605821786974)" class="node rect pop03-bb02 "> <rect width="54" height="34" rx="5" ry="5" style="fill: rgb(255, 187, 120);"></rect> <text text-anchor="middle" x="30" y="20"> <tspan x="30">POP03-bb02</tspan> </text> </g> ... </g> </g> </svg>
<line>
要素と <text>
要素が隣接していたため、CSSによる操作が簡単でした。
/* リンクにマウスオーバーしたとき、対応するラベルを操作 */ .link:hover ~ .path-label { ... }
これから
<svg width="960" height="600"> <g> <g transform="translate(-1336.8725605988434,-477.80660514393185) scale(3.448574180070414)"> <rect width="9600" height="6000" transform="translate(-4800, -3000)" style="opacity: 0;"></rect> <!-- グループ定義 --> <g id="groups"> ... <g class="group pop03" transform="translate(462.13786327372185, 31.609395906680902)"> <rect rx="8" ry="8" width="224.02789064247673" height="218.51666231118884" style="fill: rgb(255, 127, 14);"></rect> <text>POP03</text> </g> </g> <!-- リンク定義 --> <g id="links"> ... <g class="link pop03-bb01 pop03-bb02 pop03-bb01-pop03-bb02 "> <line x1="493.13786327372185" y1="183.41381777944147" x2="574.8771135543029" y2="229.12605821786974" stroke="#7a4e4e" stroke-width="3" id="link2" transform="translate(0, 0)"></line> <path d="M 493.13786327372185 183.41381777944147 L 574.8771135543029 229.12605821786974" id="path2" transform="translate(0, 0)"></path> </g> ... </g> <!-- ノード定義 --> <g id="nodes"> ... <g id="pop03-bb02" name="POP03-bb02" transform="translate(547.8771135543029, 212.12605821786974)" class="node rect pop03-bb02 "> <rect width="54" height="34" rx="5" ry="5" style="fill: rgb(255, 187, 120);"></rect> <text text-anchor="middle" x="30" y="20"> <tspan x="30">POP03-bb02</tspan> </text> </g> ... </g> <!-- リンクラベル定義 --> <g id="link-labels"> ... <g class="link pop03-bb01 pop03-bb02 pop03-bb01-pop03-bb02 "> <text class="path2" transform="rotate(0)" style="visibility: visible;"> <textPath xlink:href="#path2"> <tspan x="20" dy="1.5em" class="interface">ge-0/0/0</tspan> </textPath> </text> <text class="path2" transform="rotate(0)" style="visibility: visible;"> <textPath xlink:href="#path2" class="reverse" text-anchor="end" startOffset="100%"> <tspan x="-20" dy="1.5em" class="interface">Te0/0/0/0</tspan> </textPath> </text> </g> ... </g> </g> </g> </svg>
リンク側 <path id="path2">
とラベル側 <text class="path2">
を対応させています。 ひとつの <text/>
に複数 <line/>
というケースがあるため、<text/>
に対応するのはあくまで <path/>
です。
「個別のラベル(テキスト)がどのリンク(線)に対応するか」は表現できますが、「マウスオーバーした線に対応するラベルだけを操作」がCSSだけでは実現できなくなります。
inet-henge に入れたハック
上記の対処のため、線にマウスオーバーした場合は対応するリンクラベル要素に hover
クラスを付与する処理を入れました。十分ではありませんが、とりあえず。
前述のCSSは、👇のように変えれば動きます。
/* リンクにマウスオーバーしたとき、対応するラベルを操作 */ .link text.hover { ... }
サンプル: http://inet-henge.herokuapp.com/issue09.html
また、リンク(線) のスタイルには .link
ではなく .link line
を、ラベルテキストのスタイルには .path-label
ではなく .link text
を使ってください。バージョンアップ後は、おそらく以前の.css ではうまく動かないと思います。
Versioning 始めました
SVG DOM が変更になることで、下位互換が崩れてしまいました 😢
互換性のない変更をいれたのはおそらく初めてのはずですが、いまさらながらCHANGELOG をきちんと書くために今後はVersion を振っていきます。
SVG の z-index property
2009年にProposalが出され、当初は、いまCandidate Recommendationまで進んでいるSVG2で入る予定であったようです。 History を辿ってみると、2018-08-07版 で省かれてしまっています。
当時の議論によれば、「重要なプロパティなのはわかるし、よくリクエストを貰うんだけど、render順 = 定義順 と仮定してしまってる既存コードをチェックして回るのが超大変。SVG2.1 でやるわ」ということのようでした。
z-index
が入ればこのように泥臭いことをやらなくてよくなります。ぜひ欲しいですね! 楽しみに待ちたいと思います。