LoginSignup
5

More than 3 years have passed since last update.

Vue + SVG で作るグラフィックアプリの骨格

Last updated at Posted at 2019-10-11

はじめに

この記事はもう一つの記事、
Vue + Canvas で作るグラフィックアプリの骨格
の SVG 版です。

Canvas や SVG のおかげでブラウザ上でもインタラクティブにグラフィックを簡単に扱えるようになりました。

おまけに Vue を使うとまるでパソコン上のアプリを作るかのように Web 上にグラフィックアプリを作ることができます。

この記事では Vue + SVG でマウスで四角を書いていくような 80 行程度の簡単なサンプルを作ることで、Web 上のグラフィックアプリの骨格を示したいと思います。

できあがったものは、以下のような感じです。
ss.gif

準備

  • node, npm をダウンロードします

https://nodejs.org
この記事では node v12.4.0 で検証しています

  • vue-cli をダウンロードして、とりあえず qvs という名前でアプリを作ります。
$ npm i @vue/cli -g
$ vue create qvs
$ cd qvs
$ yarn serve

この記事では vue 3.12.0 で検証しています。yarn を使ってない人は最後の行は

$ npm run serve

になると思います。

なお、以下のコードは ESLint の掟に従ってないので、vue create qvs の時に ESLint をはずさないと多分エラーになると思われます。
また、セパレータを前に書いたり、引数とか変数の名前が _ だったりするのは単なる趣味ですので、気に入らなくても怒らないでください。

コード

src/App.vue を以下のようにしてみます。

App.vue
<template>
    <div id=app style="overflow: scroll">
        <div id=menu style="position: fixed; top: 0; left: 0">
            <button @click="mode='select'"  >select </button>
            <button @click="mode='rect'"    >rect   </button>
        </div>
        <svg
            style       = "margin: 24px 4px 4px 4px; background: aliceblue"
            :class      = "{ drawRect: mode == 'rect' }"
            :width      = "extent[ 0 ]"
            :height     = "extent[ 1 ]"
            @mousedown  = "mouseDown"
            @mousemove  = "mouseMove"
            @mouseup    = "mouseUp"
            @keyup.esc  = "keyUpESC"
        >
            <template v-for="_ in elements">
                <rect v-bind="_" stroke=black fill=none />
            </template>

            <rect v-bind=dragRect stroke=blue fill=none />
        </svg>
    </div>
</template>

<script>
export default {
    data    : () => (
        {   b           : null
        ,   c           : null
        ,   mode        : 'select'
        ,   elements    : []
        }
    )
,   computed: {
        extent  () {
            return [ 700, 500 ]
        }
    ,   svg     () {
            return this.$el.getElementsByTagName( 'svg' )[ 0 ]
        }
    ,   dragRect() {
            return ( ! this.b || ! this.c )
            ?   null
            :   {   x       : this.b.offsetX
                ,   y       : this.b.offsetY
                ,   width   : this.c.offsetX - this.b.offsetX
                ,   height  : this.c.offsetY - this.b.offsetY
                }
        }
    }
,   methods : {
        mouseDown( _ ) {
            this.b = _
        }
    ,   mouseMove( _ ) {
            this.c = _
        }
    ,   mouseUp( _ ) {
            this.c = _
            switch ( this.mode ) {
            case 'rect':
                this.elements.push( this.dragRect )
                break
            }
            this.b = null
        }
    ,   keyUpESC( _ ) {
            this.mode = 'select'
        }
    }
,   mounted() {
        this.svg.setAttribute( 'tabindex', 0 )
    }
}
</script>

<style>
.drawRect {
    cursor: crosshair
}
</style>

勘所

キーイベントの取得

svg に tabindex 属性をつけると、キーイベントを取得できるようになります。

    this.svg.setAttribute( 'tabindex', 0 )

カーソルの切り替え

mode が 'select' と 'rect' の2つの状態が存在します。
'rect' の状態の時にクロスヘアカーソルを表示するために
クラスとスタイルのバインディングを動的に使っています。

    :class = "{ drawRect: mode == 'rect' }"


<style>
.drawRect {
    cursor: crosshair
}
</style>

v-bind でプロパティを一括設定

プロパティ名と同じキーを持つ辞書を用意して

dragRect = {
    x       : 100
,   y       : 200
,   width   : 300
,   height  : 400
}
<rect v-bind=dragRect />

とやると、

<rect x=100 y=200 width=300 height=400 />

と展開されます。

最後に

この記事が何かの役にたてたら幸いです。わからないことがあればコメントください!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5