Node.js+Vue.jsで超簡易SVGエディタを作ってみた。

By | 2020年8月8日 , Last update: 2020年8月20日

はじめに

Node.jsとVue.jsを勉強し、その真髄を理解したところで、何か自分の役に立ちそうなものを作れないか考えてみたところ、SVGのエディタなら作れそうな気がしてきたので、正味5時間くらいで作ってみることにしました。

スポンサーリンク

なぜ、今SVGエディタなのか?

Inkscapeで描いた図が使いにくい問題

SVGフォーマットでポンチ絵的な図を描き、それをHTMLのデータに埋め込む必要が生じたとします。

まず、Inkscapeでポンチ絵的な図を描いて保存することを考えます。この場合、InkscapeでSVGフォーマットでファイルを保存すると、図形の情報以外にもいろいろな情報が付加されたSVGファイルが出力されます。

例えば、Inkscapeで以下のような長方形を1個描いてSVGフォーマットで保存します。

これをEmacs等のエディタで開いてみると…

長方形を1個書いただけのはずなのに、Inkscapeが使用するためのいろいろな情報が付加されていることがわかります。実際のところ、上図で表示した範囲には描いたはずの長方形についての情報はなく、SVGファイルの末尾に近いところに以下の情報が現れます。

<g
id=”layer1″
inkscape:groupmode=”layer”
inkscape:label=”レイヤー 1″>
<rect
y=”24.190477″
x=”9.8273811″
height=”43.089287″
width=”65.011902″
id=”rect10″
style=”fill:#1e3e8a;stroke-width:1.052″ />
</g>

 
上記以外の情報についてはInkscapeが使用するためのものですので、HTMLに埋め込む際には必要のない情報になります。また、上記の情報についても先頭に”inkscape:”とついている属性はInkscapeで使用するためだけのものです。

図がある程度出来上がってくると、埋め込み先のHTMLのデータごとブラウザで表示させることで、レイアウトのバランスなども含めた確認を行うことになりますが、HTMLのデータはブラウザを介して端末の画面上に描画されることを考えると、一般的にはピクセル単位での表示になります。

したがって、よほど込み入った図や関数のグラフなどを描くなどの理由によって、図形の位置を厳密に指定する必要が生じない限り、図形の座標や長さを表す値は整数値にしておいた方がメンテナンス性や他のHTMLのデータとの間の親和性は良さそうです。

Inkscapeとブラウザ間の往復は面倒ですよね。

Inkscapeで図を編集し、ブラウザで(他のHTMLデータとの兼ね合いも含めて)表示の状況を確認し、またInkscapeで手直しすることを繰り返す… という作業はかなり手間がかかります。もし、描いた図の主な利用目的がブラウザでの表示であるならば、(Inkscapeを介さずに)ブラウザ上で直接確認しながらSVGフォーマットの図を描くことで、作業効率を上げることができそうです。

ということで、作ります。

基本的な構想

前の記事でNode.jsを使ってWebアプリを作ったので、Webアプリのディレクトリ構成としてはその時の構成をそのまま使用することにします。

なお、MariaDBへの接続は行わないので、関連するコードは削除します。

画面の表示レイアウトは(大まかですが、)以下のような感じとします。SVGの図の大きさは640px x 360pxで決め打ちとしています。

図の大きさが決め打ちのため、何も描かれていないときは画面の下部の表示が間延びしてしまいますが、そのあたりは気にしないことにします。


スポンサーリンク

なお、名前はVSSE(Very Simple SVG Editor)とします。

どこかの私鉄の特急列車の愛称のようですが、関連性はありません。

実装例

画面例

構想決定後、正味5時間ほどで実装したWebアプリ(文言部及びダウンロード部を除く。)は以下のような感じになりました。

上図では見えていませんが、画面の下部にはプレビュー部が広がっています。

実装上のポイント

