Html,vue中使用canvas绘制多边形选择选择框,包含拖动,坐标显示
选择框,canvas,显示坐标,可拖动
·
这是我自己在工作中,开发的一个HTML小工具,是一个框选工具,使用canvas进行绘制,可以框选图片中的目标,也可以框选视频中的目标,虽然是vue组件,确实你也可以用在html项目中,因为是使用Typescript写的,可以自己去转换成JavaScript,我没有做更多的拓展。代码有部分代码也此功能无关可以去掉,看自己的需求来。
如果文章有错误,欢迎指正。
效果:
gif效果:
Quadrilateral.vue 多边形选择框文件代码
<template>
<div id="divCanvas">
<video id="videoCan" width="1000" height="600" autoplay>
<source src="../../assets/movie.mp4" type="video/mp4" />
</video>
<canvas id="graphCanvas"></canvas>
<canvas id="personCanvas"></canvas>
<canvas id="pointCanvas" :style="myStyle"></canvas>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import PointBean from "./PointBean";
export default defineComponent({
name: "Quadrilateral",
props: {
myStyle: Object,
},
setup(_, context) {
//画布宽高
const canvasWidth = ref(1000);
const canvasHeight = ref(600);
//点的范围
const pointRange = ref(10);
//拖动点的范围
const pointRangeDrag = ref(50);
// 线条颜色
const colorVal = ref("rgba(255,0,0,1)");
// 填充颜色
const colorValA = ref("rgba(255,0,0,.5)");
// 坐标文字颜色
const colorValPoint = ref("rgba(0,255,0,1)");
// 线条粗细,画笔大小
const lineWidthVal = ref(4);
//人的坐标数组
const personArr = ref([0.13,24,15,23]);
//用户可以直接在组件上设置的属性
if (context.attrs.width != undefined) {
canvasWidth.value = context.attrs.width as number;
}
if (context.attrs.height != undefined) {
canvasHeight.value = context.attrs.height as number;
}
if (context.attrs.pointRange != undefined) {
pointRange.value = context.attrs.pointRange as number;
}
if (context.attrs.lineColor != undefined) {
colorVal.value = context.attrs.lineColor as string;
}
if (context.attrs.fillColor != undefined) {
colorValA.value = context.attrs.fillColor as string;
}
if (context.attrs.lineWidth != undefined) {
lineWidthVal.value = context.attrs.lineWidth as number;
}
if (context.attrs.personArr != undefined) {
personArr.value = context.attrs.personArr as [];
}
let canGraph: HTMLCanvasElement;
let ctxGragh: CanvasRenderingContext2D;
let canPoint: HTMLCanvasElement;
let ctxPoint: CanvasRenderingContext2D;
let canPerson: HTMLCanvasElement;
let ctxPerson: CanvasRenderingContext2D;
const isMouseDown = ref(false);
const isMouseUp = ref(false);
const isMouseMove = ref(false);
const isDrag = ref(false);
//拖动的点
const dragPosition = ref(-1);
let pointArr = ref(new Array<PointBean>());
function clearView() {
ctxGragh.clearRect(0, 0, canGraph.width, canGraph.height);
ctxPoint.clearRect(0, 0, canPoint.width, canPoint.height);
pointArr.value = new Array<PointBean>();
}
function canOnClick(e: PointerEvent) {
// console.log("鼠标点击", e);
if (pointArr.value.length < 4) {
let piX: number, piY: number;
piX = e.offsetX == undefined ? e.clientX : e.offsetX;
piY = e.offsetY == undefined ? e.clientY : e.offsetY;
if (pointArr.value.length == 0) {
pointArr.value.push({ x: piX, y: piY });
} else {
//此点是否已经存在数组中
let isExist = false;
for (let i = 0; i < pointArr.value.length; i++) {
if (
piX >= pointArr.value[i].x - pointRange.value &&
piX <= pointArr.value[i].x + pointRange.value &&
piY >= pointArr.value[i].y - pointRange.value &&
piY <= pointArr.value[i].y + pointRange.value
) {
//判断为同一点,不存储
console.log("此点已存在");
isExist = true;
break;
}
}
if (!isExist) {
pointArr.value.push({ x: piX, y: piY });
}
}
drawArea();
}
}
function canOnmouseUp(e: MouseEvent) {
console.log("鼠标抬起", e);
if (isDrag.value) {
//这里来减少点
pointArrMerge();
drawArea();
isDrag.value = false;
dragPosition.value = -1;
}
}
function canOnmouseMove(e: MouseEvent) {
// console.log("鼠标移动", e);
ctxPoint.clearRect(0, 0, canPoint.width, canPoint.height);
let piX: number, piY: number;
piX = e.offsetX == undefined ? e.clientX : e.offsetX;
piY = e.offsetY == undefined ? e.clientY : e.offsetY;
piX = piX <= 0 ? 0 : piX;
piY = piY <= 0 ? 0 : piY;
piX = piX >= canPoint.width ? canPoint.width : piX;
piY = piY >= canPoint.height ? canPoint.height : piY;
drawMoveArea(piX, piY);
dot(piX, piY);
//显示点坐标
pointShow(piX, piY);
//判断是否是拖动
if (isMouseDown.value && isMouseMove.value && !isMouseUp.value) {
if (isDrag.value) {
drawDragArea(piX, piY);
} else {
dragPoint(piX, piY);
}
}
}
function canOnmouseDown(e: MouseEvent) {
console.log("鼠标按下", e);
}
//============================
//删除重复的点
function pointArrMerge() {
for (let i = 0; i < pointArr.value.length; i++) {
for (let j = i + 1; j < pointArr.value.length; j++) {
if (
pointArr.value[i].x >= pointArr.value[j].x - pointRange.value &&
pointArr.value[i].x <= pointArr.value[j].x + pointRange.value &&
pointArr.value[i].y >= pointArr.value[j].y - pointRange.value &&
pointArr.value[i].y <= pointArr.value[j].y + pointRange.value
) {
pointArr.value.splice(i, 1);
}
}
}
}
//鼠標下畫點
function dot(x: number, y: number) {
ctxPoint.clearRect(0, 0, canPoint.width, canPoint.height);
ctxPoint.beginPath();
ctxPoint.arc(x <= 0 ? 0 : x, y, lineWidthVal.value, 0, 2 * Math.PI);
ctxPoint.fillStyle = colorVal.value;
ctxPoint.fill();
}
//画区域
function drawArea() {
ctxGragh.clearRect(0, 0, canGraph.width, canGraph.height);
ctxGragh.beginPath();
ctxGragh.moveTo(pointArr.value[0].x, pointArr.value[0].y);
console.log(0, pointArr.value[0].x, pointArr.value[0].y);
for (let i = 1; i < pointArr.value.length; i++) {
ctxGragh.lineTo(pointArr.value[i].x, pointArr.value[i].y);
console.log(i, pointArr.value[i].x, pointArr.value[i].y);
}
ctxGragh.strokeStyle = colorVal.value;
ctxGragh.fillStyle = colorValA.value;
ctxGragh.lineWidth = lineWidthVal.value;
ctxGragh.closePath();
ctxGragh.stroke();
ctxGragh.fill();
}
//画移动的区域
function drawMoveArea(x: number, y: number) {
if (pointArr.value.length > 0 && pointArr.value.length < 4) {
ctxGragh.clearRect(0, 0, canGraph.width, canGraph.height);
ctxGragh.beginPath();
ctxGragh.moveTo(pointArr.value[0].x, pointArr.value[0].y);
for (let i = 1; i < pointArr.value.length; i++) {
ctxGragh.lineTo(pointArr.value[i].x, pointArr.value[i].y);
}
if (x <= 0) {
x = 0;
}
ctxGragh.lineTo(x, y);
ctxGragh.strokeStyle = colorVal.value;
ctxGragh.fillStyle = colorValA.value;
ctxGragh.lineWidth = lineWidthVal.value;
ctxGragh.closePath();
ctxGragh.stroke();
ctxGragh.fill();
}
}
//显示点的坐标
function pointShow(x: number, y: number) {
let i = -1;
let text;
if (pointArr.value.length > 0) {
for (i = 0; i < pointArr.value.length; i++) {
text =
i + "(" + pointArr.value[i].x + "," + pointArr.value[i].y + ")";
textCanShow(pointArr.value[i].x, pointArr.value[i].y, text);
}
if (i < 4) {
text = i + "(" + x + "," + y + ")";
textCanShow(x, y, text);
}
} else {
text = 0 + "(" + x + "," + y + ")";
textCanShow(x, y, text);
}
}
//显示文字
function textCanShow(x: number, y: number, text: string) {
//需要判断4个角,防止文字显示不到
//左上角
ctxPoint.beginPath();
if (x < 50) {
ctxPoint.textAlign = "left";
} else if (x > canPoint.width - 50) {
ctxPoint.textAlign = "right";
} else {
ctxPoint.textAlign = "center";
}
if (y > canPoint.height - 50) {
//点在下面,文字在上面
ctxPoint.textBaseline = "bottom";
} else {
ctxPoint.textBaseline = "top";
}
ctxPoint.font = "normal 18pt '黑体'";
ctxPoint.fillStyle = colorValPoint.value;
ctxPoint.fillText(text, x, y);
//右上角
//左下角
//右下角
}
function dragPoint(x: number, y: number) {
console.log("拖动");
for (let i = 0; i < pointArr.value.length; i++) {
if (
x >= pointArr.value[i].x - pointRangeDrag.value &&
x <= pointArr.value[i].x + pointRangeDrag.value &&
y >= pointArr.value[i].y - pointRangeDrag.value &&
y <= pointArr.value[i].y + pointRangeDrag.value
) {
dragPosition.value = i;
isDrag.value = true;
console.log("拖动", i);
}
}
}
function drawDragArea(x: number, y: number) {
if (dragPosition.value != -1) {
pointArr.value.splice(dragPosition.value, 1, { x, y });
drawArea();
}
}
//有带改进 一个来监听personArr.value 来画
function drawPersonArr(){
ctxPerson.clearRect(0,0,canPerson.width,canPerson.height);
console.log(canPerson.width,canPerson.height);
if(personArr.value.length>0){
ctxPerson.beginPath();
ctxPerson.rect(canPerson.width-120,20,110,(personArr.value.length+1)*21);
ctxPerson.font = "normal 18pt '黑体'";
ctxPerson.fillStyle = colorValPoint.value;
ctxPerson.fillText("个数:"+personArr.value.length,canPerson.width-110,40);
for(let i=0;i<personArr.value.length;i++){
// textCanShow(canPerson.width-125,40+i*10,i+":"+personArr.value[i]);
ctxPerson.fillText(i+":"+personArr.value[i],canPerson.width-110,(40+((i+1)*20)));
}
ctxPerson.closePath();
ctxPerson.stroke();
}
}
const setPersonArr = (arr:[])=>{
if(arr.length>0){
personArr.value = arr;
drawPersonArr();
}
}
onMounted(() => {
canGraph = document.getElementById("graphCanvas") as HTMLCanvasElement;
ctxGragh = canGraph.getContext("2d") as CanvasRenderingContext2D;
canPoint = document.getElementById("pointCanvas") as HTMLCanvasElement;
ctxPoint = canPoint.getContext("2d") as CanvasRenderingContext2D;
canPerson = document.getElementById("personCanvas") as HTMLCanvasElement;
ctxPerson = canPerson.getContext("2d") as CanvasRenderingContext2D;
canGraph.width = canvasWidth.value;
canGraph.height = canvasHeight.value;
canPoint.width = canvasWidth.value;
canPoint.height = canvasHeight.value;
canPerson.width = canvasWidth.value;
canPerson.height = canvasHeight.value;
ctxGragh.strokeStyle = colorVal.value; //线条颜色
ctxGragh.lineWidth = lineWidthVal.value; //线条粗细
ctxPoint.strokeStyle = colorVal.value; //线条颜色
ctxPoint.lineWidth = lineWidthVal.value; //线条粗细
ctxPerson.strokeStyle = colorVal.value; //线条颜色
ctxPerson.lineWidth = lineWidthVal.value; //线条粗细
canPoint.onmouseup = (e) => {
// console.log("鼠标抬起", e);
isMouseUp.value = true;
isMouseMove.value = false;
isMouseDown.value = false;
canOnmouseUp(e);
};
canPoint.onmousemove = (e) => {
isMouseMove.value = true;
// console.log("鼠标移动",e);
canOnmouseMove(e);
};
canPoint.onmousedown = (e) => {
// console.log("鼠标按下", e);
isMouseDown.value = true;
isMouseUp.value = false;
canOnmouseDown(e);
};
canPoint.onclick = (e) => {
// console.log("鼠标点击", e);
canOnClick(e as PointerEvent);
};
});
return {
clearView,
pointArr,
textCanShow,
setPersonArr,
};
},
});
</script>
<style scoped>
#divCanvas {
position: relative;
}
#graphCanvas ,#personCanvas{
position: absolute;
left: 0;
top: 0;
}
#pointCanvas {
position: absolute;
left: 0;
top: 0;
border: 1px solid red;
cursor: crosshair;
}
#videoCan {
position: absolute;
left: 0;
top: 0;
}
</style>
PointBean.ts 数据类代码
export default class PointBean{
x:number;
y:number;
constructor(x:number,y:number){
this.x = x;
this.y = y;
}
}
使用代码
<template>
<div>
<h1>def</h1>
<Quadrilateral
:myStyle="{ border: '1px solid red' }"
ref="RefChilde"
></Quadrilateral>
<button @click="ddd">asdsd</button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from "vue";
import Quadrilateral from "../utils/Quadrilateral.vue";
export default defineComponent({
name: "def",
components: { Quadrilateral },
setup() {
let RefChilde = ref();
// RefQuadrilateral.value.setPersonArr([1,2,3,4])
function ddd() {
RefChilde.value.setPersonArr([1, 2, 3, 4, 5, "asd"]);
}
onMounted(()=>{
RefChilde.value.setPersonArr([1,2,3,4]);
});
return {
RefChilde,
ddd,
};
},
});
</script>
<style>
</style>
更多推荐
已为社区贡献1条内容
所有评论(0)