一、思路概述
- 页面准备:在页面中放置一张图片(
<img>
)或直接使用<canvas>
作为绘图层。 - 捕获点击坐标:监听鼠标点击事件,利用
event.clientX/Y
与图片/画布的getBoundingClientRect()
计算出相对于图片左上角的坐标。 - 绘制标注:在 Canvas 上绘制形状(圆点、矩形等)并使用
fillText
写入文字,或使用封装好的库(如 Fabric.js、Konva.js)创建可拖拽、可编辑的对象。 - 保存数据:把每个标注的坐标、尺寸、文本等信息保存到数组或发送到后端,以便后续查询或持久化。
二、实现方式示例
1️⃣ 纯 Canvas(原生 JS)
<div style="position:relative; display:inline-block;">
<img id="srcImg" src="your-image.jpg" style="max-width:100%;">
<canvas id="annoCanvas" style="position:absolute; left:0; top:0;"></canvas>
</div>
<script>
const img = document.getElementById('srcImg');
const canvas = document.getElementById('annoCanvas');
const ctx = canvas.getContext('2d');
const marks = []; // 保存标注信息
// 当图片加载完成后,设置 canvas 大小与图片一致
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
};
// 点击获取坐标并弹出输入框填写标注文字
canvas.addEventListener('click', e => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left; // 相对图片左上角的 X
const y = e.clientY - rect.top; // 相对图片左上角的 Y
const text = prompt('请输入标注文字:');
if (!text) return;
// 绘制圆点
ctx.beginPath();
ctx.arc(x, y, 5, 0, Math.PI * 2);
ctx.fillStyle = 'red';
ctx.fill();
// 绘制文字(稍微偏移避免遮挡)
ctx.font = '14px sans-serif';
ctx.fillStyle = 'blue';
ctx.fillText(text, x + 8, y - 8);
// 保存数据
marks.push({x, y, text});
});
</script>
关键点
getBoundingClientRect()
用于把页面坐标转换为图片内部坐标。canvas
采用绝对定位覆盖在图片上,实现“在图上标注”。
2️⃣ 使用 Fabric.js(更强的交互)
<link href="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
<canvas id="fabricCanvas" width="800" height="600"></canvas>
<script>
const canvas = new fabric.Canvas('fabricCanvas');
const marks = [];
// 加载背景图片
fabric.Image.fromURL('your-image.jpg', img => {
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height
});
});
// 点击添加标注
canvas.on('mouse:down', opt => {
const pointer = canvas.getPointer(opt.e);
const text = prompt('请输入标注文字:');
if (!text) return;
// 圆点
const circle = new fabric.Circle({
left: pointer.x,
top: pointer.y,
radius: 5,
fill: 'red',
originX: 'center',
originY: 'center',
selectable: false
});
// 文字
const txt = new fabric.Text(text, {
left: pointer.x + 8,
top: pointer.y - 8,
fontSize: 14,
fill: 'blue',
selectable: false
});
canvas.add(circle, txt);
canvas.renderAll();
marks.push({x: pointer.x, y: pointer.y, text});
});
</script>
关键点
- Fabric.js 把 Canvas 抽象为对象模型,
fabric.Circle
、fabric.Text
可直接创建并添加到画布。canvas.getPointer()
自动把鼠标事件转为画布坐标,省去手动计算。
3️⃣ 数据持久化(示例)
// 将标注信息转成 JSON,发送到后端
function uploadMarks() {
fetch('/api/saveMarks', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(marks)
}).then(r => r.json()).then(res => console.log('保存成功', res));
}
只要把
marks
数组(每条记录包含x、y、text
)发送即可,后端可自行存库或写文件。
三、常见需求的扩展
需求 | 推荐实现方式 | 关键代码/思路 |
---|---|---|
矩形/多边形标注 | Fabric.js 的 fabric.Rect 、fabric.Polygon |
new fabric.Rect({ left, top, width, height, stroke:'red', fill:'rgba(0,0,0,0)' }) |
标注可编辑(拖拽、缩放) | 将对象 selectable:true ,开启 canvas.selection = true |
canvas.setActiveObject(obj); |
放大/缩小图片 | 调整 canvas.setZoom(scale) 或修改背景图 scaleX/scaleY |
canvas.setZoom(1.5); |
导出标注结果 | canvas.toJSON() 或自行遍历 marks 数组 |
const json = canvas.toJSON(); |
移动端触摸支持 | Fabric.js 已内置 touch 事件,或在原生 Canvas 中监听 touchstart |
canvas.addEventListener('touchstart', …) |
四、完整示例(可直接拷贝运行)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>JS 图像标注示例</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
<style>
#wrapper{position:relative;display:inline-block;}
canvas{border:1px solid #ccc;}
</style>
</head>
<body>
<div id="wrapper">
<canvas id="cvs" width="800" height="600"></canvas>
</div>
<script>
const canvas = new fabric.Canvas('cvs');
const marks = [];
// 背景图
fabric.Image.fromURL('https://picsum.photos/800/600', img=>{
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height
});
});
// 添加标注
canvas.on('mouse:down', e=>{
const p = canvas.getPointer(e.e);
const txt = prompt('标注文字:');
if(!txt) return;
const dot = new fabric.Circle({
left:p.x, top:p.y, radius:5, fill:'red',
originX:'center', originY:'center', selectable:false
});
const label = new fabric.Text(txt,{
left:p.x+8, top:p.y-8, fontSize:14,
fill:'blue', selectable:false
});
canvas.add(dot, label);
marks.push({x:p.x, y:p.y, text:txt});
});
// 保存按钮(可自行添加 UI)
function save(){
console.log('标注数据', marks);
// 示例:发送到后端
// fetch('/save', {method:'POST',body:JSON.stringify(marks)});
}
</script>
</body>
</html>
运行后,点击图片即可弹出输入框,输入文字后会在点击位置出现红点和蓝色文字,所有标注信息保存在
marks
数组中。
五、总结
- 获取坐标:
event.clientX/Y
+element.getBoundingClientRect()
(原生)或canvas.getPointer()
(Fabric.js)。 - 绘制标注:Canvas API(
arc
、fillText
)或库提供的对象(fabric.Circle
、fabric.Text
)。 - 保存/导出:把坐标 + 文本保存为 JSON,或使用库的
toJSON()
方法。 - 推荐库:Fabric.js(功能完整、易上手)或 Konva.js(React/Vue 生态友好),均可实现拖拽、缩放、编辑等高级交互。
通过上述步骤,你即可在网页中实现图像标注、实时获取坐标并记录对应的文本信息。祝开发顺利!
声明:文章均为AI生成,请谨慎辨别信息的真伪和可靠性!