i have this code i want be able to copy and paste rectangles with ctrl+c and ctrl+v " <template>
  <v-app>
    <v-container>
      <v-row justify="center">
        <v-col cols="12" md="8">
          <v-file-input label="Upload an Image" accept="image/*" @change="onImageUpload"
            prepend-icon="mdi-upload"></v-file-input>
        </v-col>
      </v-row>
      <v-row>
        <v-col cols="8">
          <v-card class="my-4">
            <v-card-text>
              <canvas ref="canvas" :width="canvasWidth" :height="canvasHeight" @wheel.prevent="onMouseWheel"
                @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove"
                style="border: 1px solid black;"></canvas>
            </v-card-text>
          </v-card>
        </v-col>
        <v-col cols="4">
          <v-btn v-if="rectangles.length" @click="redrawNormalizedRectangles" color="primary" class="mb-2">
            Redraw Normalized Rectangles
          </v-btn>
          <v-btn v-if="selectedRectangle" @click="copyRectangle" color="secondary" class="mb-2">
            Copy Selected
          </v-btn>
          <v-btn v-if="copiedRectangle" @click="pasteRectangle" color="success" class="mb-2">
            Paste
          </v-btn>
          <v-list v-if="rectangles.length">
            <v-subheader>Rectangles</v-subheader>
            <v-list-item v-for="(rect, index) in rectangles" :key="index" @click="selectRectangle(index)"
              :class="{ active: rect === selectedRectangle }" style="cursor: pointer;">
              <v-list-item-content>
                <v-list-item-title>Rect {{ index + 1 }}</v-list-item-title>
                <v-list-item-subtitle>
                  [x: {{ rect.x.toFixed(2) }}, y: {{ rect.y.toFixed(2) }}, w: {{ rect.width.toFixed(2) }}, h: {{rect.height.toFixed(2) }}]
                </v-list-item-subtitle>
              </v-list-item-content>
              <v-list-item-action>
                <v-btn icon @click.stop="removeRectangle(index)">
                  <v-icon>mdi-delete</v-icon>
                </v-btn>
              </v-list-item-action>
            </v-list-item>
          </v-list>
        </v-col>
      </v-row>
    </v-container>
  </v-app>
</template>

