canvas测试案例

<template>
  <div class="canvas-container">
    <canvas 
      ref="canvas" 
      @wheel.prevent="handleWheel"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
      @mouseout="handleMouseUp"
    ></canvas>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageSrc:'https://mail.iflytek.com/coremail/s?func=lp:getImg&org_id=&img_id=background_001',
      margin:0.1,
      canvas: null,
      ctx: null,
      img: null,
      scale: 1,
      minScale: 0.1,
      maxScale: 10,
      scaleStep: 0.1,
      offsetX: 0,
      offsetY: 0,
      startX: 0,
      startY: 0,
      isDragging: false,
      initialScale: 1
    }
  },
  watch: {
    imageSrc(newVal) {
      this.loadImage(newVal);
    }
  },
  mounted() {
    this.initCanvas();
    this.loadImage(this.imageSrc);
  },
  methods: {
    initCanvas() {
      this.canvas = this.$refs.canvas;
      this.ctx = this.canvas.getContext('2d');
      this.resizeCanvas();
      window.addEventListener('resize', this.resizeCanvas);
    },
    resizeCanvas() {
      const container = this.canvas.parentElement;
      this.canvas.width = container.clientWidth;
      this.canvas.height = container.clientHeight;
      
      if (this.img && this.img.complete) {
        this.calculateInitialScale();
        this.drawImage();
      }
    },
    loadImage(src) {
      this.img = new Image();
      this.img.onload = () => {
        this.calculateInitialScale();
        this.drawImage();
      };
      this.img.onerror = () => {
        console.error('Failed to load image:', src);
      };
      this.img.src = src;
    },
    calculateInitialScale() {
      if (!this.img || !this.canvas) return;
      
      const canvasAspect = this.canvas.width / this.canvas.height;
      const imgAspect = this.img.width / this.img.height;
      
      // 考虑边距的缩放计算
      const marginFactor = 1 - Math.min(Math.max(this.margin, 0), 0.9);
      
      if (imgAspect > canvasAspect) {
        // 图片比画布更宽,以宽度为基准
        this.initialScale = (this.canvas.width * marginFactor) / this.img.width;
      } else {
        // 图片比画布更高,以高度为基准
        this.initialScale = (this.canvas.height * marginFactor) / this.img.height;
      }
      
      this.scale = this.initialScale;
      this.offsetX = 0;
      this.offsetY = 0;
    },
    drawImage() {
      if (!this.img || !this.img.complete || !this.ctx) return;
      
      // 清除画布
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
      
      // 计算缩放后的实际尺寸
      const scaledWidth = this.img.width * this.scale;
      const scaledHeight = this.img.height * this.scale;
      
      // 计算居中位置(考虑偏移量)
      const x = (this.canvas.width - scaledWidth) / 2 + this.offsetX;
      const y = (this.canvas.height - scaledHeight) / 2 + this.offsetY;
      
      // 保存当前状态
      this.ctx.save();
      
      // 设置绘制质量
      this.ctx.imageSmoothingEnabled = true;
      this.ctx.imageSmoothingQuality = 'high';
      
      // 绘制图像
      this.ctx.drawImage(
        this.img,
        0, 0, this.img.width, this.img.height,
        x, y, scaledWidth, scaledHeight
      );
      
      // 恢复状态
      this.ctx.restore();
    },
    handleWheel(e) {
      e.preventDefault();
      
      // 获取鼠标在canvas上的位置
      const rect = this.canvas.getBoundingClientRect();
      const mouseX = e.clientX - rect.left;
      const mouseY = e.clientY - rect.top;
      
      // 计算鼠标在图像上的位置(相对于图像中心)
      const imgX = (mouseX - this.canvas.width / 2 - this.offsetX) / this.scale;
      const imgY = (mouseY - this.canvas.height / 2 - this.offsetY) / this.scale;
      
      // 计算缩放方向
      const delta = e.deltaY > 0 ? -1 : 1;
      
      // 保存之前的缩放比例
      const oldScale = this.scale;
      
      // 更新缩放比例
      this.scale += delta * this.scaleStep * this.scale;
      this.scale = Math.max(this.minScale, Math.min(this.maxScale, this.scale));
      
      // 计算缩放中心偏移
      this.offsetX -= imgX * (this.scale - oldScale);
      this.offsetY -= imgY * (this.scale - oldScale);
      
      // 重绘图像
      this.drawImage();
    },
    handleMouseDown(e) {
      this.isDragging = true;
      const rect = this.canvas.getBoundingClientRect();
      this.startX = e.clientX - this.offsetX;
      this.startY = e.clientY - this.offsetY;
    },
    handleMouseMove(e) {
      if (!this.isDragging) return;
      
      const rect = this.canvas.getBoundingClientRect();
      this.offsetX = e.clientX - this.startX;
      this.offsetY = e.clientY - this.startY;
      
      this.drawImage();
    },
    handleMouseUp() {
      this.isDragging = false;
    },
    // 公共方法:重置视图
    resetView() {
      this.scale = this.initialScale;
      this.offsetX = 0;
      this.offsetY = 0;
      this.drawImage();
    }
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resizeCanvas);
  }
}
</script>

<style>
.canvas-container {
  width: 500px;
  height: 500px;
  margin: 0 auto;
  overflow: hidden;
  position: relative;
}
canvas {
  display: block;
  background-color: #f0f0f0;
  cursor: grab;
}
canvas:active {
  cursor: grabbing;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猛男敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值