<!-- Use preprocessors via the lang attribute! e.g. <template lang="pug"> -->
<template>
<div class="app" id="app">
<svg class="app__svg" :viewBox="viewBox">
<rect
class="app__rect"
v-for="cell in cells"
:class="{ 'app__rect--active': cell.isActive }"
:x="getCellX(cell)"
:y="getCellY(cell)"
:width="width"
:height="height"
@mousedown="onMouseDown(cell)"
@mouseenter="onMouseEnter(cell)"
:key="cell.idx"
/>
</svg>
<form class="app__form">
<label class="app__label">
startX:
<input
type="number"
min="0"
:max="colls - 1"
v-model.number="dragStart.col"
/>
</label>
<label class="app__label">
startY:
<input
type="number"
min="0"
:max="rows - 1"
v-model.number="dragStart.row"
/>
</label>
<br />
<label class="app__label">
endX:
<input
type="number"
min="0"
:max="colls - 1"
v-model.number="dragEnd.col"
/>
</label>
<label class="app__label">
endY:
<input
type="number"
min="0"
:max="rows - 1"
v-model.number="dragEnd.row"
/>
</label>
</form>
</div>
</template>
<script>
export default {
data() {
return {
rows: 10,
colls: 10,
width: 20,
height: 20,
gap: 4,
cells: [],
isMouseDown: false,
dragStart: { col: 0, row: 0 },
dragEnd: { col: 0, row: 0 }
};
},
created() {
this.cells = Array.from(
{ length: this.rows * this.colls },
(_, idx) => ({
idx,
isActive: false,
col: idx % this.colls,
row: Math.floor(idx / this.colls)
})
);
window.addEventListener('mouseup', this.onMouseUp.bind(this));
},
watch: {
"dragStart.col": "markActiveCells",
"dragStart.row": "markActiveCells",
"dragEnd.col": "markActiveCells",
"dragEnd.row": "markActiveCells"
},
methods: {
getCellX(cell) {
return cell.col * (this.width + this.gap);
},
getCellY(cell) {
return cell.row * (this.height + this.gap);
},
markActiveCells() {
const colStart = Math.min(this.dragStart.col, this.dragEnd.col);
const rowStart = Math.min(this.dragStart.row, this.dragEnd.row);
const colEnd = Math.max(this.dragStart.col, this.dragEnd.col);
const rowEnd = Math.max(this.dragStart.row, this.dragEnd.row);
for (let c = 0; c < this.colls; c++) {
for (let r = 0; r < this.rows; r++) {
const idx = r * this.colls + c;
const isActive =
c >= colStart && c <= colEnd &&
r >= rowStart && r <= rowEnd;
this.cells[idx].isActive = isActive;
}
}
},
onMouseDown(cell) {
this.isMouseDown = true;
cell.isActive = true;
this.dragStart = { cell };
this.dragEnd = { cell };
},
onMouseUp(e) {
this.isMouseDown = false;
},
onMouseEnter(cell) {
if (!this.isMouseDown) return;
this.dragEnd = { cell };
}
},
computed: {
viewBox() {
const w = this.width * this.colls + this.gap * (this.colls - 1);
const h = this.height * this.rows + this.gap * (this.rows - 1);
return `0 0 ${w} ${h}`;
}
}
};
</script>
<!-- Use preprocessors via the lang attribute! e.g. <style lang="scss"> -->
<style>
.app {
display: flex;
align-items: center;
gap: 25px;
}
.app__svg {
display: block;
overflow: visible;
width: 50%;
transform: scale(0.75) rotateY(-45deg) rotateX(60deg);
}
.app__rect {
fill: none;
stroke-width: 1px;
stroke: #aaa;
pointer-events: all;
}
.app__rect--active {
fill: rgba(255, 99, 71, 0.25);
stroke: rgba(255, 99, 71, 1);
}
.app__form {
width: 50%;
}
.app__label {
white-space: nowrap;
}
</style>
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.