简介
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介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
 
                     
     
        
       
        
       
        
       
        
       
    
发表评论
还没有评论,快来抢沙发吧!