4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-08-31

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

作ったもの

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

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

4
3
0

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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?