SVGとは
簡単に言うとブラウザ上でベクター画像描画する形式のことです
ビットマップでないので拡大や高解像度ディスプレイでもぼやけないのが特徴で、曲線的な表現に優れています
また実態はコードなのでcssやJavaScriptで動かすことも可能です
https://developer.mozilla.org/ja/docs/Web/SVG
なんで使おうと思ったの?
弊社のフロー画面ではもともとjQueryとcssストライプでアイコンの色を変えたり配管の表現をしたりしてました
しかし顧客から変更が来るたびに絵を書き直したりスクリプト書き直したりするなどなにかとメンテに手間がかかり変更に弱い
センサー値の表示は結局pタグ書いてposition:absolute;で調整して
何より僕がposition:absolute;が嫌いなのでなんかいい方法ないかなーと思ってたどり着いた方法です
illustratorでSVG画像を作ってみよう
イラレの使い方についてはこちらのyoutubeが一番わかりやすかったですので全くわからない方はまずご覧ください
https://www.youtube.com/playlist?list=PLnDOZwrKSOzamEi7Mc0wVyw3kfrKsvj5g&pbjreload=102
ポンプアイコンを描いてみる
丸と三角を合体
まずはベースとなるパーツを合体させます
パスファインダーの合体を使います
テキストをアウトライン化
アウトライン化についてはこちら
要するにテキスト要素をオブジェクトに変換してます
これをしないとほかのパスと合体できないので
複合パス化
すると白丸部分が消えてPが緑になりました
パスファインダーのナカ窓との違いについて、違いは処理後に一つのパスになるか別々になるかです
アイコンなので一つのパスとしてセットになるのが望ましいので今回は複合パスとしました
あとは白丸をPの背景に据えて完成です
svgとして書き出す
それではsvgとして書き出してみましょう
ファイル>書き出し>書き出し形式...
そのままOKを押せばsvg形式で書き出されます
余談ですが、小数点以下の桁数は書き出しの解像度?らしく、小さいと崩れが起きて大きいと容量が重くなるそうです
ブラウザで見てみる
ブラウザでファイルを開くと作成したアイコンが表示されます
テキストエディタで開くと以下のようになっています
ellipseが背景の白丸、pathが緑の複合パスです
<svg id="レイヤー_1" data-name="レイヤー 1" xmlns="http://www.w3.org/2000/svg" width="262" height="284" viewBox="0 0 262 284">
<ellipse cx="130" cy="130.5" rx="118.5" ry="117.5" fill="#fff"/>
<path d="M245.218,256.911,290.5,310H29.5l45.7-53.581a131,131,0,1,1,170.017.492ZM160.5,47a110,110,0,1,0,110,110A110,110,0,0,0,160.5,47ZM120.159,241.469h18.248V172.656c5.056,1.319,10.772,1.539,17.148,1.539,29.679,0,61.118-14.07,61.118-53.423,0-13.191-4.4-47.927-58.48-47.927a212.166,212.166,0,0,0-38.034,3.3ZM138.407,89.333a97.024,97.024,0,0,1,20.006-1.758c22.864,0,40.012,10.552,40.012,34.516S182.376,159.245,156,159.245c-7.036,0-12.972-.439-17.588-1.759Z" transform="translate(-29.5 -26)" fill="#8cc63f"/>
</svg>
ブラウザの検証モードでfill属性を変更すると色を変えることができます
線を描いてみる
線はアウトラインにするか迷うところ
線はアウトラインにするのが常識みたいなんですが、弊社の場合顧客からの要望で変更したりするので編集しやすいように線のままにしとく方が良さげなんですよね
アウトラインにしちゃうと線に戻せないというイラレの都合もあるので
まあ線ぐらい1から書き直しても大した手間じゃないのでいいんですが
//線
<line x1="404" y1="0.961" x2="278" y2="230.961" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="4"/>
//アウトライン化した線
<rect x="252.652" y="184.349" width="262.252" height="4" transform="translate(6.448 428.843) rotate(-61.282)"/>
矢印はアウトライン化+合体させる
一方で矢印の場合矢尻と線部分が別パスとして書き出されるので一体化する必要があります
<g>
<line x1="430.68" y1="193.52" x2="316.278" y2="402.349" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="4"/>
<path d="M471.778,198.349c-9.154,7.937-22.232,16.842-33.11,20.845l19.99,3.105,13.374,15.173C469.549,226.15,470.014,210.334,471.778,198.349Z" transform="translate(-29.5 -26)"/>
</g>
その場合アウトライン化して合体です
なので矢印は少々めんどくさいです
矢尻のサイズも調整しないとなので
テキストを描いてみる
テキストはあえてそのままにします
データ量の削減の観点ではテキストパスはアウトライン化させるのが常識のようですが、弊社の場合JavaScriptで書き換えたりする都合上あえてそのままで出力します
<text transform="translate(43.87 360.947)" font-size="12" font-family="KozGoPr6N-Regular-83pv-RKSJ-H, Kozuka Gothic Pr6N">山路を登りながら</text>
レイヤーに名前をつけるとidになる
レイヤーに名前をつけてsvg書き出しするとid="名前"となります
<svg id="レイヤー_1" data-name="レイヤー 1" xmlns="http://www.w3.org/2000/svg" width="442.532" height="424.77" viewBox="0 0 442.532 424.77">
<ellipse cx="130" cy="151.961" rx="118.5" ry="117.5" fill="#fff"/>
<path id="pump" d="M245.218,256.911,290.5,310H29.5l45.7-53.581a131,131,0,1,1,170.017.492ZM160.5,47a110,110,0,1,0,110,110A110,110,0,0,0,160.5,47ZM120.159,241.469h18.248V172.656c5.056,1.319,10.772,1.539,17.148,1.539,29.679,0,61.118-14.07,61.118-53.423,0-13.191-4.4-47.927-58.48-47.927a212.166,212.166,0,0,0-38.034,3.3ZM138.407,89.333a97.024,97.024,0,0,1,20.006-1.758c22.864,0,40.012,10.552,40.012,34.516S182.376,159.245,156,159.245c-7.036,0-12.972-.439-17.588-1.759Z" transform="translate(-29.5 -4.539)" fill="#8cc63f"/>
<g id="line">
<line x1="404" y1="0.961" x2="278" y2="230.961" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="4"/>
</g>
<rect id="outline" x="252.652" y="184.349" width="262.252" height="4" transform="translate(6.448 428.843) rotate(-61.282)"/>
<g id="arrow">
<g>
<line x1="430.68" y1="214.981" x2="316.278" y2="423.81" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="4"/>
<path d="M471.778,198.349c-9.154,7.937-22.232,16.842-33.11,20.845l19.99,3.105,13.374,15.173C469.549,226.15,470.014,210.334,471.778,198.349Z" transform="translate(-29.5 -4.539)"/>
</g>
</g>
<text id="text" transform="translate(43.87 360.947)" font-size="12" font-family="KozGoPr6N-Regular-83pv-RKSJ-H, Kozuka Gothic Pr6N">山路を登りながら</text>
</svg>
なのでid="pump_"や"pump_1-name"みたいに命名規則を作って、あとはプログラムで"-"でsliceしてゴニョゴニョっとできそうな気配
うまいことプログラム組めばイラレで絵書いてid決めてsvg書き出すだけでペコペコ動くみたいなこともできそう
JavaScriptで操作する
簡単にJavaScriptで動かしてみましょう
jQueryセレクタでは取得できない
注意として、どうやら$('#pump')
とかでは取得できないようです
なので以下のようにします
<object id="svg" data="sample.svg" type="image/svg+xml"></object>
$(function(){
let svg = document.getElementById('svg').objectContent;
let pump = $(getElementById('pump'));
});
ポンプの色を変える
pathの色はfill
という属性を変更すると変えられます
pump.css('fill', '#ff0000'); //赤に変わります
線の色を変える
line要素の場合はstroke
という属性です
一方アウトライン化しているとpath要素になるのでfill
で変化させます
line.css('stroke', '#ff0000'); //line要素
outline.css('fill', '#ff0000'); //アウトラインの場合
矢印を点線、実線切替する
display: none/block;で表示非表示
switch (flag) {
case 0:
arrow.css('display', 'none');
arrow.hide();
break;
case 1:
arrow.css('display', 'block');
arrow.hide();
break;
default:
break;
}
テキストを書き換える
jQueryのtext()が使えます
text.text('変更する');
マウスオーバーで機器名表示
jQueryのhover()が使えます
$(img).hover(
function (e) {
$(name).show();
},
function (e) {
$(name).hide();
}
);
まとめ
とまぁゴリゴリやれば作れるのだけれどもまだまだ改良の予知あるなと思ったところです
少なくとも複数色のアイコンを作成してとかの手間は減ってテキストの表示位置もプログラマのセンスに依存するようなこともなくなるのでいいかなと思うのですがね
理想は絵を描いて命名規則に通りにレイヤーに名前つけて出力すれば動く、もしくはこの機器はこのアイコンをこの位置に表示みたいな設定したら配置されて動くみたいなぐらいまで工数削減実現したら素敵ですね
個人的推しなvue.jsとかモダンJavaScriptフレームワークでwebソケットつないでインタラクティブにしたいななんて思いながら