文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

HTML中如何实现一个canvas智绘画板

2023-06-09 13:12

关注

这篇文章主要介绍了HTML中如何实现一个canvas智绘画板,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

 一、项目介绍

名称:智绘画板

技术栈:HTML5,CSS3,JavaScript,移动端

功能描述:

 二、项目效果展示

项目地址 预览地址

预览图

PC端的预览图:

HTML中如何实现一个canvas智绘画板

移动端的预览图:

HTML中如何实现一个canvas智绘画板

看完上面的预览图和体验过 智绘画板 觉得还可以的,记得点个赞哦,不管你是否十分激动,反正我是挺激动的,毕竟自己实现出现的项目效果,挺自豪的,说了一堆废话,下面就可以动起手来敲代码,实现自己想要的效果!!!

注:下面实现项目效果主要是关于JavaScript方面的,下面仅仅是提供 实现思路的代码并非全部代码

三、一步步实现项目效果

(一)分析页面

通过 用例图 ,我们知道用户进入我们这个网站有哪些功能?

用户可以进行的操作:

(二)进行HTML布局

我书写html的同时,引入了css文件和js文件

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>智绘画板</title>    <link rel="shortcut icon" href="./image/favicon.png" type="image/x-icon">    <link rel="stylesheet" href="./css/style.css"></head><body>    <canvas id="canvas"></canvas>    <div class="bg-btn"></div>    <div class="color-group" id="bgGroup">        <h4>选择背景颜色:</h4>        <ul class="clearfix">            <li class="bgcolor-item" style="background-color: blue;"></li>            <li class="bgcolor-item" style="background-color: black;"></li>            <li class="bgcolor-item" style="background-color: #FF3333;"></li>            <li class="bgcolor-item" style="background-color: #0066FF;"></li>            <li class="bgcolor-item" style="background-color: #FFFF33;"></li>            <li class="bgcolor-item" style="background-color: #33CC66;"></li>            <li class="bgcolor-item" style="background-color: gray;"></li>            <li class="bgcolor-item" style="background-color: #F34334;"></li>            <li class="bgcolor-item" style="background-color: #fff;box-shadow: 0 1px 2px 0 rgba(32,33,36,0.28);"></li>            <li class="bgcolor-item" style="background-color: #9B27AC;"></li>            <li class="bgcolor-item" style="background-color: #4CB050;"></li>            <li class="bgcolor-item" style="background-color: #029688;"></li>        </ul>        <i class="closeBtn"></i>    </div>    <div class="tools">        <div class="container">            <button class="save"  id="save" title="保存"></button>            <button class="brush active" id="brush" title="画笔"></button>            <button class="eraser" id="eraser" title="橡皮擦"></button>            <button class="clear" id="clear" title="清屏"></button>            <button class="undo"  id="undo" title="撤销"></button>            <button class="redo"  id="redo" title="再做"></button>        </div>    </div>    <div class="pen-detail" id="penDetail">        <i class="closeBtn"></i>        <p>笔大小</p>        <span class="circle-box"><i id="thickness"></i></span> <input type="range" id="range1" min="1" max="10" value="1">        <p>笔颜色</p>        <ul class="pen-color clearfix">            <li class="color-item active" style="background-color: black;"></li>            <li class="color-item" style="background-color: #FF3333;"></li>            <li class="color-item" style="background-color: #99CC00;"></li>            <li class="color-item" style="background-color: #0066FF;"></li>            <li class="color-item" style="background-color: #FFFF33;"></li>            <li class="color-item" style="background-color: #33CC66;"></li>        </ul>        <p>不透明度</p>        <i class="showOpacity"></i> <input type="range" id="range2" min="1" max="10" value="1">    </div>    <script src="./js/main.js"></script></body></html>

(三)用CSS美化界面

css代码可以根据个人习惯进行美化界面,所以这里就不写css的代码了,大家可以直接看 项目代码 或者从开发者工具中审查元素观看。如果有问题可以私聊我,我觉得问题不大。

(四)使用JS实现项目的具体功能

准备工作

首先,准备个容器,也就是画板了,前面的html已经书写好这个容器,这里纯属是废话。

<canvas id="canvas"></canvas>

然后初始化js

let canvas = document.getElementById('canvas');let context = canvas.getContext('2d');

我打算把画板做成全屏的,所以接下来设置一下 canvas 的宽高

let pageWidth = document.documentElement.clientWidth;let pageHeight = document.documentElement.clientHeight;canvas.width = pageWidth;canvas.height = pageHeight;

由于部分IE不支持 canvas ,如果要兼容IE,我们可以创建一个 canvas ,然后使用 excanvas 初始化,针对IE加上exCanvas.js,这里我们明确不考虑IE。

