<template>
  <view class="canvas-container">
    <view class="header">
      <text class="title">Canvas图片拖拽示例</text>
      <text class="subtitle">点击并拖动图片到目标区域</text>
    </view>
    
    <view class="main-content">
      <view class="canvas-wrapper">
        <canvas 
          canvas-id="imageCanvas"
          id="imageCanvas"
          class="canvas-element"
          :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
          @touchstart="handleTouchStart"
          @touchmove="handleTouchMove"
          @touchend="handleTouchEnd"
        ></canvas>
        
        <view class="canvas-info">
          <text>Canvas尺寸: {{ canvasWidth }} × {{ canvasHeight }} px</text>
          <text>图片状态: {{ imageStatus }}</text>
        </view>
      </view>
      
      <view class="controls">
        <view class="control-card">
          <text class="control-title">操作说明</text>
          <view class="instructions">
            <text>1. 点击并按住图片开始拖拽</text>
            <text>2. 拖动图片到蓝色目标区域</text>
            <text>3. 释放手指完成拖放</text>
          </view>
          
          <view class="image-url">
            <text>图片URL:</text>
            <text class="url-text">{{ imageUrl }}</text>
          </view>
        </view>
        
        <view class="control-card">
          <text class="control-title">目标区域</text>
          <view :class="['target-area', { 'target-hit': isInTarget }]">
            <text>目标位置: ({{ target.x }}, {{ target.y }})</text>
            <text>尺寸: {{ target.width }} × {{ target.height }}</text>
            <text v-if="isInTarget" class="success-text">✅ 图片已在目标区域内</text>
          </view>
        </view>
        
        <view class="control-card">
          <text class="control-title">状态信息</text>
          <view class="status">
            <text :class="['status-text', { 'dragging': isDragging }, { 'success': isInTarget }]">
              {{ statusText }}
            </text>
          </view>
          
          <view class="stats">
            <view class="stat-item">
              <text class="stat-value">{{ dragCount }}</text>
              <text class="stat-label">拖拽次数</text>
            </view>
            <view class="stat-item">
              <text class="stat-value">{{ targetHits }}</text>
              <text class="stat-label">命中目标</text>
            </view>
            <view class="stat-item">
              <text class="stat-value">{{ Math.round(dragDistance) }}</text>
              <text class="stat-label">移动距离</text>
            </view>
          </view>
        </view>
        
        <view class="control-card">
          <text class="control-title">图片位置</text>
          <view class="position-info">
            <text>X坐标: {{ image.x.toFixed(0) }} px</text>
            <text>Y坐标: {{ image.y.toFixed(0) }} px</text>
            <text>宽度: {{ image.width }} px</text>
            <text>高度: {{ image.height }} px</text>
          </view>
        </view>
        
        <button class="reset-btn" @tap="resetImage">重置图片位置</button>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      // Canvas尺寸
      canvasWidth: 350,
      canvasHeight: 500,
      
      // Canvas上下文
      ctx: null,
      
      // 图片URL
      imageUrl: 'https://static.vecteezy.com/system/resources/previews/026/105/544/non_2x/example-icon-design-free-vector.jpg',
      
      // 图片对象
      image: {
        x: 50,
        y: 50,
        width: 120,
        height: 120,
        isDragging: false,
        dragOffsetX: 0,
        dragOffsetY: 0,
        startX: 0,
        startY: 0,
        img: null,
        loaded: false
      },
      
      // 目标区域
      target: {
        x: 150,
        y: 200,
        width: 140,
        height: 100
      },
      
      // Canvas位置信息
      canvasRect: {
        left: 0,
        top: 0,
        width: 0,
        height: 0
      },
      
      // 状态
      isDragging: false,
      isInTarget: false,
      dragCount: 0,
      targetHits: 0,
      dragDistance: 0,
      statusText: '点击图片开始拖拽',
      imageStatus: '加载中...',
      
      // 动画帧ID
      animationFrameId: null,
      lastRenderTime: 0,
      renderInterval: 16 // ~60fps
    }
  },
  
  onLoad() {
    // 页面加载后初始化Canvas
    this.$nextTick(() => {
      setTimeout(() => {
        this.initCanvas()
      }, 100)
    })
  },
  
  onUnload() {
    // 页面卸载时停止动画
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId)
    }
  },
  
  onShow() {
    // 页面显示时开始动画
    this.startAnimation()
  },
  
  onHide() {
    // 页面隐藏时停止动画
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId)
      this.animationFrameId = null
    }
  },
  
  methods: {
    // 初始化Canvas
    initCanvas() {
      // 创建Canvas上下文
      this.ctx = uni.createCanvasContext('imageCanvas', this)
      
      // 获取Canvas位置信息
      this.getCanvasPosition()
      
      // 加载图片
      this.loadImage()
      
      // 开始动画循环
      this.startAnimation()
    },
    
    // 获取Canvas位置信息
    getCanvasPosition() {
      const query = uni.createSelectorQuery().in(this)
      query.select('#imageCanvas').boundingClientRect(res => {
        if (res) {
          this.canvasRect = {
            left: res.left,
            top: res.top,
            width: res.width,
            height: res.height
          }
        }
      }).exec()
    },
    
    // 加载图片
    loadImage() {
      const img = new Image()
      img.onload = () => {
        console.log('图片加载成功')
        this.image.img = img
        this.image.loaded = true
        this.imageStatus = '已加载'
        this.statusText = '点击图片开始拖拽'
        
        // 如果图片尺寸太大，调整显示尺寸
        const maxWidth = 150
        const maxHeight = 150
        if (img.width > maxWidth || img.height > maxHeight) {
          const ratio = Math.min(maxWidth / img.width, maxHeight / img.height)
          this.image.width = img.width * ratio
          this.image.height = img.height * ratio
        }
      }
      
      img.onerror = () => {
        console.error('图片加载失败，使用备选方案')
        this.imageStatus = '加载失败，使用备选图片'
        this.createFallbackImage()
      }
      this.createFallbackImage()
      // img.src = '/static/dzm/img_duck.png'
    },
    
    // 创建备选图片（如果网络图片加载失败）
    createFallbackImage() {
      // 创建一个备用的Canvas来绘制图片
      const fallbackCanvas = document.createElement('canvas')
      const fallbackCtx = fallbackCanvas.getContext('2d')
      
      fallbackCanvas.width = this.image.width
      fallbackCanvas.height = this.image.height
      
      // 绘制橙色背景
      fallbackCtx.fillStyle = '#FF8C00'
      fallbackCtx.fillRect(0, 0, this.image.width, this.image.height)
      
      // 绘制边框
      fallbackCtx.strokeStyle = '#333'
      fallbackCtx.lineWidth = 2
      fallbackCtx.strokeRect(0, 0, this.image.width, this.image.height)
      
      // 绘制示例图标
      fallbackCtx.fillStyle = 'white'
      fallbackCtx.font = 'bold 14px Arial'
      fallbackCtx.textAlign = 'center'
      fallbackCtx.textBaseline = 'middle'
      fallbackCtx.fillText('示例', this.image.width / 2, this.image.height / 2 - 10)
      
      fallbackCtx.font = '12px Arial'
      fallbackCtx.fillText('图片', this.image.width / 2, this.image.height / 2 + 10)
      
      // 转换为图片
      const img = new Image()
      img.src = fallbackCanvas.toDataURL('image/png')
      img.onload = () => {
        this.image.img = img
        this.image.loaded = true
      }
    },
    
    // 开始动画循环
    startAnimation() {
      const animate = (timestamp) => {
        if (timestamp - this.lastRenderTime >= this.renderInterval) {
          this.drawCanvas()
          this.lastRenderTime = timestamp
        }
        this.animationFrameId = requestAnimationFrame(animate)
      }
      this.animationFrameId = requestAnimationFrame(animate)
    },
    
    // 绘制Canvas内容
    drawCanvas() {
      if (!this.ctx) return
      
      // 清除Canvas
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      
      // 绘制目标区域
      this.drawTargetArea()
      
      // 绘制可拖拽图片
      this.drawImage()
      
      // 绘制坐标信息
      this.drawInfo()
      
      // 执行绘制
      this.ctx.draw(true)
    },
    
    // 绘制目标区域
    drawTargetArea() {
      this.ctx.setFillStyle(this.isInTarget ? 'rgba(46, 204, 113, 0.2)' : 'rgba(52, 152, 219, 0.1)')
      this.ctx.setStrokeStyle(this.isInTarget ? '#2ecc71' : '#3498db')
      this.ctx.setLineWidth(2)
      this.ctx.setLineDash([5, 5])
      
      this.ctx.fillRect(this.target.x, this.target.y, this.target.width, this.target.height)
      this.ctx.strokeRect(this.target.x, this.target.y, this.target.width, this.target.height)
      this.ctx.setLineDash([])
      
      // 绘制目标区域文字
      this.ctx.setFontSize(12)
      this.ctx.setFillStyle('#3498db')
      this.ctx.setTextAlign('center')
      this.ctx.fillText(
        '目标区域',
        this.target.x + this.target.width / 2,
        this.target.y + this.target.height / 2
      )
    },
    
    // 绘制图片
    drawImage() {
      if (this.image.loaded && this.image.img) {
        // 绘制图片
        this.ctx.drawImage(
          this.image.img,
          this.image.x,
          this.image.y,
          this.image.width,
          this.image.height
        )
        
        // 如果正在拖拽，绘制高亮边框
        if (this.image.isDragging) {
          this.ctx.setStrokeStyle('#e74c3c')
          this.ctx.setLineWidth(3)
          this.ctx.setLineDash([5, 5])
          this.ctx.strokeRect(
            this.image.x - 5,
            this.image.y - 5,
            this.image.width + 10,
            this.image.height + 10
          )
          this.ctx.setLineDash([])
        }
      } else {
        // 图片未加载时绘制占位符
        this.ctx.setFillStyle('#FF8C00')
        this.ctx.fillRect(this.image.x, this.image.y, this.image.width, this.image.height)
        
        this.ctx.setStrokeStyle('#333')
        this.ctx.setLineWidth(2)
        this.ctx.strokeRect(this.image.x, this.image.y, this.image.width, this.image.height)
        
        this.ctx.setFontSize(14)
        this.ctx.setFillStyle('#FFFFFF')
        this.ctx.setTextAlign('center')
        this.ctx.fillText(
          '加载中...',
          this.image.x + this.image.width / 2,
          this.image.y + this.image.height / 2
        )
      }
    },
    
    // 绘制信息
    drawInfo() {
      this.ctx.setFontSize(10)
      this.ctx.setFillStyle('#666')
      this.ctx.setTextAlign('left')
      this.ctx.setTextBaseline('top')
      
      // 图片位置信息
      this.ctx.fillText(
        `图片位置: (${Math.round(this.image.x)}, ${Math.round(this.image.y)})`,
        10, 10
      )
      
      // 目标位置信息
      this.ctx.fillText(
        `目标位置: (${this.target.x}, ${this.target.y})`,
        10, 25
      )
      
      // 拖拽次数信息
      this.ctx.fillText(
        `拖拽次数: ${this.dragCount}`,
        10, 40
      )
    },
    
    // 检查触摸点是否在图片内
    isPointInImage(x, y) {
      return x >= this.image.x && 
             x <= this.image.x + this.image.width && 
             y >= this.image.y && 
             y <= this.image.y + this.image.height
    },
    
    // 检查图片是否在目标区域内
    checkImageInTarget() {
      const img = this.image
      const imgCenterX = img.x + img.width / 2
      const imgCenterY = img.y + img.height / 2
      
      const hit = 
        imgCenterX >= this.target.x && 
        imgCenterX <= this.target.x + this.target.width &&
        imgCenterY >= this.target.y && 
        imgCenterY <= this.target.y + this.target.height
      
      this.isInTarget = hit
      return hit
    },
    
    // 计算两点距离
    calculateDistance(x1, y1, x2, y2) {
      return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
    },
    
    // 触摸开始事件
    handleTouchStart(e) {
      const touch = e.touches[0]
      if (!touch) return
      
      // 更新Canvas位置信息
      this.getCanvasPosition()
      
      // 异步执行，确保Canvas位置信息已更新
      setTimeout(() => {
        const touchX = touch.clientX - this.canvasRect.left
        const touchY = touch.clientY - this.canvasRect.top
        
        if (this.isPointInImage(touchX, touchY)) {
          this.image.isDragging = true
          this.image.dragOffsetX = touchX - this.image.x
          this.image.dragOffsetY = touchY - this.image.y
          this.image.startX = this.image.x
          this.image.startY = this.image.y
          
          this.isDragging = true
          this.statusText = '正在拖拽图片...'
        }
      }, 50)
    },
    
    // 触摸移动事件
    handleTouchMove(e) {
      if (!this.image.isDragging) return
      
      e.preventDefault()
      
      const touch = e.touches[0]
      if (!touch) return
      
      const touchX = touch.clientX - this.canvasRect.left
      const touchY = touch.clientY - this.canvasRect.top
      
      // 计算移动距离
      const distance = this.calculateDistance(
        this.image.x,
        this.image.y,
        touchX - this.image.dragOffsetX,
        touchY - this.image.dragOffsetY
      )
      
      this.dragDistance += distance
      
      // 更新图片位置
      this.image.x = touchX - this.image.dragOffsetX
      this.image.y = touchY - this.image.dragOffsetY
      
      // 限制边界
      this.image.x = Math.max(0, Math.min(
        this.canvasWidth - this.image.width,
        this.image.x
      ))
      
      this.image.y = Math.max(0, Math.min(
        this.canvasHeight - this.image.height,
        this.image.y
      ))
      
      // 检查是否进入目标区域
      this.checkImageInTarget()
    },
    
    // 触摸结束事件
    handleTouchEnd() {
      if (this.image.isDragging) {
        this.image.isDragging = false
        this.isDragging = false
        this.dragCount++
        
        if (this.checkImageInTarget()) {
          this.targetHits++
          this.statusText = '图片已在目标区域内'
        } else {
          this.statusText = '拖拽完成'
        }
      }
    },
    
    // 重置图片位置
    resetImage() {
      this.image.x = 50
      this.image.y = 50
      this.image.isDragging = false
      this.isDragging = false
      this.isInTarget = false
      this.statusText = '位置已重置，点击图片开始拖拽'
    }
  }
}
</script>

