[Vue] SVG要素をドラッグ&ドロップで移動する

VueでSVG要素をドラッグ&ドロップで移動するサンプルです。

コード

template

<template>
<div id="app">
    <svg xmlns="http://www.w3.org/2000/svg" 
        ref="svg" 
        width="500px" 
        height="500px" 
        viewBox="0 0 500 500" 
    >
        <rect
            v-for="( item, i ) in shapes"
            :key="item._id"
            :x="item.x"
            :y="item.y"
            :width="item.w"
            :height="item.h"
            :fill="item.fill"
            @mousedown.stop="drag( $event, i )"
            @mouseup.stop="drop( i )"
        />
    </svg>
</div>
</template>

script

<script>
export default {
    data() {
        return {
            // setting for Rect object
            shapes: [
                {
                    _id: '0',
                    x: 10,
                    y: 10,
                    w: 150,
                    h: 150,
                    fill: 'red',
                    isSelected: false
                },
                {
                    _id: '1',
                    x: 200,
                    y: 200,
                    w: 250,
                    h: 250,
                    fill: 'blue',
                    isSelected: false
                }
            ],
            // for drag&drop event, temporarily save
            dragOffsetX: null,
            dragOffsetY: null,
        };
    },
    methods: {
        // For drag start event
        drag( e, index ) {
            // Update for get target in move()
            this.shapes[index].isSelected = true;
            // temporarily save
            this.dragOffsetX = e.offsetX - this.shapes[index].x;
            this.dragOffsetY = e.offsetY - this.shapes[index].y;
            // Add Event
            this.$refs.svg.addEventListener( 'mousemove', this.move );
        },
        // For drag End event
        drop( index ) {
            // Reset variable
            this.shapes[index].isSelected = false;
            this.dragOffsetX = this.dragOffsetY = null;
            // Remove Event
            this.$refs.svg.removeEventListener( 'mousemove', this.move );
        },
        // For move(dragging) Event
        move( { offsetX, offsetY }  ) {
            // Get target index
            const index = this.shapes.findIndex( v => v.isSelected === true );
            // Update position
            this.shapes[index].x = offsetX - this.dragOffsetX;
            this.shapes[index].y = offsetY - this.dragOffsetY;
        } 
    }
};
</script>