区域画框:前端实现的带有网格背景、支持不规则框绘制、节点可拖动、右键删除节点以及获取坐标等功能的画框,适用于——摄像头区域侦测设置、预置位设置等

06-01 1363阅读

一、概览

基于网格的图形编辑组件:突出其基于网格背景,同时具备图形绘制、编辑(包括节点操作等)的功能。用户可以在网格背景下绘制不规则的图形元素,并对其进行各种编辑操作,方便创建复杂的图形结构。

二、预览

区域画框:前端实现的带有网格背景、支持不规则框绘制、节点可拖动、右键删除节点以及获取坐标等功能的画框,适用于——摄像头区域侦测设置、预置位设置等

 

三、获取坐标的格式

[{"x":240,"y":135},{"x":240,"y":225},{"x":400,"y":225},{"x":400,"y":135},...]

 

四、功能介绍

结合前面画框功能及常见应用场景,为你详细列举该功能可能具备的特性:

  1. 基础绘制功能
    • 自由绘制不规则形状:用户可通过鼠标或触摸操作,自由绘制任意形状的框,满足对复杂图形的绘制需求,如在图像标注场景中绘制物体的不规则轮廓。
        • 支持多种绘制模式:除了直接绘制,还提供点选模式,用户点击多个点后自动连接形成多边形框;以及手绘模式,模拟真实笔触,让绘制更加自然流畅。
          1. 编辑功能
            • 节点操作:绘制的框上显示可操作节点,用户能拖动节点改变框的形状,实现对已绘制图形的精细调整,适用于对标注精度要求较高的场景。
                • 添加和删除节点:在绘制过程中或绘制完成后,用户可以随时添加新的节点来细化图形,也能删除不需要的节点,优化绘制的框。比如在绘制复杂的地图边界时,通过添加和删除节点来精确描绘边界形状。
                    • 整体移动和缩放:支持对整个绘制的框进行移动和缩放操作,方便调整框在画布中的位置和大小,以适应不同的需求。在可视化设计中,可通过整体移动和缩放画框来调整元素布局。
                      1. 样式与属性设置
                        • 边框样式设置:用户可以自定义框的边框样式,包括线条颜色、粗细、虚线或实线等,增强视觉区分度。在图像编辑中,不同类型的标注可以使用不同样式的边框。
                            • 填充设置:为绘制的框添加填充颜色或透明度设置,使框内区域与背景区分开来,或者根据需要设置半透明效果,以便同时查看框内和框外的内容。在数据可视化中,填充不同颜色的框可以代表不同的数据类别。
                              1. 交互功能
                                • 鼠标交互:通过鼠标的点击、拖动、右键操作实现绘制、选择、删除等功能。例如,点击开始绘制,拖动绘制线条,右键点击删除节点或整个框。
                                    • 触摸交互(适用于移动设备):支持触摸操作,如触摸屏幕绘制、缩放和移动框,满足在移动设备上的使用需求。在移动办公或现场数据采集场景中,用户可以直接在平板或手机上进行操作。
                                        • 快捷键操作:提供快捷键绑定,如使用特定的按键组合来快速完成常见操作,如撤销、重做、清除等,提高操作效率。对于频繁使用该功能的用户,快捷键操作能大大提升工作速度。
                                          1. 数据处理功能
                                            • 获取坐标数据:能够获取绘制框的顶点坐标数据,这些数据可以用于后续的分析、处理或存储。在机器学习数据标注中,坐标数据是训练模型的重要依据。
                                                • 数据导出与导入:支持将绘制的框及其相关属性数据导出为特定格式(如 JSON、XML),方便在不同系统或应用之间共享数据;同时也能导入已有的数据,实现数据的复用和编辑。在团队协作的标注项目中,数据的导出和导入功能可以方便不同标注员之间的数据交互。
                                                  1. 辅助功能
                                                    • 网格背景:提供可切换的网格背景,帮助用户更准确地绘制和对齐图形。在绘制具有规则形状或需要精确位置的图形时,网格背景能起到很好的辅助作用。
                                                        • 撤销和重做:支持撤销上一步操作和重做已撤销的操作,让用户在绘制过程中可以随时纠正错误,避免从头开始绘制的麻烦。
                                                            • 清除与重置:可以清除当前绘制的所有框,或者重置整个绘制区域,回到初始状态,方便用户重新开始绘制。

                                                              五、适用于

                                                              摄像头区域侦测设置、摄像头预置位设置、区域画框等

                                                              六、代码实现,提供vue2、vue3、原生js

                                                              1、 vue3组件实现,父组件注册该组件即可使用

                                                                
                                                                
                                                                  
                                                                  
                                                                  
                                                                    
                                                                    撤销
                                                                    
                                                                    获取坐标
                                                                    
                                                                    重置
                                                                  
                                                                
                                                              
                                                              
                                                              import { ref, onMounted, watch } from "vue";
                                                              // 定义组件接收的 props
                                                              const props = defineProps({
                                                                // canvas 容器的宽度,默认为 640
                                                                canvasWidth: {
                                                                  type: Number,
                                                                  default: 640,
                                                                },
                                                                // canvas 容器的高度,默认为 360
                                                                canvasHeight: {
                                                                  type: Number,
                                                                  default: 360,
                                                                },
                                                                // 初始的点数组,用于数据反显,默认为空数组
                                                                initialPoints: {
                                                                  type: Array,
                                                                  // default: () => [],
                                                                  default: () => [
                                                                    { x: 240, y: 135 },
                                                                    { x: 240, y: 225 },
                                                                    { x: 400, y: 225 },
                                                                    { x: 400, y: 135 },
                                                                  ],
                                                                },
                                                              });
                                                              // 引用 canvas 元素
                                                              const gridCanvas = ref(null);
                                                              // 存储当前不规则图形的点数组,初始值为传入的初始点数据
                                                              const points = ref(props.initialPoints.slice());
                                                              // 标记是否正在绘制图形
                                                              const isDrawing = ref(false);
                                                              // 标记是否正在拖动某个点
                                                              const isDragging = ref(false);
                                                              // 当前正在拖动的点的索引
                                                              const draggedPointIndex = ref(-1);
                                                              // 网格的大小
                                                              const gridSize = ref(10);
                                                              // 画布内边距,这里设置为 0 以铺满整个 canvas
                                                              const framePadding = ref(0);
                                                              // canvas 的 2D 上下文对象
                                                              let ctx = null;
                                                              // 初始化 canvas 并绘制网格
                                                              const initCanvas = () => {
                                                                const canvas = gridCanvas.value;
                                                                // 设置 canvas 的宽度和高度
                                                                canvas.width = props.canvasWidth;
                                                                canvas.height = props.canvasHeight;
                                                                // 获取 canvas 的 2D 上下文对象
                                                                ctx = canvas.getContext("2d");
                                                                // 绘制网格
                                                                drawGrid();
                                                              };
                                                              // 绘制网格
                                                              const drawGrid = () => {
                                                                // 清空 canvas 内容
                                                                ctx.clearRect(0, 0, props.canvasWidth, props.canvasHeight);
                                                                // 设置网格线的颜色和宽度
                                                                ctx.strokeStyle = "rgba(0, 255, 0, 0.5)";
                                                                ctx.lineWidth = 1;
                                                                // 绘制垂直网格线
                                                                for (let x = 0; x  {
                                                                // 限制鼠标点击的坐标在 canvas 范围内
                                                                const x = Math.min(Math.max(e.offsetX, 0), props.canvasWidth);
                                                                const y = Math.min(Math.max(e.offsetY, 0), props.canvasHeight);
                                                                const clickRadius = 5;
                                                                // 检查是否点击在某个点上
                                                                for (let i = 0; i  0) {
                                                                  // 重新绘制 canvas
                                                                  redraw();
                                                                  // 绘制临时的图形(包含当前鼠标位置)
                                                                  drawShape([...points.value, { x, y }]);
                                                                } else if (isDragging.value) {
                                                                  // 更新被拖动点的坐标
                                                                  points.value[draggedPointIndex.value] = { x, y };
                                                                  // 重新绘制 canvas
                                                                  redraw();
                                                                }
                                                              };
                                                              // 处理鼠标松开事件
                                                              const handleMouseUp = () => {
                                                                // 停止绘制和拖动状态
                                                                isDrawing.value = false;
                                                                isDragging.value = false;
                                                                draggedPointIndex.value = -1;
                                                                // 绘制最终的图形
                                                                drawShape();
                                                              };
                                                              // 处理鼠标右键点击事件
                                                              const handleContextMenu = (e) => {
                                                                // 阻止默认的右键菜单行为
                                                                e.preventDefault();
                                                                // 限制鼠标右键点击的坐标在 canvas 范围内
                                                                const x = Math.min(Math.max(e.offsetX, 0), props.canvasWidth);
                                                                const y = Math.min(Math.max(e.offsetY, 0), props.canvasHeight);
                                                                const clickRadius = 5;
                                                                // 检查是否右键点击在某个点上
                                                                for (let i = 0; i  {
                                                                  ctx.beginPath();
                                                                  ctx.arc(x, y, 5, 0, 2 * Math.PI);
                                                                  ctx.fill();
                                                                });
                                                              };
                                                              // 重新绘制 canvas(先初始化,再绘制图形)
                                                              const redraw = () => {
                                                                initCanvas();
                                                                drawShape();
                                                              };
                                                              // 撤销上一步操作
                                                              const undo = () => {
                                                                if (points.value.length > 0) {
                                                                  // 移除最后一个点
                                                                  points.value.pop();
                                                                  // 重新绘制 canvas
                                                                  redraw();
                                                                }
                                                              };
                                                              // 获取当前不规则图形各点的坐标
                                                              const getCoordinates = () => {
                                                                console.log(
                                                                  "不规则框坐标:",
                                                                  points.value.map((p) => ({ x: p.x, y: p.y }))
                                                                );
                                                              };
                                                              // 重置 canvas 内容
                                                              const reset = () => {
                                                                // 清空点数组
                                                                //   points.value = [];
                                                                points.value = [
                                                                  { x: 240, y: 135 },
                                                                  { x: 240, y: 225 },
                                                                  { x: 400, y: 225 },
                                                                  { x: 400, y: 135 },
                                                                ];
                                                                // 重新绘制 canvas
                                                                redraw();
                                                              };
                                                              onMounted(() => {
                                                                // 初始化 canvas
                                                                initCanvas();
                                                                // 绘制初始的不规则图形
                                                                drawShape();
                                                                const canvas = gridCanvas.value;
                                                                // 绑定鼠标事件
                                                                canvas.addEventListener("mousedown", handleMouseDown);
                                                                canvas.addEventListener("mousemove", handleMouseMove);
                                                                canvas.addEventListener("mouseup", handleMouseUp);
                                                                canvas.addEventListener("contextmenu", handleContextMenu);
                                                              });
                                                              // 监听 canvas 宽高的变化,重新初始化 canvas 并绘制图形
                                                              watch([() => props.canvasWidth, () => props.canvasHeight], () => {
                                                                initCanvas();
                                                                drawShape();
                                                              });
                                                              // 监听初始点数据的变化,更新 points 数组,重新初始化 canvas 并绘制图形
                                                              watch(
                                                                () => props.initialPoints,
                                                                (newPoints) => {
                                                                  points.value = newPoints.slice();
                                                                  initCanvas();
                                                                  drawShape();
                                                                }
                                                              );
                                                              // 导出函数以供外部调用,可以使用refs方法调用
                                                              defineExpose({
                                                                getCoordinates,
                                                                reset,
                                                                undo,
                                                              });
                                                              
                                                              
                                                              .canvas-container {
                                                                position: relative;
                                                                margin: 20px auto;
                                                                border: 1px solid #ccc;
                                                                overflow: hidden;
                                                              }
                                                              canvas {
                                                                display: block;
                                                                width: 100%;
                                                                height: 100%;
                                                                background-color: #f0f0f0;
                                                              }
                                                              .button-group {
                                                                position: absolute;
                                                                top: 10px;
                                                                left: 10px;
                                                                z-index: 10;
                                                              }
                                                              button {
                                                                padding: 6px 12px;
                                                                font-size: 14px;
                                                                cursor: pointer;
                                                                background-color: #fff;
                                                                border: 1px solid #ddd;
                                                                margin-right: 8px;
                                                              }
                                                              
                                                              

                                                              2、vue2 组件实现,父组件注册该组件即可使用

                                                                
                                                                
                                                                  
                                                                  
                                                                  
                                                                    
                                                                    撤销
                                                                    
                                                                    获取坐标
                                                                    
                                                                    重置
                                                                  
                                                                
                                                              
                                                              
                                                              export default {
                                                                // 接收父组件传递的参数
                                                                props: {
                                                                  // canvas 容器的宽度,默认为 640
                                                                  canvasWidth: {
                                                                    type: Number,
                                                                    default: 640,
                                                                  },
                                                                  // canvas 容器的高度,默认为 360
                                                                  canvasHeight: {
                                                                    type: Number,
                                                                    default: 360,
                                                                  },
                                                                  // 初始的点数组,用于数据反显,默认为空数组
                                                                  initialPoints: {
                                                                    type: Array,
                                                                    // default: () => [],
                                                                    default: () => [
                                                                      { x: 240, y: 135 },
                                                                      { x: 240, y: 225 },
                                                                      { x: 400, y: 225 },
                                                                      { x: 400, y: 135 },
                                                                    ],
                                                                  },
                                                                },
                                                                data() {
                                                                  return {
                                                                    // 存储当前不规则图形的点数组
                                                                    points: [],
                                                                    // 标记是否正在绘制图形
                                                                    isDrawing: false,
                                                                    // 标记是否正在拖动某个点
                                                                    isDragging: false,
                                                                    // 当前正在拖动的点的索引
                                                                    draggedPointIndex: -1,
                                                                    // 网格的大小
                                                                    gridSize: 10,
                                                                    // 画布内边距,这里设置为 0 以铺满整个 canvas
                                                                    framePadding: 0,
                                                                    // canvas 的 2D 上下文对象
                                                                    ctx: null,
                                                                  };
                                                                },
                                                                mounted() {
                                                                  // 将初始点数据赋值给 points 数组,实现数据反显
                                                                  this.points = this.initialPoints.slice();
                                                                  // 初始化 canvas
                                                                  this.initCanvas();
                                                                  // 绑定鼠标事件
                                                                  this.bindEvents();
                                                                  // 绘制初始的不规则图形
                                                                  this.drawShape();
                                                                },
                                                                methods: {
                                                                  // 初始化 canvas 并绘制网格
                                                                  initCanvas() {
                                                                    const canvas = this.$refs.gridCanvas;
                                                                    // 设置 canvas 的宽度和高度
                                                                    canvas.width = this.canvasWidth;
                                                                    canvas.height = this.canvasHeight;
                                                                    // 获取 canvas 的 2D 上下文对象
                                                                    this.ctx = canvas.getContext("2d");
                                                                    // 绘制网格
                                                                    this.drawGrid();
                                                                  },
                                                                  // 绘制网格
                                                                  drawGrid() {
                                                                    const ctx = this.ctx;
                                                                    // 清空 canvas 内容
                                                                    ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
                                                                    // 设置网格线的颜色和宽度
                                                                    ctx.strokeStyle = "rgba(0, 255, 0, 0.5)";
                                                                    ctx.lineWidth = 1;
                                                                    // 绘制垂直网格线
                                                                    for (let x = 0; x  0) {
                                                                      // 移除最后一个点
                                                                      this.points.pop();
                                                                      // 重新绘制 canvas
                                                                      this.redraw();
                                                                    }
                                                                  },
                                                                  // 获取当前不规则图形各点的坐标
                                                                  getCoordinates() {
                                                                    console.log(
                                                                      "不规则框坐标:",
                                                                      this.points.map((p) => ({ x: p.x, y: p.y }))
                                                                    );
                                                                  },
                                                                  // 重置 canvas 内容
                                                                  reset() {
                                                                    // 清空点数组
                                                                    //   points.value = [];
                                                                    points.value = [
                                                                      { x: 240, y: 135 },
                                                                      { x: 240, y: 225 },
                                                                      { x: 400, y: 225 },
                                                                      { x: 400, y: 135 },
                                                                    ];
                                                                    // 重新绘制 canvas
                                                                    this.redraw();
                                                                  },
                                                                  // 限制坐标在指定范围内
                                                                  limitCoordinate(value, max) {
                                                                    return Math.min(Math.max(value, 0), max);
                                                                  },
                                                                  // 计算两点之间的距离
                                                                  calculateDistance(x1, y1, x2, y2) {
                                                                    const dx = x1 - x2;
                                                                    const dy = y1 - y2;
                                                                    return Math.sqrt(dx * dx + dy * dy);
                                                                  },
                                                                  // 绑定鼠标事件
                                                                  bindEvents() {
                                                                    const canvas = this.$refs.gridCanvas;
                                                                    canvas.addEventListener("mousedown", this.handleMouseDown);
                                                                    canvas.addEventListener("mousemove", this.handleMouseMove);
                                                                    canvas.addEventListener("mouseup", this.handleMouseUp);
                                                                    canvas.addEventListener("contextmenu", this.handleContextMenu);
                                                                  },
                                                                },
                                                              };
                                                              
                                                              
                                                              .canvas-container {
                                                                position: relative;
                                                                margin: 20px auto;
                                                                border: 1px solid #ccc;
                                                                overflow: hidden;
                                                              }
                                                              canvas {
                                                                display: block;
                                                                width: 100%;
                                                                height: 100%;
                                                                background-color: #f0f0f0;
                                                              }
                                                              .button-group {
                                                                position: absolute;
                                                                top: 10px;
                                                                left: 10px;
                                                                z-index: 10;
                                                              }
                                                              button {
                                                                padding: 6px 12px;
                                                                font-size: 14px;
                                                                cursor: pointer;
                                                                background-color: #fff;
                                                                border: 1px solid #ddd;
                                                                margin-right: 8px;
                                                              }
                                                              
                                                              

                                                              3、原生js实现,在HTML文件里面运行即可使用

                                                              
                                                              
                                                                  
                                                                  
                                                                  Camera Grid Frame with Draggable, Deletable, Coordinate Retrieval and Reset
                                                                  
                                                                      body {
                                                                          display: flex;
                                                                          justify-content: center;
                                                                          align-items: center;
                                                                          height: 100vh;
                                                                          margin: 0;
                                                                          background-color: #f0f0f0;
                                                                      }
                                                                      canvas {
                                                                          border: 1px solid #ccc;
                                                                      }
                                                                      button {
                                                                          position: absolute;
                                                                          padding: 8px 16px;
                                                                          font-size: 14px;
                                                                          cursor: pointer;
                                                                      }
                                                                      #undoButton {
                                                                          top: 20px;
                                                                          left: 20px;
                                                                      }
                                                                      #getCoordinatesButton {
                                                                          top: 20px;
                                                                          left: 120px;
                                                                      }
                                                                      #resetButton {
                                                                          top: 20px;
                                                                          left: 240px;
                                                                      }
                                                                  
                                                              
                                                              
                                                                  
                                                                  撤销
                                                                  获取坐标
                                                                  重置
                                                                  
                                                                      const canvas = document.getElementById('gridCanvas');
                                                                      canvas.width = 640;
                                                                      canvas.height = 360;
                                                                      const ctx = canvas.getContext('2d');
                                                                      const undoButton = document.getElementById('undoButton');
                                                                      const getCoordinatesButton = document.getElementById('getCoordinatesButton');
                                                                      const resetButton = document.getElementById('resetButton');
                                                                      const gridSize = 10;
                                                                      const framePadding = 0; // 边框内边距
                                                                      const frameWidth = canvas.width - 2 * framePadding;
                                                                      const frameHeight = canvas.height - 2 * framePadding;
                                                                      // 预设的 points 数据,可根据需要修改
                                                                      const initialPoints = [
                                                                          { x: 240, y: 135 },
                                                                          { x: 240, y: 225 },
                                                                          { x: 400, y: 225 },
                                                                          { x: 400, y: 135 },
                                                                      ];
                                                                      const points = initialPoints.slice(); // 复制预设数据到 points
                                                                      // 绘制方格
                                                                      function drawGrid() {
                                                                          for (let x = framePadding; x  1) {
                                                                          drawIrregularShape();
                                                                      }
                                                                      canvas.addEventListener('mousedown', (e) => {
                                                                          const x = e.offsetX;
                                                                          const y = e.offsetY;
                                                                          const clickRadius = 5;
                                                                          // 检查是否点击在节点上
                                                                          for (let i = 0; i  0) {
                                                                              redrawCanvas();
                                                                              drawIrregularShape([...points, { x, y }]);
                                                                          } else if (isDragging) {
                                                                              points[draggedPointIndex] = { x, y };
                                                                              redrawCanvas();
                                                                              drawIrregularShape();
                                                                          }
                                                                      });
                                                                      canvas.addEventListener('mouseup', () => {
                                                                          isDrawing = false;
                                                                          isDragging = false;
                                                                          draggedPointIndex = -1;
                                                                      });
                                                                      canvas.addEventListener('contextmenu', (e) => {
                                                                          e.preventDefault();
                                                                          const x = e.offsetX;
                                                                          const y = e.offsetY;
                                                                          const clickRadius = 5;
                                                                          for (let i = 0; i  0) {
                                                                              points.pop();
                                                                              redrawCanvas();
                                                                              drawIrregularShape();
                                                                          }
                                                                      });
                                                                      getCoordinatesButton.addEventListener('click', () => {
                                                                          const coordinates = points.map(point => ({ x: point.x, y: point.y }));
                                                                          console.log('不规则框各点位的坐标:', coordinates);
                                                                          alert('不规则框各点位的坐标:' + JSON.stringify(coordinates));
                                                                          // 你可以在这里将坐标信息用于其他用途,比如发送到服务器等
                                                                      });
                                                                      resetButton.addEventListener('click', () => {
                                                                          points.length = 0;
                                                                          redrawCanvas();
                                                                      });
                                                                      function redrawCanvas() {
                                                                          ctx.clearRect(0, 0, canvas.width, canvas.height);
                                                                          drawGrid();
                                                                      }
                                                                      function drawIrregularShape(pointsToDraw = points) {
                                                                          if (pointsToDraw.length > 1) {
                                                                              ctx.beginPath();
                                                                              ctx.moveTo(pointsToDraw[0].x, pointsToDraw[0].y);
                                                                              for (let i = 1; i  
                                                              
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码