SVG
Vue.js
rect
drag&drop
3
どのような問題がありますか?

この記事は最終更新日から1年以上が経過しています。

投稿日

更新日

Vue.jsとsvgで図形をドラッグ&ドロップする

初めての記事で書き方が分からないけど、とりあえず書いてみたいと思います。

作ったもの

svg1.png

svg2.png

svg3.png
※GIFが表示されなかったので画像になります・・・

svg内に図形(四角形)を作り、それをドラッグ&ドロップで移動させることができます。

App.vue
<template>
  <div class="container">
    <div class="text">枠の中に図形を移動できます</div>
    <!-- SVG定義 -->
    <svg>
      <rect v-for="(r, idx) in rects" :key="idx"
        @mousedown="move($event, idx)"
        :fill="r.color" :stroke="r.stroke"
        :rx="r.rx"
        :x="r.x" :y="r.y" :width="r.w" :height="r.h">{{message}}
      </rect>
      <rect stroke="darkblue" stroke-width="5" fill="none" 
      x="600" :y="100" :width="300" :height="300">
      </rect>
    </svg>
  </div>
</template>

<script>
export default {
  name: 'SVGDemo',
  data () {
    return {
      ratio: 1,
      dx: 0,
      dy: 0,
      viewport: '0 0 500 500',
      isMove: false,
      beforeMouseX: null,
      beforeMouseY: null,
      selectIdx: 0,
      rects: [
        {
          x: 10,
          y: 10,
          w: 100,
          h: 100,
          id: "green",
          color: 'green',
          stroke: 'black',
        },
        {
          x: 200,
          y: 150,
          w: 100,
          h: 100,
          color: 'red',
          stroke: 'black',
        },
        {
          x: 310,
          y: 410,
          w: 200,
          h: 100,
          color: 'blue',
          stroke: 'black',
        },
        {
          x: 100,
          y: 200,
          w: 200,
          h: 100,
          color: 'yellow',
          stroke: 'black',
        },
        {
          x: 300,
          y: 300,
          w: 50,
          h: 50,
          color: 'skyblue',
          stroke: 'black',
        },
        {
          x: 280,
          y: 280,
          w: 50,
          h: 50,
          color: 'white',
          stroke: 'black',
        },
        {
          x: 300,
          y: 300,
          w: 50,
          h: 50,
          color: 'pink',
          stroke: 'black',
        },
        {
          x: 150,
          y: 300,
          w: 50,
          h: 50,
          color: 'lightgreen',
          stroke: 'black',
        },
        {
          x: 50,
          y: 400,
          w: 200,
          h: 50,
          color: 'black',
          stroke: 'black',
        },
        {
          x: 50,
          y: 450,
          w: 200,
          h: 50,
          color: 'brown',
          stroke: 'black',
        },
      ]
    } 
  },
  // マウス操作関連
  mounted () {
    console.log('MOUNT LISTENER ON')
    document.addEventListener('mouseup', this.mouseUp)
    document.addEventListener('mousemove', this.mouseMove)
  },
  beforeDestroy () {
    console.log('MOUNT LISTENER OFF')
    document.removeEventListener('mouseup', this.mouseUp)
    document.removeEventListener('mousemove', this.mouseMove)
  },
  methods: {

    // 図形を動かすフラグを立てる
    move (e, i) {
      this.isMove = true
      this.selectIdx = i
      e.preventDefault()
    },
    // マウスのクリックが終わった段階で初期化
    mouseUp (e) {
      this.isMove = false
      this.beforeMouseX = null
      this.beforeMouseY = null
      e.preventDefault()
    },
    // move中は前回まで動かした差分を取りながら座標を変化させていく
    mouseMove (e) {
      if (!this.isMove) return
      var mouseX = e.offsetX * this.ratio + this.dx
      var mouseY = e.offsetY * this.ratio + this.dy
      var dx = 0
      var dy = 0
      if (this.beforeMouseX && this.beforeMouseY) {
          dx = mouseX - this.beforeMouseX
          dy = mouseY - this.beforeMouseY
      }
      this.beforeMouseX = mouseX
      this.beforeMouseY = mouseY
      var tempX = dx + Number(this.rects[this.selectIdx].x)
      var tempY = dy + Number(this.rects[this.selectIdx].y)
      //var tempX = dx + Number(this.polygons[this.selectIdx].x)
      //var tempY = dy + Number(this.polygons[this.selectIdx].y)
      if (tempX > 0) this.rects[this.selectIdx].x = tempX
      if (tempY > 0) this.rects[this.selectIdx].y = tempY
      e.preventDefault()
    }
  },

}
</script>

<style>
.text {
  height:50px;
  width:1000px;
  font-size:35px;
  text-align: center;
  background-color: tomato;
}

svg {
  width : 1000px;
  height: 500px;
  background-color: silver;
}
</style>

作った理由

javascriptが苦手なので勉強のために作りました。また、vue.jsはスクールで学ばなかったことと、比較的簡単(本当か?)とのことで取り組んでみました。
できたものに関してですが、本当はタングラムパズル(↓こんなやつ)
tangrampazle.jpg
を作りたかったのですが、polygonのx座標y座標をvue.js上にdataとして渡すことができなかったためにrectのみで作成しました。
もしご存知の方は教えてください!!

試したこと

①rect図形に斜線を引いて2分割し、片側を透明にしてしまえば三角形になるのでは?
→結果的にできず
②rect図形にクラス名を付けて個別にstyleを付ければ三角形になるのでは?
→結果的にできず
③polygon図形自体は表示できたので動かしてみよう
→結果的に動かず

いろいろ考えましたが、自分の調べたこと・理解では解決できませんでした。

今後の展望

もっと勉強してタングラムパズルにしたいです。

参考文献

https://qiita.com/masa0209/items/27fb36e939d08b77def7
https://fuwafuwac.com/?p=748

こんなので良いのかわかりませんが、これから備忘録として記事を書いていきたいと思います。

ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
ユーザー登録ログイン

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
Remote TestKitを使ってレビューを書こう!
~
悪いコードを改善した時の体験や知見を共有しよう
~
3
どのような問題がありますか?
ユーザー登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
ユーザー登録ログイン
ストックするカテゴリー