效果如下
下面直接看代码吧,可以直接复制运行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
html,
body {
height: 100vh;
width: 100vw;
background-color: #ececec;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
/* 图像容器 */
.image_box {
position: relative;
height: 600px;
width: 600px;
}
img,
.canvas_dom {
height: 100%;
width: 100%;
position: absolute;
}
.canvas_dom {
background-color: rgba(0, 0, 0, .2);
cursor: crosshair;
}
</style>
</head>
<body>
<div class="image_box">
<!-- canvas 必须指定宽高,不然绘制出来的矩形会模糊和错误。 -->
<canvas class="canvas_dom" id="canvasDom" width="600" height="600">
no canvas! Your Browser is not support canvas. Please change your browser.
</canvas>
</div>
</body>
</html>
<script>
// canvas对象
let canvasDom = document.getElementById('canvasDom')
let ctx2d = canvasDom.getContext("2d");
// 保存矩形数据
let recArrs = []
// 记录当前的信息
let curObj = {
isRightClick: false, // 鼠标右键按下标识
radious: 4, // 范围误差值
recSize: 5, // 移动小框的大小
index: -1, // 当前矩形框的index
side: 0, // 边界值
resize: false, // 是否拖拽大小
draw: false, // 是否画图
drag: false, // 是否拖动
x: 0, // 画图的起始x
y: 0, // 画图的起始y
startX: 0, // x轴开始位置
startY: 0, // y轴开始位置
}
// 获取canvas的宽高
const canvasHeight = canvasDom.offsetHeight
const canvasWidth = canvasDom.offsetWidth
console.log('高度--', canvasHeight);
console.log('宽度--', canvasWidth);
// 注册事件
canvasDom.addEventListener('mousemove', moveFunction)
canvasDom.addEventListener('mousedown', downFunction)
canvasDom.addEventListener('mouseup', upFunction)
canvasDom.addEventListener('mouseout', outFunction)
canvasDom.addEventListener('contextmenu', contextMenuFunction)
// 禁止鼠标右键
function contextMenuFunction(e) {
e.preventDefault();
return false
}
// 鼠标移出画布
function outFunction(e) {
let x = e.clientX;
let y = e.clientY;
let left = canvasDom.offsetLeft
let top = canvasDom.offsetTop
let width = canvasDom.offsetWidth
let height = canvasDom.offsetHeight
let limitX = left + width
let limitY = top + height
if(x < left || x > limitX || y < top || y > limitY ) {
console.log('鼠标移出范围, 清除canvas,重新绘制');
clearCanvas()
drawOldRect()
}
}
// 鼠标移动事件
function moveFunction(e) {
// console.log('鼠标移动', e);
// 需要清除之前的辅助线
clearCanvas()
// 画辅助线
drawRuler(e)
// 清空辅助线和矩形数据后,这里重绘
drawOldRect()
// 画矩形
drawRect(e)
// 移动或缩放
moveOrScale(e)
}
// 移动矩形框/缩放矩形框
function moveOrScale(e) {
let index = getEventIndex(e.offsetX, e.offsetY)
let side = 0
if(index > -1) {
side = getEventArea(index, e.offsetX, e.offsetY)
// 画移动小框
if(side > 0) {
drawLitRecs(index)
}
}
// 鼠标样式
changeResizeCursor(side);
// 如果在移动
moveRec(e)
// 如果在缩放
reSizeRec(e)
}
// 移动
function moveRec(e) {
if(curObj.drag && recArrs[curObj.index]) {
let x = curObj.startX + e.offsetX - curObj.x
let y = curObj.startY + e.offsetY - curObj.y
let minX = canvasDom.offsetLeft
let maxX = canvasDom.offsetLeft + canvasDom.offsetWidth - recArrs[curObj.index].w
let minY = canvasDom.offsetTop
let maxY = canvasDom.offsetTop + canvasDom.offsetHeight - recArrs[curObj.index].h
if(x < minX) {
x = minX
}
if( x > maxX) {
x = maxX
}
if(y < minY) {
y = minY
}
if( y > maxY) {
y = maxY
}
recArrs[curObj.index].x = x
recArrs[curObj.index].y = y
}
}
// 缩放
function reSizeRec(e) {
const { side, index, recSize } = curObj
const rec = recArrs[index]
if(curObj.resize && rec) {
const temX = rec.x;
const temY = rec.y;
const ex = e.offsetX
const ey = e.offsetY
if (side < 4 && temX + rec.w - ex > recSize) {
rec.x = ex;
}
if (
(side == 1 || side == 4 || side == 7) &&
temY + rec.h - ey > recSize
) {
rec.y = ey;
}
if (side < 4) {
if (temX + rec.w - ex > recSize) {
rec.w = temX + rec.w - ex;
}
} else if (side < 7) {
if (ex - temX > recSize) {
rec.w = ex - temX;
}
}
if (side == 1 || side == 4 || side == 7) {
if (temY + rec.h - ey > recSize) {
rec.h = temY + rec.h - ey;
}
} else if (side == 3 || side == 6 || side == 8) {
if (ey - temY > recSize) {
rec.h = ey - temY;
}
}
}
}
// 鼠标移动,画辅助线
function drawRuler(e) {
// 开始一条路径
ctx2d.beginPath();
// 填充色
ctx2d.strokeStyle = "red";
// 路径宽度
ctx2d.lineWidth = 1;
// 移动到 鼠标的 x位置, y位置 0(竖线的起点)
ctx2d.moveTo(e.offsetX, 0);
// lineTo() 方法添加一个新点,(竖线的终点)
ctx2d.lineTo(e.offsetX, canvasHeight);
// 移动到(x: 0, y:鼠标的位置)(横线的起点)
ctx2d.moveTo(0, e.offsetY);
// lineTo() 方法添加一个新点,(横线的终点)
ctx2d.lineTo(canvasWidth, e.offsetY);
ctx2d.stroke();
}
// 清除canvas
function clearCanvas() {
ctx2d.clearRect(0, 0, canvasWidth, canvasHeight);
}
// 鼠标按下并移动,画矩形
function drawRect(e) {
if (curObj.draw) {
ctx2d.strokeRect(
curObj.x,
curObj.y,
e.offsetX - curObj.x,
e.offsetY - curObj.y
);
}
}
// 画初始数据
function drawOldRect() {
if (!recArrs.length) return
for (var i = 0; i < recArrs.length; i++) {
// >2的判断是为了防止误触画出来的数据
if(recArrs[i].w > 2 && recArrs[i].h > 2) {
ctx2d.beginPath();
ctx2d.lineWidth = 2; // 矩形框的线条宽度
ctx2d.strokeStyle = "rgb(255, 0, 0)"; // 矩形框的线条颜色
ctx2d.strokeRect(recArrs[i].x, recArrs[i].y, recArrs[i].w, recArrs[i].h); // 矩形框
// 如果有文本信息,填充文本信息
if (recArrs[i].text) {
ctx2d.fillStyle = "purple";
ctx2d.font = "14px 微软雅黑";
ctx2d.lineWidth = 1;
ctx2d.strokeStyle = "rgb(255,0,0)";
ctx2d.strokeText(
recArrs[i].text,
(recArrs[i].x + recArrs[i].w / 2) - (recArrs[i].text.length / 2) * 16,
recArrs[i].y - 20 < 0 ? recArrs[i].y + recArrs[i].h + 20 : recArrs[i].y - 10
);
}
}
}
}
// 鼠标按下事件
function downFunction(e) {
console.log('鼠标按下', e); // e.button 0 鼠标左键 1 鼠标滚轮 2 鼠标右键
curObj.isRightClick = e.button > 1
console.log('是否右键', curObj.isRightClick);
// 赋值 x,y 轴起始数据
curObj.x = e.offsetX
curObj.y = e.offsetY
// 判断是否落在的矩形框上
//得到落点所在框的序数
curObj.index = getEventIndex(curObj.x, curObj.y)
console.log('落点矩形', curObj.index);
// 如果是鼠标右键 TODO...
if (curObj.isRightClick) {
} else {
// 鼠标左键
// 如果鼠标落点不在矩形内,画矩形
if(curObj.index === -1) {
curObj.draw = true
}else {
// 落点在矩形内
//移动或者放缩
curObj.startX = recArrs[curObj.index].x;
curObj.startY = recArrs[curObj.index].y;
//得到落点在一个框中的区域
curObj.side = getEventArea(curObj.index, curObj.x, curObj.y);
console.log("curObj.side", curObj.side);
if (curObj.side < 9) {
//准备缩放
console.log("在缩放");
curObj.resize = true;
} else {
//准备拖动
console.log("在拖动");
curObj.drag = true;
}
// 画移动小框
drawLitRecs(curObj.index);
}
}
//判断小框类型
changeResizeCursor(curObj.side);
}
// 修改鼠标样式
function changeResizeCursor(side) {
switch (side) {
case 0:
canvasDom.style.cursor = "crosshair";
break;
case 1:
canvasDom.style.cursor = "se-resize";
break;
case 2:
canvasDom.style.cursor = "e-resize";
break;
case 3:
canvasDom.style.cursor = "ne-resize";
break;
case 4:
canvasDom.style.cursor = "sw-resize";
break;
case 5:
canvasDom.style.cursor = "w-resize";
break;
case 6:
canvasDom.style.cursor = "nw-resize";
break;
case 7:
canvasDom.style.cursor = "s-resize";
break;
case 8:
canvasDom.style.cursor = "n-resize";
break;
case 9:
canvasDom.style.cursor = "move";
break;
default:
canvasDom.style.cursor = "default";
}
}
//得到落点在一个框中的区域
function getEventArea(index, x, y) {
const { radious } = curObj
const data = recArrs[index]
console.log('recArrs', recArrs)
console.log('data', data)
if (x > data.x - radious && x < data.x + radious) {
if (y > data.y - radious && y < data.y + radious) {
return 1;
} else if (y > data.y + radious && y < data.y + data.h - radious) {
return 2;
} else if (
y > data.y + data.h - radious &&
y < data.y + data.h + radious
) {
return 3;
}
} else if (
x > data.x + data.w - radious &&
x < data.x + data.w + radious
) {
if (y > data.y - radious && y < data.y + radious) {
return 4;
} else if (y > data.y + radious && y < data.y + data.h - radious) {
return 5;
} else if (
y > data.y + data.h - radious &&
y < data.y + data.h + radious
) {
return 6;
}
} else {
if (
y > data.y - radious &&
y < data.y + radious &&
x > data.x + radious &&
x < data.x + data.w - radious
) {
return 7;
} else if (
y > data.y + data.h - radious &&
y < data.y + data.h + radious &&
x > data.x + radious &&
x < data.x + data.w - radious
) {
return 8;
} else {
return 9;
}
}
}
//把一个框的左上角坐标和宽高输入,得到8个坐标,左3,右3中2
function prepareLitRecs(index) {
const data = recArrs[index]
var li = [];
li[0] = [data.x, data.y];
li[1] = [data.x, data.y + data.h / 2];
li[2] = [data.x, data.y + data.h];
li[3] = [data.x + data.w, data.y];
li[4] = [data.x + data.w, data.y + data.h / 2];
li[5] = [data.x + data.w, data.y + data.h];
li[6] = [data.x + data.w / 2, data.y];
li[7] = [data.x + data.w / 2, data.y + data.h];
return li;
}
//画移动时的小框,data为矩形框9个点的坐标
function drawLitRecs(index) {
const data = prepareLitRecs(index)
const { recSize } = curObj
for (var i = 0; i < data.length; i++) {
ctx2d.strokeRect(
data[i][0] - recSize / 2,
data[i][1] - recSize / 2,
recSize,
recSize,
);
}
}
// 获取鼠标落点所在矩形的index, -1 表示没有落在任何框内
function getEventIndex(x, y) {
if (!recArrs.length) return -1
for (var i = 0; i < recArrs.length; i++) {
const limitX = x > recArrs[i].x - curObj.radious
const limitW = x < recArrs[i].x + recArrs[i].w + curObj.radious
const limitY = y > recArrs[i].y - curObj.radious
const limitH = y < recArrs[i].y + recArrs[i].h + curObj.radious
// 有在范围内的,返回index
if (limitX && limitY && limitW && limitH) {
return i;
}
// 没有返回 -1
if (i == recArrs.length - 1) {
return -1;
}
}
}
// 鼠标抬起事件
function upFunction(e) {
console.log('鼠标抬起', e);
if(curObj.isRightClick) {
if(curObj.index !== -1) {
// 删除,重绘
recArrs.splice(curObj.index, 1)
clearCanvas()
drawOldRect()
}
curObj.isRightClick = false;
return
}
curObj.resize = false
curObj.drag = false
// 如果是画图
if (curObj.draw) {
addToRecs(e)
curObj.draw = false;
}
console.log('鼠标抬起-当前矩形框', recArrs);
}
// 添加矩形
function addToRecs(e) {
let rec = {
x: curObj.x > e.offsetX ? e.offsetX : curObj.x, // x点
y: curObj.y > e.offsetY ? e.offsetY : curObj.y, // y点
w: Math.abs(e.offsetX - curObj.x), // 宽
h: Math.abs(e.offsetY - curObj.y), // 高
text: '矩形框' + recArrs.length, // 默认填充文本
type: 1, // 类型
// 其他需要的数据自行添加...
};
// 防止误触
if(rec.w > 2 && rec.h > 2) {
recArrs.push(rec)
console.log('recArrs', recArrs);
}
}
</script>
在上面的基础上增加截图功能。效果如下:
代码,可直接更换图片运行查看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
html,
body {
height: 100vh;
width: 100vw;
background-color: #ececec;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
/* 图像容器 */
.image_box {
position: relative;
height: 800px;
width: 800px;
}
img,
.canvas_dom {
height: 100%;
width: 100%;
position: absolute;
}
.canvas_dom {
background-color: rgba(0, 0, 0, .2);
cursor: crosshair;
}
.cut-box {
height: 800px;
width: 800px;
overflow: auto;
background-color: bisque;
margin-left: 20px;
}
.cut-img {
height: 200px;
width: 200px;
position: relative;
display: inline-block;
}
</style>
</head>
<body>
<div class="image_box">
<!-- TODO 自行更换图片 -->
<!-- <img src="./test.png" alt="" id="imgDom"> -->
<!-- canvas 必须指定宽高,不然绘制出来的矩形会模糊和错误。 -->
<canvas class="canvas_dom" id="canvasDom" width="800" height="800">
no canvas! Your Browser is not support canvas. Please change your browser.
</canvas>
</div>
<div class="cut-box">
</div>
</body>
</html>
<script>
// 放置截图的容器
let cutDom = document.querySelector('.cut-box')
// 图像
let imgDom = document.getElementById('imgDom')
// canvas对象
let canvasDom = document.getElementById('canvasDom')
let ctx2d = canvasDom.getContext("2d");
// 保存矩形数据
let recArrs = []
// 记录当前的信息
let curObj = {
isRightClick: false, // 鼠标右键按下标识
radious: 4, // 范围误差值
recSize: 5, // 移动小框的大小
index: -1, // 当前矩形框的index
side: 0, // 边界值
resize: false, // 是否拖拽大小
draw: false, // 是否画图
drag: false, // 是否拖动
x: 0, // 画图的起始x
y: 0, // 画图的起始y
startX: 0, // x轴开始位置
startY: 0, // y轴开始位置
}
// 获取canvas的宽高
const canvasHeight = canvasDom.offsetHeight
const canvasWidth = canvasDom.offsetWidth
console.log('高度--', canvasHeight);
console.log('宽度--', canvasWidth);
// 注册事件
canvasDom.addEventListener('mousemove', moveFunction)
canvasDom.addEventListener('mousedown', downFunction)
canvasDom.addEventListener('mouseup', upFunction)
canvasDom.addEventListener('mouseout', outFunction)
canvasDom.addEventListener('contextmenu', contextMenuFunction)
// 禁止鼠标右键
function contextMenuFunction(e) {
e.preventDefault();
return false
}
// 鼠标移出画布
function outFunction(e) {
let x = e.clientX;
let y = e.clientY;
let left = canvasDom.offsetLeft
let top = canvasDom.offsetTop
let width = canvasDom.offsetWidth
let height = canvasDom.offsetHeight
let limitX = left + width
let limitY = top + height
if(x < left || x > limitX || y < top || y > limitY ) {
console.log('鼠标移出范围, 清除canvas,重新绘制');
clearCanvas()
drawOldRect()
}
}
// 鼠标移动事件
function moveFunction(e) {
// console.log('鼠标移动', e);
// 需要清除之前的辅助线
clearCanvas()
// 画辅助线
drawRuler(e)
// 清空辅助线和矩形数据后,这里重绘
drawOldRect()
// 画矩形
drawRect(e)
// 移动或缩放
moveOrScale(e)
}
// 移动矩形框/缩放矩形框
function moveOrScale(e) {
let index = getEventIndex(e.offsetX, e.offsetY)
let side = 0
if(index > -1) {
side = getEventArea(index, e.offsetX, e.offsetY)
// 画移动小框
if(side > 0) {
drawLitRecs(index)
}
}
// 鼠标样式
changeResizeCursor(side);
// 如果在移动
moveRec(e)
// 如果在缩放
reSizeRec(e)
}
// 移动
function moveRec(e) {
let rec = recArrs[curObj.index]
if(curObj.drag && rec) {
let x = curObj.startX + e.offsetX - curObj.x
let y = curObj.startY + e.offsetY - curObj.y
let minX = canvasDom.offsetLeft
let maxX = canvasDom.offsetLeft + canvasDom.offsetWidth - rec.w
let minY = canvasDom.offsetTop
let maxY = canvasDom.offsetTop + canvasDom.offsetHeight - rec.h
if(x < minX) {
x = minX
}
if( x > maxX) {
x = maxX
}
if(y < minY) {
y = minY
}
if( y > maxY) {
y = maxY
}
rec.x = x
rec.y = y
// 截图
let { scleX, scleY } = getImgScale()
let scx = rec.x / scleX
let scy = rec.y / scleY
let h = rec.h / scleY
let w = rec.w / scleX
rec.cutImgUrl = exportBase64(scx, scy, w, h, w, h)
console.log('recArrs', recArrs);
// 显示
freshImg()
}
}
// 缩放
function reSizeRec(e) {
const { side, index, recSize } = curObj
const rec = recArrs[index]
if(curObj.resize && rec) {
const temX = rec.x;
const temY = rec.y;
const ex = e.offsetX
const ey = e.offsetY
if (side < 4 && temX + rec.w - ex > recSize) {
rec.x = ex;
}
if (
(side == 1 || side == 4 || side == 7) &&
temY + rec.h - ey > recSize
) {
rec.y = ey;
}
if (side < 4) {
if (temX + rec.w - ex > recSize) {
rec.w = temX + rec.w - ex;
}
} else if (side < 7) {
if (ex - temX > recSize) {
rec.w = ex - temX;
}
}
if (side == 1 || side == 4 || side == 7) {
if (temY + rec.h - ey > recSize) {
rec.h = temY + rec.h - ey;
}
} else if (side == 3 || side == 6 || side == 8) {
if (ey - temY > recSize) {
rec.h = ey - temY;
}
}
// 截图
let { scleX, scleY } = getImgScale()
let x = rec.x / scleX
let y = rec.y / scleY
let h = rec.h / scleY
let w = rec.w / scleX
rec.cutImgUrl = exportBase64(x, y, w, h, w, h)
console.log('recArrs', recArrs);
// 显示
freshImg()
}
}
// 鼠标移动,画辅助线
function drawRuler(e) {
// 开始一条路径
ctx2d.beginPath();
// 填充色
ctx2d.strokeStyle = "red";
// 路径宽度
ctx2d.lineWidth = 1;
// 移动到 鼠标的 x位置, y位置 0(竖线的起点)
ctx2d.moveTo(e.offsetX, 0);
// lineTo() 方法添加一个新点,(竖线的终点)
ctx2d.lineTo(e.offsetX, canvasHeight);
// 移动到(x: 0, y:鼠标的位置)(横线的起点)
ctx2d.moveTo(0, e.offsetY);
// lineTo() 方法添加一个新点,(横线的终点)
ctx2d.lineTo(canvasWidth, e.offsetY);
ctx2d.stroke();
}
// 清除canvas
function clearCanvas() {
ctx2d.clearRect(0, 0, canvasWidth, canvasHeight);
}
// 鼠标按下并移动,画矩形
function drawRect(e) {
if (curObj.draw) {
ctx2d.strokeRect(
curObj.x,
curObj.y,
e.offsetX - curObj.x,
e.offsetY - curObj.y
);
}
}
// 画初始数据
function drawOldRect() {
if (!recArrs.length) return
for (var i = 0; i < recArrs.length; i++) {
// >2的判断是为了防止误触画出来的数据
if(recArrs[i].w > 2 && recArrs[i].h > 2) {
ctx2d.beginPath();
ctx2d.lineWidth = 2; // 矩形框的线条宽度
ctx2d.strokeStyle = "rgb(255, 0, 0)"; // 矩形框的线条颜色
ctx2d.strokeRect(recArrs[i].x, recArrs[i].y, recArrs[i].w, recArrs[i].h); // 矩形框
// 如果有文本信息,填充文本信息
if (recArrs[i].text) {
ctx2d.fillStyle = "purple";
ctx2d.font = "14px 微软雅黑";
ctx2d.lineWidth = 1;
ctx2d.strokeStyle = "rgb(255,0,0)";
ctx2d.strokeText(
recArrs[i].text,
(recArrs[i].x + recArrs[i].w / 2) - (recArrs[i].text.length / 2) * 16,
recArrs[i].y - 20 < 0 ? recArrs[i].y + recArrs[i].h + 20 : recArrs[i].y - 10
);
}
}
}
}
// 鼠标按下事件
function downFunction(e) {
console.log('鼠标按下', e); // e.button 0 鼠标左键 1 鼠标滚轮 2 鼠标右键
curObj.isRightClick = e.button > 1
console.log('是否右键', curObj.isRightClick);
// 赋值 x,y 轴起始数据
curObj.x = e.offsetX
curObj.y = e.offsetY
// 判断是否落在的矩形框上
//得到落点所在框的序数
curObj.index = getEventIndex(curObj.x, curObj.y)
console.log('落点矩形', curObj.index);
// 如果是鼠标右键 TODO...
if (curObj.isRightClick) {
} else {
// 鼠标左键
// 如果鼠标落点不在矩形内,画矩形
if(curObj.index === -1) {
curObj.draw = true
}else {
// 落点在矩形内
//移动或者放缩
curObj.startX = recArrs[curObj.index].x;
curObj.startY = recArrs[curObj.index].y;
//得到落点在一个框中的区域
curObj.side = getEventArea(curObj.index, curObj.x, curObj.y);
console.log("curObj.side", curObj.side);
if (curObj.side < 9) {
//准备缩放
console.log("在缩放");
curObj.resize = true;
} else {
//准备拖动
console.log("在拖动");
curObj.drag = true;
}
// 画移动小框
drawLitRecs(curObj.index);
}
}
//判断小框类型
changeResizeCursor(curObj.side);
}
// 修改鼠标样式
function changeResizeCursor(side) {
switch (side) {
case 0:
canvasDom.style.cursor = "crosshair";
break;
case 1:
canvasDom.style.cursor = "se-resize";
break;
case 2:
canvasDom.style.cursor = "e-resize";
break;
case 3:
canvasDom.style.cursor = "ne-resize";
break;
case 4:
canvasDom.style.cursor = "sw-resize";
break;
case 5:
canvasDom.style.cursor = "w-resize";
break;
case 6:
canvasDom.style.cursor = "nw-resize";
break;
case 7:
canvasDom.style.cursor = "s-resize";
break;
case 8:
canvasDom.style.cursor = "n-resize";
break;
case 9:
canvasDom.style.cursor = "move";
break;
default:
canvasDom.style.cursor = "default";
}
}
//得到落点在一个框中的区域
function getEventArea(index, x, y) {
const { radious } = curObj
const data = recArrs[index]
console.log('recArrs', recArrs)
console.log('data', data)
if (x > data.x - radious && x < data.x + radious) {
if (y > data.y - radious && y < data.y + radious) {
return 1;
} else if (y > data.y + radious && y < data.y + data.h - radious) {
return 2;
} else if (
y > data.y + data.h - radious &&
y < data.y + data.h + radious
) {
return 3;
}
} else if (
x > data.x + data.w - radious &&
x < data.x + data.w + radious
) {
if (y > data.y - radious && y < data.y + radious) {
return 4;
} else if (y > data.y + radious && y < data.y + data.h - radious) {
return 5;
} else if (
y > data.y + data.h - radious &&
y < data.y + data.h + radious
) {
return 6;
}
} else {
if (
y > data.y - radious &&
y < data.y + radious &&
x > data.x + radious &&
x < data.x + data.w - radious
) {
return 7;
} else if (
y > data.y + data.h - radious &&
y < data.y + data.h + radious &&
x > data.x + radious &&
x < data.x + data.w - radious
) {
return 8;
} else {
return 9;
}
}
}
//把一个框的左上角坐标和宽高输入,得到8个坐标,左3,右3中2
function prepareLitRecs(index) {
const data = recArrs[index]
var li = [];
li[0] = [data.x, data.y];
li[1] = [data.x, data.y + data.h / 2];
li[2] = [data.x, data.y + data.h];
li[3] = [data.x + data.w, data.y];
li[4] = [data.x + data.w, data.y + data.h / 2];
li[5] = [data.x + data.w, data.y + data.h];
li[6] = [data.x + data.w / 2, data.y];
li[7] = [data.x + data.w / 2, data.y + data.h];
return li;
}
//画移动时的小框,data为矩形框9个点的坐标
function drawLitRecs(index) {
const data = prepareLitRecs(index)
const { recSize } = curObj
for (var i = 0; i < data.length; i++) {
ctx2d.strokeRect(
data[i][0] - recSize / 2,
data[i][1] - recSize / 2,
recSize,
recSize,
);
}
}
// 获取鼠标落点所在矩形的index, -1 表示没有落在任何框内
function getEventIndex(x, y) {
if (!recArrs.length) return -1
for (var i = 0; i < recArrs.length; i++) {
const limitX = x > recArrs[i].x - curObj.radious
const limitW = x < recArrs[i].x + recArrs[i].w + curObj.radious
const limitY = y > recArrs[i].y - curObj.radious
const limitH = y < recArrs[i].y + recArrs[i].h + curObj.radious
// 有在范围内的,返回index
if (limitX && limitY && limitW && limitH) {
return i;
}
// 没有返回 -1
if (i == recArrs.length - 1) {
return -1;
}
}
}
// 鼠标抬起事件
function upFunction(e) {
console.log('鼠标抬起', e);
if(curObj.isRightClick) {
if(curObj.index !== -1) {
// 删除,重绘
recArrs.splice(curObj.index, 1)
clearCanvas()
drawOldRect()
// 显示
freshImg()
}
curObj.isRightClick = false;
return
}
curObj.resize = false
curObj.drag = false
// 如果是画图
if (curObj.draw) {
addToRecs(e)
curObj.draw = false;
}
console.log('鼠标抬起-当前矩形框', recArrs);
}
// 添加矩形
function addToRecs(e) {
let rec = {
x: curObj.x > e.offsetX ? e.offsetX : curObj.x, // x点
y: curObj.y > e.offsetY ? e.offsetY : curObj.y, // y点
w: Math.abs(e.offsetX - curObj.x), // 宽
h: Math.abs(e.offsetY - curObj.y), // 高
text: '矩形框' + recArrs.length, // 默认填充文本
type: 1, // 类型
// 其他需要的数据自行添加...
};
// 防止误触
if(rec.w > 2 && rec.h > 2) {
// 添加截图
let { scleX, scleY } = getImgScale()
let x = rec.x / scleX
let y = rec.y / scleY
let h = rec.h / scleY
let w = rec.w / scleX
rec.cutImgUrl = exportBase64(x, y, w, h, w, h)
recArrs.push(rec)
console.log('recArrs', recArrs);
// 显示
freshImg()
}
}
// 获取当前图片的缩放比例
function getImgScale() {
// 图片原始大小
let imgDefWidth = imgDom.naturalWidth
let imgDefHeight = imgDom.naturalHeight
// 图片的实际渲染尺寸
let imgRenderWidth = imgDom.offsetWidth
let imgRenderHeight = imgDom.offsetHeight
// 图片x轴和y轴的缩放比例
let scleX = imgRenderWidth / imgDefWidth
let scleY = imgRenderHeight / imgDefHeight
console.log('X轴缩放比例', scleX);
console.log('Y轴缩放比例', scleY);
return { scleX, scleY }
}
// 将所框的数据转为图片地址
/**
*
* @param {剪切的x轴开始坐标,相对于原图} x
* @param {剪切的y轴开始坐标,相对于原图} y
* @param {剪切的宽,相对于原图} sWidth
* @param {剪切的高,相对于原图} sHeight
* @param {输出的宽,默认按照剪切框大小输出} rW
* @param {输出的高,默认按照剪切框大小输出} rH
*/
function exportBase64(x, y, sWidth, sHeight, rW = 200, rH = 200) {
// 创建一个新的canvas
let canvasElement = document.createElement("canvas");
canvasElement.width = `${rW}`
canvasElement.height = `${rH}`
let canvasContext = canvasElement.getContext("2d");
canvasContext.drawImage(imgDom, x, y, sWidth, sHeight, 0, 0, rW, rH);
let cutPicUrl = canvasElement.toDataURL("image/jpeg");
return cutPicUrl
}
function freshImg() {
// 先清除
cutDom.innerHTML = ''
recArrs.forEach( rec => {
let item = document.createElement('img')
item.src = rec.cutImgUrl
item.className = 'cut-img'
cutDom.appendChild(item)
})
}
</script>