Vue Select Elements

Select elements with mouse over

by WILLIAM CORREA

HTML

<div id="app">
  <div
    ref="canvas"
    id="canvas" 
    @mousedown="onMouseDown"
    @mousemove="onMouseMove"
    @mouseup="onMouseUp"
  >
    <div
      ref="selector"
      id="selector"
      :style="style"
      hidden
    ></div>
    <div
      v-for="button in buttons"
      class="container"
      :ref="button.ref"
      :class="{'selected': button.selected}"
    >
      <button>{{ button.label }}</button>
    </div>
  </div>
  <pre>{{ selected }}</pre>
</div>

CSS

#canvas {
  padding: 20px;
  display: flex;
  flex-wrap: wrap;
  user-select: none;
  justify-content: space-between;
  align-items: center;
  height: 200px;
  overflow: auto;
  border: 1px solid #ddd;
}

.container {
  margin: 5px;
  flex: 1;
}

.container > * {
  display: block;
  width: 100%;
  height: 100%;
}

.container.selected > * {
  box-shadow: 0 0 5px 1px rgba(0, 0, 0, .7);
}

#selector {
  border-radius: 2px;
  border: 1px dotted #000;
  position: fixed;
  background: rgba(100, 100, 100, .25);
}

JavaScript

new Vue({
  el: '#app',
  data: () => ({
  	selector: {
      top: 0,
      left: 0,
      width: 0,
      height: 0,
    },
    style: {
      left: '',
      top: '',
      width: '',
      height: '',
    },
    tolerance: {
    	top: 10,
    	left: 10,
    	height: 10,
    	width: 10
    },
    buttons: Array.from({
      length: 100
    }).map((item, index) => ({
      label: `Button ${index}`,
      ref: `ref-${index}`,
      selected: false
    }))
  }),
  computed: {
  	selected () {
    	return this.buttons.filter(button => button.selected).map(button => button.ref)
    }
  },
  methods: {
    onMouseDown($event) {
        this.$refs.selector.hidden = 0
        this.selector.top = $event.clientX
        this.selector.left = $event.clientY
        this.draw()
      },
      onMouseMove($event) {
        this.selector.width = $event.clientX
        this.selector.height = $event.clientY
        this.draw()
      },
      onMouseUp($event) {
        const rectangle = element => {
          return {
            top: element.offsetTop,
            left: element.offsetLeft,
            width: element.offsetWidth,
            height: element.offsetHeight
          }
        }
        const area = rectangle(this.$refs.selector)

        this.$refs.selector.hidden = 1
        this.buttons.forEach(button => {
          button.selected = this.areaHasContainer(area, rectangle(this.$refs[button.ref][0]))
        })
      },
      draw() {
        const a = Math.min(this.selector.top, this.selector.width);
        const b = Math.max(this.selector.top, this.selector.width);
        const c = Math.min(this.selector.left, this.selector.height);
        const d = Math.max(this.selector.left, this.selector.height);
        this.style.left = a + 'px';
        this.style.top = c + 'px';
        this.style.width = b - a + 'px';
        this.style.height = d - c + 'px';
      },
      areaHasContainer(area, container) {
        const top = this.$refs.canvas.scrollTop
       ...