<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="dragCanvas"
          id="dragCanvas"
          class="canvas-element"
          :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
          @touchstart="handleTouchStart"
          @touchmove="handleTouchMove"
          @touchend="handleTouchEnd"
        ></canvas>
        
        <view class="canvas-status">
          <text>{{ statusText }}</text>
        </view>
      </view>
      
      <view class="controls">
        <view class="control-section">
          <text class="section-title">操作说明</text>
          <view class="instructions">
            <view class="instruction-item">
              <view class="step-number">1</view>
              <text>点击橙色方块</text>
            </view>
            <view class="instruction-item">
              <view class="step-number">2</view>
              <text>拖动到蓝色目标区域</text>
            </view>
            <view class="instruction-item">
              <view class="step-number">3</view>
              <text>释放手指完成拖放</text>
            </view>
          </view>
        </view>
        
        <view class="control-section">
          <text class="section-title">调试信息</text>
          <view class="debug-info">
            <text class="debug-item">方块位置: X={{ rect.x.toFixed(0) }}, Y={{ rect.y.toFixed(0) }}</text>
            <text class="debug-item">触摸位置: X={{ touchPos.x.toFixed(0) }}, Y={{ touchPos.y.toFixed(0) }}</text>
            <text class="debug-item">触摸状态: {{ isDragging ? '拖拽中' : '未拖拽' }}</text>
            <text class="debug-item">事件触发: {{ lastEvent }}</text>
          </view>
        </view>
        
        <view class="control-section">
          <text class="section-title">目标区域</text>
          <view :class="['target-display', { '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-section">
          <text class="section-title">统计数据</text>
          <view class="stats">
            <view class="stat-box">
              <text class="stat-value">{{ dragCount }}</text>
              <text class="stat-label">拖拽次数</text>
            </view>
            <view class="stat-box">
              <text class="stat-value">{{ successCount }}</text>
              <text class="stat-label">成功次数</text>
            </view>
            <view class="stat-box">
              <text class="stat-value">{{ Math.round(dragDistance) }}</text>
              <text class="stat-label">拖拽距离</text>
            </view>
          </view>
        </view>
        
        <view class="buttons">
          <button class="btn reset-btn" @tap="resetAll">重置所有</button>
          <button class="btn debug-btn" @tap="toggleDebug">调试模式: {{ debugMode ? '开启' : '关闭' }}</button>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      // Canvas尺寸
      canvasWidth: 350,
      canvasHeight: 500,
      
      // Canvas上下文
      ctx: null,
      
      // 图片对象
      duckImage: null,
      
      // 拖拽方块
      rect: {
        x: 50,
        y: 50,
        width: 54,
        height: 105,
        color: '#FF8C00',
        isDragging: false,
        dragOffsetX: 0,
        dragOffsetY: 0,
        lastX: 50,
        lastY: 50
      },
      
      // 目标区域
      target: {
        x: 150,
        y: 200,
        width: 130,
        height: 90,
        color: 'rgba(52, 152, 219, 0.3)'
      },
      
      // 触摸位置
      touchPos: {
        x: 0,
        y: 0,
        clientX: 0,
        clientY: 0
      },
      
      // Canvas位置信息
      canvasRect: {
        left: 0,
        top: 0,
        width: 0,
        height: 0
      },
      
      // 状态
      isDragging: false,
      isInTarget: false,
      dragCount: 0,
      successCount: 0,
      dragDistance: 0,
      statusText: '点击橙色方块开始拖拽',
      lastEvent: '无',
      debugMode: true,
      
      // 动画帧
      animationId: null,
      lastRenderTime: 0,
      renderInterval: 16 // ~60fps
    }
  },
  
  onLoad() {
    // 页面加载后初始化Canvas
    this.$nextTick(() => {
      setTimeout(() => {
        this.initCanvas()
        this.getCanvasPosition()
      }, 100)
    })
  },
  
  onUnload() {
    // 清理动画帧
    if (this.animationId) {
      cancelAnimationFrame(this.animationId)
    }
  },
  
  onShow() {
    // 页面显示时开始绘制
    this.startAnimation()
  },
  
  onHide() {
    // 页面隐藏时停止绘制
    if (this.animationId) {
      cancelAnimationFrame(this.animationId)
      this.animationId = null
    }
  },
  
  methods: {
    // 初始化Canvas
    initCanvas() {
      console.log('正在初始化Canvas...')
      
      // 在uni-app中必须使用uni.createCanvasContext
      this.ctx = uni.createCanvasContext('dragCanvas', this)
      
      if (this.ctx) {
        console.log('Canvas上下文创建成功')
        this.lastEvent = 'Canvas初始化成功'
        // 加载图片
        this.loadDuckImage()
      } else {
        console.error('Canvas上下文创建失败')
        this.lastEvent = 'Canvas初始化失败'
      }
    },
    
    // 加载鸭子图片
    loadDuckImage() {
      // 使用 uni.getImageInfo 获取图片信息
      uni.getImageInfo({
        src: '/static/dzm/img_duck.png',
        success: (res) => {
          console.log('鸭子图片加载成功:', res)
          this.duckImage = res.path
          this.lastEvent = '图片加载成功'
        },
        fail: (err) => {
          console.error('鸭子图片加载失败:', err)
          this.lastEvent = '图片加载失败'
        }
      })
    },
    
    // 获取Canvas元素位置 - 关键修复函数
    getCanvasPosition() {
      const query = uni.createSelectorQuery().in(this)
      query.select('#dragCanvas').boundingClientRect(res => {
        if (res) {
          this.canvasRect = {
            left: res.left,
            top: res.top,
            width: res.width,
            height: res.height
          }
          console.log('Canvas位置信息:', this.canvasRect)
          this.lastEvent = `Canvas位置: left=${res.left.toFixed(1)}, top=${res.top.toFixed(1)}`
        } else {
          console.error('无法获取Canvas位置信息')
          this.lastEvent = '无法获取Canvas位置'
        }
      }).exec()
    },
    
    // 开始动画循环
    startAnimation() {
      const animate = (timestamp) => {
        // 控制渲染频率
        if (timestamp - this.lastRenderTime >= this.renderInterval) {
          this.drawCanvas()
          this.lastRenderTime = timestamp
        }
        this.animationId = requestAnimationFrame(animate)
      }
      this.animationId = requestAnimationFrame(animate)
    },
    
    // 绘制Canvas
    drawCanvas() {
      if (!this.ctx) return
      
      // 清除Canvas
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      
      // 绘制目标区域
      this.drawTarget()
      
      // 绘制可拖拽方块
      this.drawDraggableRect()
      
      // 绘制状态信息
      this.drawDebugInfo()
      
      // 执行绘制
      this.ctx.draw(true) // 设置为true使用延迟绘制
    },
    
    // 绘制目标区域
    drawTarget() {
      // 绘制目标区域背景
      this.ctx.setFillStyle(this.target.color)
      this.ctx.fillRect(this.target.x, this.target.y, this.target.width, this.target.height)
      
      // 绘制目标区域边框
      this.ctx.setStrokeStyle(this.isInTarget ? '#2ecc71' : '#3498db')
      this.ctx.setLineWidth(2)
      this.ctx.setLineDash([5, 5])
      this.ctx.strokeRect(this.target.x, this.target.y, this.target.width, this.target.height)
      this.ctx.setLineDash([])
      
      // 绘制目标区域文字
      this.ctx.setFontSize(14)
      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
      )
    },
    
    // 绘制可拖拽方块
    drawDraggableRect() {
      const rect = this.rect
      
      // 如果图片已加载，绘制图片
      if (this.duckImage) {
        this.ctx.drawImage(this.duckImage, rect.x, rect.y, rect.width, rect.height)
      } else {
        // 图片未加载时，绘制占位方块
        this.ctx.setFillStyle(rect.color)
        this.ctx.fillRect(rect.x, rect.y, rect.width, rect.height)
        
        // 绘制方块边框
        this.ctx.setStrokeStyle('#333')
        this.ctx.setLineWidth(2)
        this.ctx.strokeRect(rect.x, rect.y, rect.width, rect.height)
        
        // 绘制"拖我"文字
        this.ctx.setFontSize(20)
        this.ctx.setFillStyle('#FFFFFF')
        this.ctx.setTextAlign('center')
        this.ctx.setTextBaseline('middle')
        this.ctx.fillText(
          '拖我',
          rect.x + rect.width / 2,
          rect.y + rect.height / 2
        )
      }
      
      // 如果正在拖拽，绘制拖拽效果
      if (rect.isDragging) {
        // 绘制拖拽阴影
        this.ctx.setFillStyle('rgba(231, 76, 60, 0.3)')
        this.ctx.fillRect(rect.x, rect.y, rect.width, rect.height)
        
        // 绘制拖拽边框
        this.ctx.setStrokeStyle('#e74c3c')
        this.ctx.setLineWidth(3)
        this.ctx.setLineDash([5, 5])
        this.ctx.strokeRect(rect.x - 5, rect.y - 5, rect.width + 10, rect.height + 10)
        this.ctx.setLineDash([])
      }
    },
    
    // 绘制调试信息
    drawDebugInfo() {
      if (!this.debugMode) return
      
      this.ctx.setFontSize(12)
      this.ctx.setFillStyle('#666666')
      this.ctx.setTextAlign('left')
      
      // 方块位置
      this.ctx.fillText(
        `方块: (${Math.round(this.rect.x)}, ${Math.round(this.rect.y)})`,
        10, 20
      )
      
      // 触摸位置
      this.ctx.fillText(
        `触摸: (${Math.round(this.touchPos.x)}, ${Math.round(this.touchPos.y)})`,
        10, 40
      )
      
      // 状态信息
      this.ctx.fillText(
        `状态: ${this.isDragging ? '拖拽中' : '静止'}`,
        10, 60
      )
      
      // 拖拽次数
      this.ctx.fillText(
        `次数: ${this.dragCount}`,
        10, 80
      )
    },
    
    // 检查触摸点是否在方块内
    checkTouchInRect(x, y) {
      const rect = this.rect
      return x >= rect.x && 
             x <= rect.x + rect.width && 
             y >= rect.y && 
             y <= rect.y + rect.height
    },
    
    // 检查方块是否在目标区域内
    checkRectInTarget() {
      const rect = this.rect
      const target = this.target
      
      // 计算方块中心点
      const rectCenterX = rect.x + rect.width / 2
      const rectCenterY = rect.y + rect.height / 2
      
      // 检查中心点是否在目标区域内
      const isInTarget = 
        rectCenterX >= target.x &&
        rectCenterX <= target.x + target.width &&
        rectCenterY >= target.y &&
        rectCenterY <= target.y + target.height
      
      this.isInTarget = isInTarget
      return isInTarget
    },
    
    // 计算两点距离
    calculateDistance(x1, y1, x2, y2) {
      return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
    },
    
    // 触摸开始事件
    handleTouchStart(e) {
      console.log('触摸开始事件触发', e)
      this.lastEvent = 'touchstart'
      
      // 获取触摸点
      const touch = e.touches[0]
      if (!touch) {
        console.error('没有触摸点信息')
        return
      }
      
      // 确保Canvas位置信息是最新的
      this.getCanvasPosition()
      
      // 异步获取Canvas位置后执行检查
      setTimeout(() => {
        // 计算相对于Canvas的坐标
        const touchX = touch.clientX - this.canvasRect.left
        const touchY = touch.clientY - this.canvasRect.top
        
        console.log(`触摸点 - 客户端: (${touch.clientX}, ${touch.clientY})`)
        console.log(`Canvas位置: left=${this.canvasRect.left}, top=${this.canvasRect.top}`)
        console.log(`触摸点相对Canvas: (${touchX}, ${touchY})`)
        
        // 更新触摸位置
        this.touchPos = {
          x: touchX,
          y: touchY,
          clientX: touch.clientX,
          clientY: touch.clientY
        }
        
        // 检查是否点击在方块上
        if (this.checkTouchInRect(touchX, touchY)) {
          console.log('触摸点在方块内，开始拖拽')
          
          // 设置拖拽状态和偏移量
          this.rect.isDragging = true
          this.rect.dragOffsetX = touchX - this.rect.x
          this.rect.dragOffsetY = touchY - this.rect.y
          this.rect.lastX = this.rect.x
          this.rect.lastY = this.rect.y
          
          this.isDragging = true
          this.statusText = '拖拽中...'
          
          console.log(`拖拽偏移量: offsetX=${this.rect.dragOffsetX}, offsetY=${this.rect.dragOffsetY}`)
        } else {
          console.log('触摸点不在方块内')
          this.statusText = '请点击橙色方块'
        }
      }, 50)
    },
    
    // 触摸移动事件 - 关键修复函数
    handleTouchMove(e) {
      // 只有开始拖拽后才处理移动事件
      if (!this.rect.isDragging) {
        return
      }
      
      e.preventDefault()
      e.stopPropagation()
      
      this.lastEvent = 'touchmove'
      
      const touch = e.touches[0]
      if (!touch) return
      
      // 计算相对于Canvas的坐标
      const touchX = touch.clientX - this.canvasRect.left
      const touchY = touch.clientY - this.canvasRect.top
      
      // 更新触摸位置
      this.touchPos = {
        x: touchX,
        y: touchY,
        clientX: touch.clientX,
        clientY: touch.clientY
      }
      
      // 计算移动距离
      const distance = this.calculateDistance(
        this.rect.x,
        this.rect.y,
        touchX - this.rect.dragOffsetX,
        touchY - this.rect.dragOffsetY
      )
      
      this.dragDistance += distance
      
      // 关键修复：直接更新方块位置
      const newX = touchX - this.rect.dragOffsetX
      const newY = touchY - this.rect.dragOffsetY
      
      console.log(`触摸移动: 新位置(${newX}, ${newY})，旧位置(${this.rect.x}, ${this.rect.y})`)
      
      // 更新方块位置
      this.rect.x = newX
      this.rect.y = newY
      
      // 限制边界
      this.rect.x = Math.max(0, Math.min(
        this.canvasWidth - this.rect.width,
        this.rect.x
      ))
      
      this.rect.y = Math.max(0, Math.min(
        this.canvasHeight - this.rect.height,
        this.rect.y
      ))
      
      // 检查是否进入目标区域
      this.checkRectInTarget()
      
      // 强制立即重绘 - 关键修复
      this.forceRedraw()
    },
    
    // 强制立即重绘
    forceRedraw() {
      if (this.ctx) {
        // 直接调用绘制函数，不等待下一帧
        this.drawCanvas()
      }
    },
    
    // 触摸结束事件
    handleTouchEnd() {
      console.log('触摸结束事件触发')
      this.lastEvent = 'touchend'
      
      if (this.rect.isDragging) {
        this.rect.isDragging = false
        this.isDragging = false
        
        // 增加拖拽次数
        this.dragCount++
        
        // 检查是否成功放入目标区域
        if (this.checkRectInTarget()) {
          this.successCount++
          this.statusText = '成功放入目标区域！'
        } else {
          this.statusText = '拖拽完成，未放入目标区域'
        }
        
        console.log(`拖拽结束，总次数: ${this.dragCount}`)
        
        // 强制重绘以移除拖拽效果
        this.forceRedraw()
      }
    },
    
    // 重置所有状态
    resetAll() {
      this.rect.x = 50
      this.rect.y = 50
      this.rect.isDragging = false
      this.isDragging = false
      this.isInTarget = false
      this.dragCount = 0
      this.successCount = 0
      this.dragDistance = 0
      this.statusText = '已重置，点击橙色方块开始拖拽'
      this.lastEvent = '重置'
      
      // 重新获取Canvas位置
      this.getCanvasPosition()
      
      // 强制重绘
      this.forceRedraw()
    },
    
    // 切换调试模式
    toggleDebug() {
      this.debugMode = !this.debugMode
      this.forceRedraw()
    }
  }
}
</script>