<style>
.canvas-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
}

.header {
  text-align: center;
  margin-bottom: 20px;
  padding: 20px;
  background-color: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.title {
  display: block;
  font-size: 22px;
  font-weight: 700;
  color: #2c3e50;
  margin-bottom: 8px;
}

.subtitle {
  display: block;
  font-size: 16px;
  color: #7f8c8d;
}

.main-content {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.canvas-wrapper {
  background-color: white;
  border-radius: 12px;
  padding: 15px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.canvas-element {
  border-radius: 8px;
  background-color: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  touch-action: none;
}

.canvas-info {
  margin-top: 10px;
  padding: 10px;
  background-color: #f8f9fa;
  border-radius: 8px;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

.canvas-info text {
  font-size: 12px;
  color: #666;
  text-align: center;
}

.controls {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.control-card {
  background-color: white;
  border-radius: 12px;
  padding: 15px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.control-title {
  font-size: 16px;
  font-weight: 600;
  color: #2c3e50;
  margin-bottom: 12px;
  display: block;
  padding-bottom: 8px;
  border-bottom: 2px solid #f0f0f0;
}

.instructions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 15px;
}

.instructions text {
  display: block;
  color: #555;
  font-size: 14px;
  line-height: 1.5;
}

.image-url {
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.image-url text {
  font-size: 12px;
  color: #666;
}

.url-text {
  word-break: break-all;
  color: #3498db !important;
  font-family: monospace;
  font-size: 11px !important;
}

.target-area {
  margin-top: 10px;
  padding: 12px;
  border: 2px dashed #3498db;
  border-radius: 8px;
  background-color: #e8f4fc;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  transition: all 0.3s;
}

.target-area text {
  display: block;
  color: #3498db;
  font-size: 13px;
  text-align: center;
}

.target-hit {
  background-color: #d1f2eb;
  border-color: #2ecc71;
  border-style: solid;
}

.success-text {
  color: #27ae60 !important;
  font-weight: bold;
  margin-top: 5px !important;
}

.status {
  padding: 12px;
  border-radius: 8px;
  background-color: #f8f9fa;
  margin-bottom: 15px;
}

.status-text {
  display: block;
  text-align: center;
  font-weight: 500;
  color: #666;
}

.status-text.dragging {
  color: #e67e22;
  background-color: #fff9e6;
  padding: 8px;
  border-radius: 6px;
}

.status-text.success {
  color: #27ae60;
  background-color: #d4f8e8;
  padding: 8px;
  border-radius: 6px;
}

.stats {
  display: flex;
  justify-content: space-between;
  background-color: #f8f9fa;
  padding: 12px;
  border-radius: 8px;
}

.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
}

.stat-value {
  font-size: 18px;
  font-weight: 700;
  color: #3498db;
  margin-bottom: 4px;
}

.stat-label {
  font-size: 11px;
  color: #7f8c8d;
}

.position-info {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background-color: #f8f9fa;
  padding: 12px;
  border-radius: 8px;
}

.position-info text {
  display: block;
  font-size: 13px;
  color: #666;
}

.reset-btn {
  background-color: #3498db;
  color: white;
  border: none;
  padding: 15px;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 600;
  text-align: center;
  transition: all 0.3s;
  margin-top: 10px;
}

.reset-btn:active {
  background-color: #2980b9;
  transform: scale(0.98);
}

@media (min-width: 768px) {
  .main-content {
    flex-direction: row;
  }
  
  .canvas-wrapper {
    flex: 1;
  }
  
  .controls {
    flex: 1;
    min-width: 300px;
  }
}
</style>