但是我在电脑上对浏览器的窗口进行改变,画板不会自适应的放缩。解决办法:

// 记得要执行autoSetSize这个函数哦function autoSetSize(){    canvasSetSize();    // 当执行这个函数的时候,会先设置canvas的宽高    function canvasSetSize(){        let pageWidth = document.documentElement.clientWidth;        let pageHeight = document.documentElement.clientHeight;                canvas.width = pageWidth;        canvas.height = pageHeight;    }    // 在窗口大小改变之后,就会触发resize事件,重新设置canvas的宽高    window.onresize = function(){        canvasSetSize();    }}

实现画画的功能

实现思路:监听鼠标事件, 用 drawLine() 方法把记录的数据画出来。

注: drawCircle 这个方法其实可以不用书写,这个只是为了让大家能够理解开始点击的位置在哪里?

function listenToUser() {    // 定义一个变量初始化画笔状态    let painting = false;    // 记录画笔最后一次的位置    let lastPoint = {x: undefined, y: undefined};    // 鼠标按下事件    canvas.onmousedown = function(e){        painting = true;        let x = e.clientX;        let y = e.clientY;        lastPoint = {'x':x,'y':y};        drawCircle(x,y,5);    }    // 鼠标移动事件    canvas.onmousemove = function(e){        if(painting){            let x = e.clientX;            let y = e.clientY;            let newPoint = {'x':x,'y':y};            drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y);            lastPoint = newPoint;        }    }    // 鼠标松开事件    canvas.onmouseup = function(){        painting = false;    }}// 画点函数function drawCircle(x,y,radius){    // 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。    context.beginPath();    // 画一个以(x,y)为圆心的以radius为半径的圆弧(圆),    // 从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。    context.arc(x,y,radius,0,Math.PI*2);    // 通过填充路径的内容区域生成实心的图形    context.fill();    // 闭合路径之后图形绘制命令又重新指向到上下文中。    context.closePath();}function drawLine(x1,y1,x2,y2){    // 设置线条宽度    context.lineWidth = 10;    // 设置线条末端样式。    context.lineCap = "round";    // 设定线条与线条间接合处的样式    context.lineJoin = "round";    // moveTo(x,y)将笔触移动到指定的坐标x以及y上    context.moveTo(x1,y1);    // lineTo(x, y) 绘制一条从当前位置到指定x以及y位置的直线    context.lineTo(x2,y2);    // 通过线条来绘制图形轮廓    context.stroke();    context.closePath();}

实现橡皮擦功能

实现思路:

  1. 获取橡皮擦元素

  2. 设置橡皮擦初始状态, eraserEnabled = false

  3. 监听橡皮擦 click 事件,点击橡皮擦,改变橡皮擦状态, eraserEnabled = true ,并且切换class,实现 被激活 的效果。

  4. eraserEnabledtrue 时,移动鼠标用 context.clearRect() 实现了 橡皮檫。

但是我发现canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除区域矩形,毕竟大部分人的习惯中的橡皮擦都是圆形的,所以就引入了剪辑区域这个强大的功能,也就是clip方法。下面的代码是使用 context.clearRect() 实现了 橡皮檫。请看踩坑部分,了解如何更好的实现橡皮檫。

let eraser = document.getElementById("eraser");let eraserEnabled = false;// 记得要执行listenToUser这个函数哦function listenToUser() {   // ... 代表省略了之前写的代码    // ...    // 鼠标按下事件    canvas.onmousedown = function(e){        // ...        if(eraserEnabled){//要使用eraser            context.clearRect(x-5,y-5,10,10)        }else{            lastPoint = {'x':x,'y':y}        }    }    // 鼠标移动事件    canvas.onmousemove = function(e){        let x = e.clientX;        let y = e.clientY;        if(!painting){return}        if(eraserEnabled){            context.clearRect(x-5,y-5,10,10);        }else{            var newPoint = {'x':x,'y':y};            drawLine(lastPoint.x, lastPoint.y,newPoint.x, newPoint.y);            lastPoint = newPoint;        }      }    // ...}// 点击橡皮檫eraser.onclick = function(){    eraserEnabled = true;    eraser.classList.add('active');    brush.classList.remove('active');}

实现清屏功能

实现思路:

获取元素节点。

点击清空按钮清空canvas画布。

let reSetCanvas = document.getElementById("clear");// 实现清屏reSetCanvas.onclick = function(){    ctx.clearRect(0,0,canvas.width,canvas.height);    setCanvasBg('white');}// 重新设置canvas背景颜色function setCanvasBg(color) {    ctx.fillStyle = color;    ctx.fillRect(0, 0, canvas.width, canvas.height);}

实现保存成图片功能

实现思路:

let save = document.getElementById("save");// 下载图片save.onclick = function(){    let imgUrl = canvas.toDataURL('image/png');    let saveA = document.createElement('a');    document.body.appendChild(saveA);    saveA.href = imgUrl;    saveA.download = 'mypic'+(new Date).getTime();    saveA.target = '_blank';    saveA.click();}

实现改变背景颜色的功能

实现思路:

  1. 获取相应的元素节点。

  2. 给每一个class为bgcolor-item的标签添加点击事件,当点击事件触发时,改变背景颜色。

  3. 点击设置背景颜色的div之外的地方,实现隐藏那个div。

let selectBg = document.querySelector('.bg-btn');let bgGroup = document.querySelector('.color-group');let bgcolorBtn = document.querySelectorAll('.bgcolor-item');let penDetail = document.getElementById("penDetail");let activeBgColor = '#fff';// 实现了切换背景颜色for (let i = 0; i < bgcolorBtn.length; i++) {    bgcolorBtn[i].onclick = function (e) {        // 阻止冒泡        e.stopPropagation();        for (let i = 0; i < bgcolorBtn.length; i++) {            bgcolorBtn[i].classList.remove("active");            this.classList.add("active");            activeBgColor = this.style.backgroundColor;            setCanvasBg(activeBgColor);        }    }}document.onclick = function(){    bgGroup.classList.remove('active');}selectBg.onclick = function(e){    bgGroup.classList.add('active');    e.stopPropagation();}

实现改变画笔粗细的功能

实现思路:

  1. 实现让设置画笔的属性的对话框出现。

  2. 获取相应的元素节点。

  3. 当input=range的元素发生改变的时候,获取到的值赋值给lWidth。

  4. 然后设置context.lineWidth = lWidth。

let range1 = document.getElementById('range1');let lWidth = 2;let ifPop = false;range1.onchange = function(){    console.log(range1.value);    console.log(typeof range1.value)    thickness.style.transform = 'scale('+ (parseInt(range1.value)) +')';    console.log(thickness.style.transform )    lWidth = parseInt(range1.value*2);}// 画线函数function drawLine(x1,y1,x2,y2){    // ...    context.lineWidth = lWidth;    // ...}// 点击画笔brush.onclick = function(){    eraserEnabled = false;    brush.classList.add('active');    eraser.classList.remove('active');    if(!ifPop){        // 弹出框        console.log('弹一弹')        penDetail.classList.add('active');    }else{        penDetail.classList.remove('active');    }    ifPop = !ifPop;}

实现改变画笔颜色的功能

实现思路跟 改变画板背景颜色 的思路类似。

let aColorBtn = document.getElementsByClassName("color-item");getColor();function getColor(){    for (let i = 0; i < aColorBtn.length; i++) {        aColorBtn[i].onclick = function () {            for (let i = 0; i < aColorBtn.length; i++) {                aColorBtn[i].classList.remove("active");                this.classList.add("active");                activeColor = this.style.backgroundColor;                ctx.fillStyle = activeColor;                ctx.strokeStyle = activeColor;            }        }    }}

实现改变撤销和重做的功能

实现思路:

  1. 保存快照:每完成一次绘制操作则保存一份 canvas 快照到 canvasHistory 数组(生成快照使用 canvas 的 toDataURL() 方法,生成的是 base64 的图片);

  2. 撤销和反撤销:把 canvasHistory 数组中对应索引的快照使用 canvas 的 drawImage() 方法重绘一遍;

  3. 绘制新图像:执行新的绘制操作时,删除当前位置之后的数组记录,然后添加新的快照。

let undo = document.getElementById("undo");let redo = document.getElementById("redo");// ...canvas.onmouseup = function(){        painting = false;        canvasDraw();}let canvasHistory = [];let step = -1;// 绘制方法function canvasDraw(){    step++;    if(step < canvasHistory.length){        canvasHistory.length = step;  // 截断数组    }    // 添加新的绘制到历史记录    canvasHistory.push(canvas.toDataURL());}// 撤销方法function canvasUndo(){    if(step > 0){        step--;        // ctx.clearRect(0,0,canvas.width,canvas.height);        let canvasPic = new Image();        canvasPic.src = canvasHistory[step];        canvasPic.onload = function () { ctx.drawImage(canvasPic, 0, 0); }        undo.classList.add('active');    }else{        undo.classList.remove('active');        alert('不能再继续撤销了');    }}// 重做方法function canvasRedo(){    if(step < canvasHistory.length - 1){        step++;        let canvasPic = new Image();        canvasPic.src = canvasHistory[step];        canvasPic.onload = function () {             // ctx.clearRect(0,0,canvas.width,canvas.height);            ctx.drawImage(canvasPic, 0, 0);        }        redo.classList.add('active');    }else {        redo.classList.remove('active')        alert('已经是最新的记录了');    }}undo.onclick = function(){    canvasUndo();}redo.onclick = function(){    canvasRedo();}

兼容移动端

实现思路:

// ...if (document.body.ontouchstart !== undefined) {    // 使用touch事件    anvas.ontouchstart = function (e) {        // 开始触摸    }    canvas.ontouchmove = function (e) {        // 开始滑动    }    canvas.ontouchend = function () {        // 滑动结束    }}else{    // 使用mouse事件    // ...}// ...

四、踩坑

 问题1:在电脑上对浏览器的窗口进行改变,画板不会自适应

解决办法:

onresize响应事件处理中,获取到的页面尺寸参数是变更后的参数 。

当窗口大小发生改变之后,重新设置canvas的宽高,简单来说,就是窗口改变之后,给canvas.width和canvas.height重新赋值。

// 记得要执行autoSetSize这个函数哦function autoSetSize(){    canvasSetSize();    // 当执行这个函数的时候,会先设置canvas的宽高    function canvasSetSize(){        let pageWidth = document.documentElement.clientWidth;        let pageHeight = document.documentElement.clientHeight;                canvas.width = pageWidth;        canvas.height = pageHeight;    }    // 在窗口大小改变之后,就会触发resize事件,重新设置canvas的宽高    window.onresize = function(){        canvasSetSize();    }}

问题2:当绘制线条宽度比较小的时候还好,一旦比较粗就会出现问题

解决办法:看一下文档,得出方法,只需要简单修改一下 绘制线条的代码 就行

// 画线函数function drawLine(x1,y1,x2,y2){    context.beginPath();    context.lineWidth = lWidth;    //-----加入-----    // 设置线条末端样式。    context.lineCap = "round";    // 设定线条与线条间接合处的样式    context.lineJoin = "round";    //-----加入-----    context.moveTo(x1,y1);    context.lineTo(x2,y2);    context.stroke();    context.closePath();}

问题3:如何实现圆形的橡皮檫?

解决办法:

canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除区域矩形,毕竟大部分人的习惯中的橡皮擦都是圆形的,所以就引入了剪辑区域这个强大的功能,也就是clip方法。用法很简单:

ctx.save()ctx.beginPath()ctx.arc(x2,y2,a,0,2*Math.PI);ctx.clip()ctx.clearRect(0,0,canvas.width,canvas.height);ctx.restore();

上面那段代码就实现了圆形区域的擦除,也就是先实现一个圆形路径,然后把这个路径作为剪辑区域,再清除像素就行了。有个注意点就是需要先保存绘图环境,清除完像素后要重置绘图环境,如果不重置的话以后的绘图都是会被限制在那个剪辑区域中。

问题4:如何兼容移动端?

添加meta标签

因为浏览器初始会将页面现在手机端显示时进行缩放,因此我们可以在meta标签中设置meta viewport属性,告诉浏览器不将页面进行缩放,页面宽度=用户设备屏幕宽度

<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0"/>

在移动端几乎使用的都是touch事件,与PC端不同

由于移动端是触摸事件,所以要用到H5的属性touchstart/touchmove/touchend,但是PC端只支持鼠标事件,所以要进行特性检测。

touch 事件里,是通过 .touches[0].clientX.touches[0].clientY 来获取坐标的,这点要和 mouse 事件区别开。

问题5:出现一个问题就是清空之后,重新画,然后出现原来的画的东西

这个嘛,问题不大,只不过是我漏写context.beginPath(); ,也花了一点时间在上面解决bug,让我想起“代码千万行,注释第一行;编程不规范,同事两行泪 ”,还是按照文档操作规范操作好,真香!!!

html有什么特点

1、简易性:超级文本标记语言版本升级采用超集方式,从而更加灵活方便,适合初学前端开发者使用。2、可扩展性:超级文本标记语言的广泛应用带来了加强功能,增加标识符等要求,超级文本标记语言采取子类元素的方式,为系统扩展带来保证。 3、平台无关性:超级文本标记语言能够在广泛的平台上使用,这也是万维网盛行的一个原因。4、通用性:HTML是网络的通用语言,它允许网页制作人建立文本与图片相结合的复杂页面,这些页面可以被网上任何其他人浏览到,无论使用的是什么类型的电脑或浏览器。

感谢你能够认真阅读完这篇文章,希望小编分享的“HTML中如何实现一个canvas智绘画板”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