简介
canvas是HTML5新增的,用javaScript进行图形的绘制
beginPath()创建路径,
closePath()闭合路径,
arc(x, y, r, startAngle, endAngle, anticlockwise)绘制圆弧,
stroke()绘制,
移动画笔
moveTo(x,y)起始坐标,
lineTo(x,y)中途坐标
首先,创建一个canvas的容器
html
<canvas id="ctx" style="border:1px solid #000;" width="600" height="600">
</canvas>
js
getDom(domId){
return document.querySelector(domId)
}
let canvas = getDom('#ctx')
let ctx = canvas.getContext('2d')
介绍完创建画板之后,接下来进入我们画多边形的代码
js
构建一个类
let start = new Draw('#ctx')
class Draw(){
constructor(domId){
//画板容器
this.domId = domId
//用于存放每次鼠标点击的位置
this.dataList=[]
//端点变化模式
this.isChange = false
//第几个图形
this.changeFatherIndex = 0
//第几个坐标点
this.changeIndex = 0
}
}
获取dom
getDom(){
//this.domId 是构造函数中存好的
let canvas = document.querySelector(this.domId)
let ctx = canvas.getContent('2d')
//完成选区按钮
let btn = document.querySelector(this.btnId)
return {
canvas,
ctx,
btn
}
}
注册鼠标事件
event(){
//鼠标按下的事件,start方法是用来记录点击的坐标点存放入dataList中
document.addEventListener('mousedown',this.start.bind(this))
//在端点变化模式开启使用
document.addEventListener('mouseup', this.closeChange.bind(this))
document.addEventListener('mousemove', this.changeData.bind(this))
//完成选取
btn.addEventListener('click', this.end.bind(this))
}
画图
(每次数据发生变化重新绘制图形)因为后面有一个端点拖动的需求
draw(){
let {
canvas,
} = this.getDom()
let ctx = canvas.getContext("2d")
//为了实现多个图形都可以编辑,在数组中嵌套数组对象,第一层的数组代表了有多少个图形,第二层的数组以
//`{x,y}`的形式存放着每一个端点
this.dataList.forEach((item, i) => {
item.forEach((itemi, indexi) => {
//如果indexi !== 0 时不是起始点就直接往下继续画,相反是起始点的时候开始创建路径画图
if (indexi !== 0) {
ctx.arc(itemi.x, itemi.y, 1, 0, 2 * Math.PI);//画一个小圆点看的明显一点
ctx.lineTo(itemi.x, itemi.y)
if (indexi == item.length - 1 && this.isChange) {
ctx.closePath()
}
ctx.stroke()
} else {
//当不是第一个的时候闭合上一个图形
if (i > 0) {
ctx.closePath()
ctx.stroke()
ctx.beginPath()
} else {
ctx.beginPath()
}
ctx.arc(itemi.x, itemi.y, 1, 0, 2 * Math.PI);
ctx.stroke()
ctx.moveTo(itemi.x, itemi.y)
}
})
})
}
记录坐标
start(e) {
let {
canvas,
} = this.getDom()
//鼠标x y轴位置
let x = e.pageX - canvas.offsetLeft
let y = e.pageY - canvas.offsetTop
//最大宽度位置
let bodyX = e.pageX + canvas.offsetWidth
let bodyY = e.pageY + canvas.offsetHeight
//第一次进入时创建第一个图形
if (this.dataList.length == 0) {
this.dataList = [
[]
]
}
//判断是否在画板框中
if (y > e.offsetY && y < bodyY && x > e.offsetX && x < bodyX) {
//searchData方法是用于点击端点时改变画图模式
if (this.searchData(x, y)) {
//改变端点
this.isChange = true
} else {
this.dataList[this.dataList.length - 1].push({
x,
y
})
this.fatherIndex = this.dataList.length - 1
this.draw()
}
}
}
检测是否为端点
searchData(x, y) {
let flag = false
this.dataList.forEach((item, index) => {
item.forEach((data, i) => {
//点击端点时友好一些,给个点容错
if (data.x > x - 3 && data.x < x + 3 && data.y > y - 3 && data.y < y + 3) {
this.changeFatherIndex = index
this.changeIndex = i
flag = true
}
})
})
return flag
}
闭合图形-完成选区
end() {
let {
canvas,
} = this.getDom()
let ctx = canvas.getContext("2d")
ctx.closePath()
ctx.stroke()
ctx.beginPath()
//创建下一个图形
this.dataList.push([])
}
变化端点
changeData(e) {
//是否开启了端点变化模式
if (this.isChange) {
this.close()
let {
canvas,
} = this.getDom()
let x = e.pageX - canvas.offsetLeft
let y = e.pageY - canvas.offsetTop
//最大宽度位置
let bodyX = e.pageX + canvas.offsetWidth
let bodyY = e.pageY + canvas.offsetHeight
if (y > e.offsetY && y < bodyY && x > e.offsetX && x < bodyX) {
//改变端点坐标
this.dataList[this.changeFatherIndex][this.changeIndex] = {
x,
y
}
//重新绘制
this.draw()
}
}
}
点击完成选取闭合图形
closeChange() {
this.isChange = false
}
html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas多边形</title>
</head>
<body>
<div>
<button id="btn">完成选区</button>
</div>
<canvas id="ctx" style="border:1px solid #000;" width="600" height="600">
</canvas>
</body>
</html>
结语
分享一下我对画多边形的思路 首先得创建好一个画板,鼠标点击第一次的时候需要创建一个起始点,之后的点击让线一点一点的连起来,最后画好图形点击完成选取的按钮闭合图形。
拖动端点改变端点位置,在上面我们先把每一个画好图形的(x,y)坐标去存到一个数组里面,鼠标从点击端点时保存好端点的位置,鼠标抬起时把当前拖动的端点(x,y)坐标改变,去清空画板重新beginTo()一个新的图形
在写项目的过程中,经常会写到很多重复的代码,复用性不是很高 这次尝试使用面向对象的编程模式,使用过程中感觉到了不少的益处,最重要的是代码可读性会更高一些,在找bug的时候能轻易的分辨。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!