<style>
.canvas-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}

.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: 20px;
  font-weight: 700;
  color: #2c3e50;
  margin-bottom: 8px;
}

.subtitle {
  display: block;
  font-size: 14px;
  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-status {
  margin-top: 10px;
  padding: 10px 15px;
  background-color: #f8f9fa;
  border-radius: 8px;
  width: 100%;
  text-align: center;
}

.canvas-status text {
  font-size: 14px;
  color: #495057;
  font-weight: 500;
}

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

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

.section-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: 10px;
}

.instruction-item {
  display: flex;
  align-items: center;
  gap: 10px;
}

.step-number {
  width: 24px;
  height: 24px;
  background-color: #3498db;
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
}

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

.debug-item {
  font-size: 12px;
  color: #666;
  font-family: monospace;
}

.target-display {
  background-color: #e8f4fc;
  border: 2px dashed #3498db;
  border-radius: 8px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: all 0.3s;
}

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

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

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

.stats {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}

.stat-box {
  flex: 1;
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

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

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

.buttons {
  display: flex;
  gap: 10px;
}

.btn {
  flex: 1;
  padding: 12px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  border: none;
  transition: all 0.2s;
}

.btn:active {
  transform: scale(0.98);
}

.reset-btn {
  background-color: #3498db;
  color: white;
}

.debug-btn {
  background-color: #6c757d;
  color: white;
}

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