LGTM

Looks Good To Me

inet-henge が出力する SVG の変更点

TL; DR

  • リンクラベルをノードの上に描画するため、SVG DOM 構造を変えました
  • CSS を適用している場合は、修正する必要があるかもしれません
  • いまさらですがVersioning 始めます

問題: リンクラベルがノードの裏に回ってしまう

これまでのinet-hengeには、上のように「リンクラベルがノードの裏に回ってしまって読めない」問題がありました。

下の2点を満たすためにやむなくこうなっていたものです。

  1. SVGの仕様では、後に定義された要素が表に描画される
  2. CSSでうまく選択できるよう、リンク(線) とリンクラベル(テキスト) を近くに配置したい
    • 例: 線をポイントしたとき、ラベルを強調したい

線をノードの裏に隠すために先に定義すると、リンクラベルは線にひきずられてノードの裏に回ってしまっていました。

解決策: リンクを 線レイヤー / ラベルレイヤー に分割する

次のような修正を入れました。

  1. リンク(線)
  2. ノード
  3. リンクラベル(テキスト)

の順に定義することで、リンクラベルだけをノードの表に描画します。SVGz-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 が入ればこのように泥臭いことをやらなくてよくなります。ぜひ欲しいですね! 楽しみに待ちたいと思います。