onMounted(() => { 
 
 
  // 创建图片对象 
 
 
  const imgElement = new Image(); 
 
 
  // imgElement.src = testImage; // 图片路径,注意使用公共路径 
 
 
  // imgElement.src = '@/assets/images/test.png' 
 
 
  // imgElement.src = './../../assets/images/test.png' 
 
 
  // imgElement.src = './vite.svg' 
 
 
  // imgElement.src = './test.png' 
 
 
  imgElement.src = './1.jpg' 
 
 
 
     
 
 
  imgElement.onload = function() { 
 
 
  // 获取图片宽高 
 
 
  const imgWidth = imgElement.width; 
 
 
  const imgHeight = imgElement.height; 
 
 
 
     
 
 
  // 初始化 Fabric 画布,尺寸与图片一致 
 
 
  const canvas = new fabric.Canvas(canvasRef.value, { 
 
 
  width: imgWidth, 
 
 
  height: imgHeight 
 
 
  }); 
 
 
 
     
 
 
  // 创建背景图片 
 
 
  const bgImage = new fabric.Image(imgElement, { 
 
 
  scaleX: 1, 
 
 
  scaleY: 1, 
 
 
  selectable: false, // 设置背景图片不可选 
 
 
  }); 
 
 
 
     
 
 
  // 将图片设置为背景 
 
 
  canvas.setBackgroundImage(bgImage, canvas.renderAll.bind(canvas)); 
 
 
 
     
 
 
  // 定义变量 
 
 
  let isDrawing = false; // 是否正在绘制多边形 
 
 
  let points = []; // 存储多边形的点 
 
 
  let pointObjects = []; // 存储点的可视化对象 
 
 
  let lineObjects = []; // 存储永久线段对象 
 
 
  let finalPolygon = null; // 最终多边形 
 
 
  let firstPoint = null; // 第一个点(用于闭合多边形) 
 
 
 
     
 
 
  // 动态元素 - 随鼠标移动更新 
 
 
  let activeLine = null; // 当前鼠标位置的活动线 
 
 
  let activeShape = null; // 当前动态多边形 
 
 
  
 
 
     
 
 
  let blueColor = 'blue' 
 
 
  let redColor = 'red' 
 
 
  // let otherColor = 'rgb(201, 201, 201)' 
 
 
  let otherColor = blueColor 
 
 
  let linkLineColor = 'rgb(51, 164, 255)' 
 
 
  let fillColor = 'rgb(232, 241, 249)' 
 
 
  let endColor = 'rgb(227, 242, 202)' 
 
 
  // let endColor = blueColor 
 
 
  // let endStrokeColor = 'rgb(169, 224, 36)' 
 
 
  let endStrokeColor = blueColor 
 
 
 
     
 
 
  // 创建点的函数(用于可视化) 
 
 
  const createPoint = (x, y, isFirst = false) => { 
 
 
  const circle = new fabric.Circle({ 
 
 
  radius: 5, 
 
 
  fill: 'white', 
 
 
  stroke: isFirst ? redColor : otherColor, 
 
 
  strokeWidth: 1, 
 
 
  selectable: false, 
 
 
  originX: 'center', 
 
 
  originY: 'center', 
 
 
  left: x, 
 
 
  top: y 
 
 
  }); 
 
 
 
     
 
 
  canvas.add(circle); 
 
 
  return circle; 
 
 
  }; 
 
 
 
     
 
 
  // 创建连接线的函数 
 
 
  const createLine = (fromX, fromY, toX, toY) => { 
 
 
  const line = new fabric.Line([fromX, fromY, toX, toY], { 
 
 
  stroke: linkLineColor, 
 
 
  strokeWidth: 2, 
 
 
  selectable: false 
 
 
  }); 
 
 
 
     
 
 
  canvas.add(line); 
 
 
  return line; 
 
 
  }; 
 
 
 
     
 
 
  // 检查点是否接近第一个点 
 
 
  const isNearFirstPoint = (x, y) => { 
 
 
  if (!firstPoint) return false; 
 
 
 
     
 
 
  const distance = Math.sqrt( 
 
 
  Math.pow(x - firstPoint.x, 2) + 
 
 
  Math.pow(y - firstPoint.y, 2) 
 
 
  ); 
 
 
 
     
 
 
  return distance < 20; // 20像素范围内视为接近 
 
 
  }; 
 
 
 
     
 
 
  // 生成或更新动态多边形 
 
 
  const generatePolygon = (mousePointer) => { 
 
 
  // 确保有足够的点 
 
 
  if (!isDrawing || points.length < 1) return; 
 
 
 
     
 
 
  // 清除旧的活动线 
 
 
  if (activeLine) { 
 
 
  canvas.remove(activeLine); 
 
 
  activeLine = null; 
 
 
  } 
 
 
 
     
 
 
  // 清除旧的活动形状 
 
 
  if (activeShape) { 
 
 
  canvas.remove(activeShape); 
 
 
  activeShape = null; 
 
 
  } 
 
 
 
     
 
 
  // 创建动态线段 - 从最后一个点到当前鼠标位置 
 
 
  const lastPoint = points[points.length - 1]; 
 
 
  activeLine = new fabric.Line( 
 
 
  [lastPoint.x, lastPoint.y, mousePointer.x, mousePointer.y], 
 
 
  { 
 
 
  stroke: linkLineColor, 
 
 
  strokeWidth: 2, 
 
 
  selectable: false 
 
 
  } 
 
 
  ); 
 
 
  canvas.add(activeLine); 
 
 
 
     
 
 
  // 如果有至少2个点,创建动态多边形 
 
 
  if (points.length >= 2) { 
 
 
  // 创建包含所有点和当前鼠标位置的点数组 
 
 
  let polygonPoints = [...points]; 
 
 
 
     
 
 
  // 如果鼠标接近第一个点,使用第一个点作为闭合点 
 
 
  if (isNearFirstPoint(mousePointer.x, mousePointer.y)) { 
 
 
  polygonPoints.push(firstPoint); 
 
 
  } else { 
 
 
  polygonPoints.push({ x: mousePointer.x, y: mousePointer.y }); 
 
 
  } 
 
 
 
     
 
 
  // 创建动态多边形 
 
 
  activeShape = new fabric.Polygon( 
 
 
  polygonPoints.map(p => ({ x: p.x, y: p.y })), 
 
 
  { 
 
 
  fill: fillColor, 
 
 
  stroke: fillColor, 
 
 
  strokeWidth: 1, 
 
 
  selectable: false, 
 
 
  globalCompositeOperation: 'multiply' // 使用混合模式而不是透明度 
 
 
  } 
 
 
  ); 
 
 
 
     
 
 
  // 添加到画布 
 
 
  canvas.add(activeShape); 
 
 
  // 确保背景图在最下层 
 
 
  activeShape.sendToBack(); 
 
 
  bgImage.sendToBack(); 
 
 
  } 
 
 
 
     
 
 
  canvas.renderAll(); 
 
 
  }; 
 
 
 
     
 
 
  // 完成多边形绘制 
 
 
  const completePolygon = () => { 
 
 
  if (points.length < 3) { 
 
 
  showMessage('至少需要3个点才能形成多边形', 'warning'); 
 
 
  return; 
 
 
  } 
 
 
 
     
 
 
  // 清除动态元素 
 
 
  if (activeLine) { 
 
 
  canvas.remove(activeLine); 
 
 
  activeLine = null; 
 
 
  } 
 
 
  // 清除动态多边形 
 
 
  if (activeShape) { 
 
 
  canvas.remove(activeShape); 
 
 
  activeShape = null; 
 
 
  } 
 
 
 
     
 
 
  // 移除所有线段 
 
 
  lineObjects.forEach(line => { 
 
 
  if (line) canvas.remove(line); 
 
 
  }); 
 
 
 
     
 
 
  // 创建最终的多边形 
 
 
  finalPolygon = new fabric.Polygon(points.map(p => ({ x: p.x, y: p.y })), { 
 
 
  fill: endColor, 
 
 
  stroke: endStrokeColor, // 线段颜色为rgb(169, 224, 36) 
 
 
  strokeWidth: 2, 
 
 
  selectable: true, 
 
 
  globalCompositeOperation: 'multiply' // 使用混合模式而不是透明度 
 
 
  }); 
 
 
 
     
 
 
  // 移除所有临时点 
 
 
  pointObjects.forEach(point => { 
 
 
  if (point) canvas.remove(point); 
 
 
  }); 
 
 
 
     
 
 
  // 添加多边形到画布 
 
 
  canvas.add(finalPolygon); 
 
 
  canvas.renderAll(); 
 
 
 
     
 
 
  // 重置状态 
 
 
  points = []; 
 
 
  pointObjects = []; 
 
 
  lineObjects = []; 
 
 
  isDrawing = false; 
 
 
  firstPoint = null; 
 
 
 
     
 
 
  showMessage('多边形绘制完成', 'success'); 
 
 
  }; 
 
 
 
     
 
 
  // 监听鼠标按下事件 
 
 
  canvas.on('mouse:down', function(o) { 
 
 
  const pointer = canvas.getPointer(o.e); 
 
 
 
     
 
 
  // 检查是否点击在现有对象上 
 
 
  // 注意:这里可能导致问题,因为activeLine和activeShape也是对象 
 
 
  // 只有明确是polygon类型的最终多边形才应该阻止操作 
 
 
  if (o.target && o.target.type === 'polygon' && !isDrawing) { 
 
 
  // 如果点击了现有多边形且不在绘制模式,只进行选择 
 
 
  return; 
 
 
  } 
 
 
 
     
 
 
  // 如果是第一次点击,开始绘制 
 
 
  if (!isDrawing) { 
 
 
  // 初始化绘制状态 
 
 
  isDrawing = true; 
 
 
  points = []; 
 
 
  pointObjects = []; 
 
 
  lineObjects = []; 
 
 
 
     
 
 
  // 记录第一个点 
 
 
  firstPoint = { x: pointer.x, y: pointer.y }; 
 
 
  points.push(firstPoint); 
 
 
 
     
 
 
  // 创建第一个点的可视标记(红色表示起点) 
 
 
  const firstPointObject = createPoint(pointer.x, pointer.y, true); 
 
 
  pointObjects.push(firstPointObject); 
 
 
 
     
 
 
  showMessage(`开始绘制${sidesCount.value}边形,请继续点击确定顶点位置`, 'info'); 
 
 
  } else { 
 
 
  console.log('当前点数:', points.length, '最大点数:', sidesCount.value); 
 
 
 
     
 
 
  // 检查是否点击了第一个点(闭合多边形) 
 
 
  if (isNearFirstPoint(pointer.x, pointer.y)) { 
 
 
  // 如果已经有至少3个点且点击接近第一个点,闭合多边形 
 
 
  if (points.length >= 5) { 
 
 
  completePolygon(); 
 
 
  } else { 
 
 
  showMessage(`需要${sidesCount.value}个点才能闭合多边形。`, 'warning'); 
 
 
  } 
 
 
  } else { 
 
 
  // 只有在未达到最大点数时才添加新点 
 
 
  if (points.length < sidesCount.value) { 
 
 
  // 继续添加点 
 
 
  const newPoint = { x: pointer.x, y: pointer.y }; 
 
 
  points.push(newPoint); 
 
 
 
     
 
 
  // 创建点的可视标记 
 
 
  const pointObject = createPoint(pointer.x, pointer.y); 
 
 
  pointObjects.push(pointObject); 
 
 
 
     
 
 
  // 添加永久连接线 
 
 
  if (points.length >= 2) { 
 
 
  const lastIndex = points.length - 1; 
 
 
  const line = createLine( 
 
 
  points[lastIndex - 1].x, points[lastIndex - 1].y, 
 
 
  points[lastIndex].x, points[lastIndex].y 
 
 
  ); 
 
 
  lineObjects.push(line); 
 
 
  } 
 
 
 
     
 
 
  // if (points.length < sidesCount.value) { 
 
 
  // showMessage(`已添加${points.length}个点,继续点击添加更多点`, 'info'); 
 
 
  // } 
 
 
 
     
 
 
  // 如果刚好达到最大点数,提示用户 
 
 
  if (points.length === sidesCount.value) { 
 
 
  showMessage(`已达到最大点数${sidesCount.value},请点击第一个点完成绘制`, 'warning'); 
 
 
  } 
 
 
  } else { 
 
 
  // 已达到最大点数,点击无效,只能点击起点完成绘制 
 
 
  showMessage(`已达到最大点数${sidesCount.value},请点击第一个点完成绘制`, 'warning'); 
 
 
  } 
 
 
 
     
 
 
  // 强制更新画布 
 
 
  canvas.renderAll(); 
 
 
  } 
 
 
  } 
 
 
  }); 
 
 
 
     
 
 
  // 监听鼠标移动事件 
 
 
  canvas.on('mouse:move', function(o) { 
 
 
  if (!isDrawing) return; 
 
 
 
     
 
 
  const pointer = canvas.getPointer(o.e); 
 
 
 
     
 
 
  // 生成动态多边形 
 
 
  generatePolygon(pointer); 
 
 
  }); 
 
 
 
     
 
 
  // 取消绘制的快捷键(Esc键) 
 
 
  document.addEventListener('keydown', (e) => { 
 
 
  if (e.key === 'Escape' && isDrawing) { 
 
 
  // 清除所有元素 
 
 
  if (activeLine) { 
 
 
  canvas.remove(activeLine); 
 
 
  } 
 
 
 
     
 
 
  if (activeShape) { 
 
 
  canvas.remove(activeShape); 
 
 
  } 
 
 
 
     
 
 
  pointObjects.forEach(point => { 
 
 
  if (point) canvas.remove(point); 
 
 
  }); 
 
 
 
     
 
 
  lineObjects.forEach(line => { 
 
 
  if (line) canvas.remove(line); 
 
 
  }); 
 
 
 
     
 
 
  // 重置状态 
 
 
  points = []; 
 
 
  pointObjects = []; 
 
 
  lineObjects = []; 
 
 
  activeLine = null; 
 
 
  activeShape = null; 
 
 
  isDrawing = false; 
 
 
  firstPoint = null; 
 
 
 
     
 
 
  canvas.renderAll(); 
 
 
  showMessage('已取消绘制', 'info'); 
 
 
  } 
 
 
  }); 
 
 
  }; 
 
 
  }) 
 
 
  </script> 
 
 
  
全部评论