実装上のポイントは以下の通りです。

  1. textareaに入力されたデータ(SVGの要素)はプレビュー部の表示エリアと同期していますが、このデータはXMLベースのデータであるため、プレビュー部の最上位タグ(svgタグ)にv-html属性を追加し、対応する値にルートVueインスタンス中の属性値のうち入力されたデータを格納しているもの(svg)を指定します。
  2. プレビュー部の最上位タグ(svgタグ)の子要素としてHTMLのaタグは使用できないことになってはいますが、念のためのXSS対策としてanchorタグ(aタグ)は入力データの反映時に削除しています。

    前項とまとめると、以下のような実装となります。removeAnchorTagがanchorタグを削除するための関数になります。

    <svg width=”640px” height=”360px” viewPort=”0 0 640 360″ version=”1.1″ v-html=”$removeAnchorTag(svg)” xmlns=”http://www.w3.org/2000/svg”>
    </svg>
    (中略)
    <script>
    let removeAnchorTag = str => str.replace(/<a[^>]*>/gi,”).replace(/<\/a>/gi,”);

    Vue.prototype.$removeAnchorTag = removeAnchorTag;
    (後略)
    <script>

     

  3. VSSEには作成したSVGファイルをダウンロードする機能がありますが、ファイル名については作成したSVGデータのSHA-256によるハッシュ値を計算し、その結果を16進変換した結果得られる文字列にSVGファイルの拡張子(.svg)を付加したものとし、ダウンロード時のファイル名の変更は不可としています。
  4. SVGファイルをダウンロードする際にはaxiosを使っていったんデータをサーバに送信し、最上位タグ(svgタグ)を追加したものをクライアント(本Webアプリ)に返送してファイルに保存する仕組みとしていますが、この場合、ブラウザはサーバからのデータを受信する以外のこと(HTMLのヘッダ及びHTMLデータの本体の解析)はしてくれませんので、HTMLのヘッダの解析及びHTMLデータの処理を別途実装する必要があります。本Webアプリでも以下のコードによりHTMLデータに含まれるcontent-dispositionのデータを解析してファイル名を取り出してから…
    const contentDisposition = response.headers[“content-disposition”];
    let fileName = contentDisposition.match(/filename=”?([^”]+)\s*/u);
    // fileName[1]がファイル名を表す文字列になります。

    スポンサーリンク

     
    FileSaver.jsを使って受信したSVGデータを取り出したファイル名のファイルとして保存するコードを実装しています。

    この機能については、HTMLヘッダを適切に設定してもファイルのダウンロードができず、2日ほどハマりました。

VSSEの動作確認

実装がいい感じのところまで完了したところでVSSEを起動し、動作を確認していきます。

VSSEのURLにアクセスしてブラウザに「実装例」の節の画面を表示させて下にスクロールさせ、プレビュー部を表示させます(下図)。

Line→Rect→Polygon→Polyline→Ellipse→Circle→Textの順にボタンをクリックします。


スポンサーリンク

楕円がブラックすぎるので、textareaを使って属性値(fill,下図の赤矢印)を修正してみます。

“Download SVG!!”ボタンをクリックして、作成したSVGファイルをダウンロードします。

ダウンロードしたファイルをInkscapeで開いてみます。

VSSEで編集したものが表示できていることが確認できました。😎

Example for nowボタンを追加してみた。[2020/08/20]

VSSEにExample for nowボタンを追加してみました。

Example for nowボタンをクリックすると、↓のようなアニメーションの入ったSVGファイルのサンプルがダウンロードされます(この画像に限りインラインSVGとしています)。
The quick brown fox jumps over the lazy dog.
インラインSVGでない場合には↓のような微妙な感じの表示になります。

なお、animateタグ及びanimateTransformタグはInkscapeでは対応していないようです。

まとめ

Inkscapeは機能豊富なソフトウェアですので、アート的な要素が入る図や絵を描くのであれば、Inkscapeだけを使って図や絵を描き切ってから必要に応じて全体を拡大・縮小する方針の方が描画に集中できるので、作業効率や質を向上させることができると思います。

しかし、ポンチ絵的な図を描く場合だとInkscapeの機能的にはtoo muchであると感じることの方が多いので、単純なエディタではありますが、VSSEみたいなものを作っておくと意外に出番は多いのではないかと思います。実際、「実装例」の節の画面はVSSEを使って作ったものです。

また、Node.jsとVue.jsを使うことにより軽量なアプリケーションに仕上げてみましたので、セキュリティ面などの検討(実はこれが一番面倒なところです。(´・ω・`))を行って問題ないことが確認できましたので、ここにVSSEへのリンクを置いておきます。よろしければ見ていっていただけると幸いです。

この記事は以上です。

References / 参考文献