feat: add versioned Sense areas and directional lines (#27)

This commit is contained in:
QiuSW
2026-08-12 17:29:09 +08:00
parent 8509699fff
commit e2e18b0380
17 changed files with 593 additions and 0 deletions
@@ -0,0 +1,21 @@
<template>
<div class="canvas-panel">
<div class="canvas-toolbar"><span>在画面上单击添加{{ kind === 'polygon' ? '多边形顶点' : '警戒线端点' }}</span><div><el-button size="small" :disabled="!points.length" @click="undo">撤销一点</el-button><el-button size="small" :disabled="!points.length" @click="clear">清空</el-button></div></div>
<svg ref="canvasRef" viewBox="0 0 1000 562.5" role="img" aria-label="区域绘制画布" @click="addPoint">
<defs><pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse"><path d="M 50 0 L 0 0 0 50" fill="none" stroke="#303844" stroke-width="1" /></pattern><marker id="arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 z" fill="#f7ba2a" /></marker></defs>
<rect width="1000" height="562.5" fill="#151b23" /><rect width="1000" height="562.5" fill="url(#grid)" /><text x="500" y="280" text-anchor="middle" fill="#6b7785" font-size="24">视频画面区域</text>
<polygon v-if="kind === 'polygon' && points.length" :points="svgPoints" fill="rgba(24,144,255,.24)" stroke="#1890ff" stroke-width="4" />
<line v-if="kind === 'line' && points.length === 2" :x1="points[0].x*1000" :y1="points[0].y*562.5" :x2="points[1].x*1000" :y2="points[1].y*562.5" stroke="#f7ba2a" stroke-width="5" marker-end="url(#arrow)" />
<circle v-for="(point,index) in points" :key="index" :cx="point.x*1000" :cy="point.y*562.5" r="8" fill="#fff" stroke="#1890ff" stroke-width="4" />
</svg>
<div class="canvas-hint">坐标按当前 Profile 分辨率归一化保存;切换分辨率后必须重新校准。</div>
</div>
</template>
<script setup>
import{computed,ref}from'vue'
const props=defineProps({modelValue:{type:Array,default:()=>[]},kind:{type:String,default:'polygon'}}),emit=defineEmits(['update:modelValue']),canvasRef=ref();const points=computed(()=>props.modelValue);const svgPoints=computed(()=>points.value.map(point=>`${point.x*1000},${point.y*562.5}`).join(' '))
function addPoint(event){if(props.kind==='line'&&points.value.length>=2)return;const rect=canvasRef.value.getBoundingClientRect(),x=Math.max(0,Math.min(1,(event.clientX-rect.left)/rect.width)),y=Math.max(0,Math.min(1,(event.clientY-rect.top)/rect.height));emit('update:modelValue',[...points.value,{x:Number(x.toFixed(6)),y:Number(y.toFixed(6))}])}
function undo(){emit('update:modelValue',points.value.slice(0,-1))}function clear(){emit('update:modelValue',[])}
</script>
<style scoped>.canvas-panel{border:1px solid #e5e6eb;border-radius:4px;overflow:hidden}.canvas-toolbar{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:#f7f8fa;color:#4e5969;font-size:13px}.canvas-panel svg{display:block;width:100%;cursor:crosshair}.canvas-hint{padding:9px 12px;background:#fff8e6;color:#86909c;font-size:12px}</style>