<script>
export default {
  data() {
    return {
      canvasWidth: 800,
      canvasHeight: 600,
      image: null,
      context: null,
      scale: 1,
      minScale: 0.1,
      maxScale: 12,
      scaleStep: 0.1,
      originX: 0,
      originY: 0,
      rectangles: [],
      selectedRectangle: null,
      copiedRectangle: null,
      drawStartX: 0,
      drawStartY: 0,
      drawing: false,
      isDraggingImage: false,
      isDraggingRectangle: false,
      isResizing: false,
      selectedResizeHandle: null,
      resizeHandleSize: 8,
      lastMouseX: 0,
      lastMouseY: 0,
    };
  },
  mounted() {
    this.context = this.$refs.canvas.getContext('2d');
  },
  methods: {
    onImageUpload(event) {
      const file = event.target.files[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = (e) => {
          this.loadImage(e.target.result);
        };
        reader.readAsDataURL(file);
      }
    },
    loadImage(src) {
      this.image = new Image();
      this.image.onload = () => {
        const widthScale = this.canvasWidth / this.image.width;
        const heightScale = this.canvasHeight / this.image.height;
        this.scale = Math.min(widthScale, heightScale);

        const width = this.image.width * this.scale;
        const height = this.image.height * this.scale;
        this.originX = (this.canvasWidth - width) / 2;
        this.originY = (this.canvasHeight - height) / 2;

        this.draw();
      };
      this.image.src = src;
    },
    draw() {
      if (!this.image) return;

      this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      const width = this.image.width * this.scale;
      const height = this.image.height * this.scale;
      this.context.drawImage(this.image, this.originX, this.originY, width, height);

      this.redrawRectangles();

      if (this.drawing) {
        this.context.strokeStyle = 'green';
        const drawWidth = this.currentMouseX - this.drawStartX;
        const drawHeight = this.currentMouseY - this.drawStartY;
        this.context.strokeRect(this.drawStartX, this.drawStartY, drawWidth, drawHeight);
      }
    },
    redrawRectangles() {
      const width = this.image.width * this.scale;
      const height = this.image.height * this.scale;

      this.rectangles.forEach((rect) => {
        const rectX = this.originX + rect.x * width;
        const rectY = this.originY + rect.y * height;
        const rectW = rect.width * width;
        const rectH = rect.height * height;

        this.context.strokeStyle = rect === this.selectedRectangle ? 'red' : 'blue';
        this.context.strokeRect(rectX, rectY, rectW, rectH);

        if (rect === this.selectedRectangle) {
          this.context.fillStyle = 'red';
          this.drawResizeHandles(rectX, rectY, rectW, rectH);
        }
      });
    },
    drawResizeHandles(rectX, rectY, rectW, rectH) {
      const handleSize = this.resizeHandleSize ;/// this.scale;
      const halfSize = handleSize / 2;
      this.context.fillRect(rectX - halfSize, rectY - halfSize, handleSize, handleSize); // Top-left
      this.context.fillRect(rectX + rectW - halfSize, rectY - halfSize, handleSize, handleSize); // Top-right
      this.context.fillRect(rectX - halfSize, rectY + rectH - halfSize, handleSize, handleSize); // Bottom-left
      this.context.fillRect(rectX + rectW - halfSize, rectY + rectH - halfSize, handleSize, handleSize); // Bottom-right
    },
    onMouseWheel(event) {
      const { offsetX, offsetY } = event;
      const oldScale = this.scale;
      const newScale = event.deltaY > 0
        ? Math.max(this.scale - this.scaleStep, this.minScale)
        : Math.min(this.scale + this.scaleStep, this.maxScale);

      if (newScale !== oldScale) {
        const scaleRatio = newScale / oldScale;
        this.originX = offsetX - (offsetX - this.originX) * scaleRatio;
        this.originY = offsetY - (offsetY - this.originY) * scaleRatio;
        this.scale = newScale;
        this.draw();
      }
    },
    onMouseDown(event) {
      const mouseX = event.offsetX;
      const mouseY = event.offsetY;

      if (event.button === 1) { // Middle mouse button for dragging
        this.isDraggingImage = true;
        this.lastMouseX = mouseX;
        this.lastMouseY = mouseY;
      }
      else if (event.button === 0) { // Left mouse button for actions
        this.selectedResizeHandle = this.getResizeHandle(mouseX, mouseY);
        if (this.selectedResizeHandle) {
          this.isResizing = true;
          this.lastMouseX = mouseX;
          this.lastMouseY = mouseY;
          return;
        }

        this.selectedRectangle = this.rectangles.find(rect =>
          mouseX >= this.originX + rect.x * this.image.width * this.scale &&
          mouseX <= this.originX + (rect.x + rect.width) * this.image.width * this.scale &&
          mouseY >= this.originY + rect.y * this.image.height * this.scale &&
          mouseY <= this.originY + (rect.y + rect.height) * this.image.height * this.scale
        );

        if (this.selectedRectangle) {
          this.isDraggingRectangle = true;
          this.lastMouseX = mouseX;
          this.lastMouseY = mouseY;
        } else {
          this.drawing = true;
          this.drawStartX = mouseX;
          this.drawStartY = mouseY;
          this.currentMouseX = mouseX;
          this.currentMouseY = mouseY;
        }
      }
      this.draw();
    },
    onMouseMove(event) {
      this.currentMouseX = event.offsetX;
      this.currentMouseY = event.offsetY;

      if (this.isDraggingImage) {
        const deltaX = this.currentMouseX - this.lastMouseX;
        const deltaY = this.currentMouseY - this.lastMouseY;
        this.originX += deltaX;
        this.originY += deltaY;
        this.lastMouseX = this.currentMouseX;
        this.lastMouseY = this.currentMouseY;
        this.draw();
      } else if (this.isDraggingRectangle && this.selectedRectangle) {
        const deltaX = (this.currentMouseX - this.lastMouseX) / (this.image.width * this.scale);
        const deltaY = (this.currentMouseY - this.lastMouseY) / (this.image.height * this.scale);
        this.selectedRectangle.x += deltaX;
        this.selectedRectangle.y += deltaY;
        this.lastMouseX = this.currentMouseX;
        this.lastMouseY = this.currentMouseY;
        this.draw();
      } else if (this.isResizing && this.selectedRectangle) {
        const deltaX = this.currentMouseX - this.lastMouseX;
        const deltaY = this.currentMouseY - this.lastMouseY;
        this.resizeRectangle(deltaX, deltaY);
        this.lastMouseX = this.currentMouseX;
        this.lastMouseY = this.currentMouseY;
        this.draw();
      } else if (this.drawing) {
        this.draw();
      }
    },
    onMouseUp(event) {
      if (event.button === 1) {
        this.isDraggingImage = false;
      }
      if (event.button === 0) {
        if (this.drawing) {
          const mouseX = this.currentMouseX;
          const mouseY = this.currentMouseY;

          if (Math.abs(mouseX - this.drawStartX) > 0 && Math.abs(mouseY - this.drawStartY) > 0) {
            this.addRectangle(mouseX, mouseY);
          }
          this.drawing = false;
        }
        this.isDraggingRectangle = false;
        this.isResizing = false;
        this.selectedResizeHandle = null;
        this.draw();
      }
    },
    addRectangle(mouseX, mouseY) {
      const rect = {
        x: (Math.min(this.drawStartX, mouseX) - this.originX) / (this.image.width * this.scale),
        y: (Math.min(this.drawStartY, mouseY) - this.originY) / (this.image.height * this.scale),
        width: Math.abs(mouseX - this.drawStartX) / (this.image.width * this.scale),
        height: Math.abs(mouseY - this.drawStartY) / (this.image.height * this.scale),
      };
      this.rectangles.push(rect);
    },
    resizeRectangle(deltaX, deltaY) {
      switch (this.selectedResizeHandle) {
        case 'top-left':
          this.selectedRectangle.x += deltaX / (this.image.width * this.scale);
          this.selectedRectangle.y += deltaY / (this.image.height * this.scale);
          this.selectedRectangle.width -= deltaX / (this.image.width * this.scale);
          this.selectedRectangle.height -= deltaY / (this.image.height * this.scale);
          break;
        case 'top-right':
          this.selectedRectangle.y += deltaY / (this.image.height * this.scale);
          this.selectedRectangle.width += deltaX / (this.image.width * this.scale);
          this.selectedRectangle.height -= deltaY / (this.image.height * this.scale);
          break;
        case 'bottom-left':
          this.selectedRectangle.x += deltaX / (this.image.width * this.scale);
          this.selectedRectangle.width -= deltaX / (this.image.width * this.scale);
          this.selectedRectangle.height += deltaY / (this.image.height * this.scale);
          break;
        case 'bottom-right':
          this.selectedRectangle.width += deltaX / (this.image.width * this.scale);
          this.selectedRectangle.height += deltaY / (this.image.height * this.scale);
          break;
      }
    },
    getResizeHandle(mouseX, mouseY) {
      if (!this.selectedRectangle) return null;
      const { x, y, width, height } = this.selectedRectangle;
      const rectX = this.originX + x * this.image.width * this.scale;
      const rectY = this.originY + y * this.image.height * this.scale;
      const rectW = width * this.image.width * this.scale;
      const rectH = height * this.image.height * this.scale;
      const handleSize = this.resizeHandleSize / this.scale;

      if (this.isWithinBounds(mouseX, mouseY, rectX, rectY, handleSize)) return 'top-left';
      if (this.isWithinBounds(mouseX, mouseY, rectX + rectW, rectY, handleSize)) return 'top-right';
      if (this.isWithinBounds(mouseX, mouseY, rectX, rectY + rectH, handleSize)) return 'bottom-left';
      if (this.isWithinBounds(mouseX, mouseY, rectX + rectW, rectY + rectH, handleSize)) return 'bottom-right';

      return null;
    },
    isWithinBounds(mouseX, mouseY, targetX, targetY, size) {
      return (
        mouseX >= targetX - size / 2 &&
        mouseX <= targetX + size / 2 &&
        mouseY >= targetY - size / 2 &&
        mouseY <= targetY + size / 2
      );
    },
    selectRectangle(index) {
      this.selectedRectangle = this.rectangles[index];
      this.draw();
    },
    removeRectangle(index) {
      this.rectangles.splice(index, 1);
      if (this.selectedRectangle && this.selectedRectangle === this.rectangles[index]) {
        this.selectedRectangle = null;
      }
      this.draw();
    },
    redrawNormalizedRectangles() {
      if (!this.image) return;

      this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      this.context.drawImage(this.image, this.originX, this.originY, this.image.width * this.scale, this.image.height * this.scale);

      this.rectangles.forEach((rect) => {
        const rectX = rect.x * this.image.width;
        const rectY = rect.y * this.image.height;
        const rectWidth = rect.width * this.image.width;
        const rectHeight = rect.height * this.image.height;

        this.context.strokeStyle = 'black';
        this.context.strokeRect(
          this.originX + rectX * this.scale,
          this.originY + rectY * this.scale,
          rectWidth * this.scale,
          rectHeight * this.scale
        );
      });
    },
    copyRectangle() {
      if (this.selectedRectangle) {
        this.copiedRectangle = { ...this.selectedRectangle };
      }
    },
    pasteRectangle() {
      if (this.copiedRectangle) {
        const newRect = {
          ...this.copiedRectangle,
          x: this.copiedRectangle.x + 0.05,
          y: this.copiedRectangle.y + 0.05,
        };
        this.rectangles.push(newRect);
        this.selectedRectangle = newRect;
        this.draw();
      }
    },
  },
};
</script>

<style scoped>
canvas {
  display: block;
  cursor: crosshair;
  margin-bottom: 16px;
}

.active {
  background-color: rgba(0, 0, 255, 0.1);
}
</style>"