编写静态页面

html代码和css样式如下图,这一块比较大略,也不是本文重点,可自行查看。

<!DOCTYPE html><html lang=&#34;zh"><head> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" /> <title>涂鸦</title> <link rel="shortcut icon" href="#" /> <link rel="stylesheet" type="text/css" href="css/base.css"> <link rel="stylesheet" type="text/css" href="css/handWriting.css"></head><body> <div class="wrapper"> <canvas class="offCanvas"></canvas> <canvas class="canvas"></canvas> </div> <div class="footer"> <div class="control-button"> <div class="item colorButton"><img src="images/colors.png" alt=""><span>玄色</span></div> <div class="item sizeButton"><img src="images/size.png" alt=""><span>中笔</span></div> <div class="item bgButton"><img src="images/bg.png" alt=""><span>背景</span></div> <div class="item rubberButton"><img src="images/rubber.png" alt=""><span>擦掉</span></div> <div class="item historyButton"><img src="images/history.png" alt=""><span>历史</span></div> <div class="item clearButton"><img src="images/clear.png" alt=""><span>清屏</span></div> <div class="item saveButton"><img src="images/save.png" alt=""><span>保存</span></div> </div> <div class="pop-up colors-panel"> <div class="title">笔触颜色<span class="closeBtn"></span></div> <div class="colors"> <div class="lineColors"> <div><span class="red" data-text="赤色" data-color="#ff0000"></span></div> <div><span class="blue" data-text="蓝色" data-color="#0000ff"></span></div> <div><span class="green" data-text="绿色" data-color="#00ff00"></span></div> <div><span class="black" data-text="玄色" data-color="#000000"></span></div> <div><span class="orange" data-text="橙色" data-color="#ff6302"></span></div> </div> <div class="lineColors"> <div><span class="red" data-text="赤色" data-color="#ff0000"></span></div> <div><span class="blue" data-text="蓝色" data-color="#0000ff"></span></div> <div><span class="green" data-text="绿色" data-color="#00ff00"></span></div> <div><span class="black" data-text="玄色" data-color="#000000"></span></div> <div><span class="orange" data-text="橙色" data-color="#ff6302"></span></div> </div> </div> </div> <div class="pop-up size-panel"> <div class="title">笔触大小<span class="closeBtn"></span></div> <div class="sizes"> <div class="lineSizes"><span data-lineWidth="10" data-text="大笔" class="big"></span></div> <div class="lineSizes"><span data-lineWidth="30" data-text="中笔" class="middle"></span></div> <div class="lineSizes"><span data-lineWidth="50" data-text="小笔" class="small"></span></div> </div> </div> <div class="pop-up bg-panel"> <div class="title">推举背景<span class="closeBtn"></span></div> <div class="list"> <img src="images/white.jpg" alt="" /> <img src="images/white.jpg" alt="" /> <img src="images/white.jpg" alt="" /> <img src="images/white.jpg" alt="" /> <img src="images/white.jpg" alt="" /> </div> </div> <!-- 添加橡皮檫列表和历史记录列表样式 --> <div class="pop-up rubber-panel"> <div class="title">橡皮檫大小<span class="closeBtn"></span></div> <div class="rubbers"> <div class="first">大小:</div> <div class="second"><input type="range" min="1" max="50" value="25" step="1" name="大小" /></div> <div class="last"><span class="rubberSize">25</span>像素</div> </div> </div> <div class="pop-up history-panel"> <div class="title">历史记录<span class="closeBtn"></span></div> <div class="history"> <div class="lineBox"></div> </div> </div> </div> <div class="offImgs" style="display: none;"></div> <script src="js/jquery.min.js"></script> <script src="js/handWriting.js"></script></body></html>

html,body,.wrapper { height: 100%}.wrapper { position: relative; padding-bottom: 60px; box-sizing: border-box}.wrapper .offCanvas,.wrapper .canvas { position: absolute; top: 0; left: 0}.footer { position: absolute; bottom: 0; width: 100%; height: 60px; background-color: #fff; box-shadow: 0 0 10px 3px #e2e2e2; overflow: hidden;}.footer .control-button { display: flex; height: 100%}.control-button .item { flex: 1; text-align: center}.control-button .item img { width: 22px; height: 22px; margin: 8px auto 5px; display: block;}.control-button .item span { color: #2e344a; font-size: 12px}/后面添加//笔触设置/.footer .pop-up{display:none;height:130px;padding:0 15px}.pop-up .title{font-size:14px;color:#eb4985;margin:10px 0 15px;text-align:center}.pop-up .title .closeBtn{background:url("../images/close.png") no-repeat;background-size:100%;width:20px;height:20px;float:right}.pop-up .colors{overflow:hidden}.pop-up .lineColors div{width:20%;float:left;margin:6px 0}.pop-up .lineColors span{display:block;width:28px;height:28px;margin:auto;border-radius:50%}.pop-up .lineColors span.red{background-color:#f00}.pop-up .lineColors span.blue{background-color:#00f}.pop-up .lineColors span.green{background-color:#0f0}.pop-up .lineColors span.black{background-color:#000}.pop-up .lineColors span.orange{background-color:#ff6302}.pop-up .sizes{margin-top:20px}.pop-up .sizes .lineSizes{height:30px;cursor:pointer}.pop-up .sizes .big{display:block;height:10px;width:100%;background-color:#eb4985;border-radius:3px}.pop-up .sizes .middle{display:block;height:6px;width:100%;background-color:#eb4985;border-radius:3px}.pop-up .sizes .small{display:block;height:3px;width:100%;background-color:#eb4985;border-radius:3px}.pop-up .list{height:80px;line-height:80px}.pop-up .list img{width:20%;float:left;padding:5px;box-sizing:border-box}/橡皮檫样式/.rubbers { display: flex; color: #2e344a; font-size: 14px; margin-top: 40px;}.rubbers div { flex: 1;}.rubbers .second { flex: 5;}.rubbers .second input { /滑动条的样式/ width: 100%; -webkit-appearance: none; height: 3px; border-radius: 5px; vertical-align: super; background-color: #2e344a;}.rubbers .second input::-webkit-slider-thumb { /滑动条的样式/ -webkit-appearance: none; height: 25px; width: 25px; background-color: #eb4985; border-radius: 50%;}.rubbers .last { text-align: right;}.history-panel .history { overflow-x: scroll; -webkit-overflow-scrolling: touch;}.history-panel .lineBox img { width: 70px; height: 70px; border: 1px solid #2e344a; margin-right: 8px;}实现事理

$(function() { var offCanvas = $(&#39;.offCanvas')[0]; // 用于改换背景图 var offCtx = offCanvas.getContext('2d'); var canvas = $('.canvas')[0]; // 用于涂鸦 var ctx = canvas.getContext('2d'); var lastCoordinate = null; // 前一个坐标 var lastTimestamp = 0; // 前一个韶光戳 var lastLineWidth = -1; // 用于线光滑过度 var point = null; // 存储鼠标或触发坐标 var sizeWidth = 30; // 中笔触打算值 var strokeColor = '#000'; // 笔触颜色默认玄色 var imgSrc = null; // 背景图片地址 var imgArray = []; // 存储背景图和涂鸦图 var rubberSize = 25; // 存储橡皮檫大小 var flag = true; // 用于判断涂鸦还是擦除 var footerHeight = $('.footer').height(); // 获取底部高度 offCanvas.width = $(window).width(); offCanvas.height = $(window).height() - footerHeight; canvas.width = $(window).width(); canvas.height = $(window).height() - footerHeight; // 选择颜色 $('.lineColors span').click(function() { strokeColor = $(this).attr('data-color'); // 获取颜色值,用于更换笔触颜色 var colorName = $(this).attr('data-text'); // 获取颜色笔墨,用于更换操作栏笔墨 $('.colorButton span').html(colorName); // 更换操作栏笔墨 animatePanel('.colors-panel', '-130px', '.control-button', '60px'); // 收转机彩列表显示操作栏 }); // 选择大小 $('.lineSizes span').click(function() { sizeWidth = $(this).attr('data-lineWidth'); // 获取大小值,用于打算笔触大小 var sizeName = $(this).attr('data-text'); // 获取大小笔墨,用于更换操作栏笔墨 $('.sizeButton span').html(sizeName); // 更换操作栏笔墨 animatePanel('.size-panel', '-130px', '.control-button', '60px'); // 收起大小列表显示操作栏 }); // canvas触摸事宜 $('.canvas').on('touchstart', function(event) { point = { x: event.originalEvent.targetTouches[0].clientX, y: event.originalEvent.targetTouches[0].clientY }; lastCoordinate = windowToCanvas(point.x, point.y); lastTimestamp = new Date().getTime(); }); $('.canvas').on('touchmove', function(event) { point = { x: event.originalEvent.targetTouches[0].clientX, y: event.originalEvent.targetTouches[0].clientY }; var curCoordinate = windowToCanvas(point.x, point.y); if (flag) { // 涂鸦 var curTimestamp = new Date().getTime(); var s = calcDistance(lastCoordinate, curCoordinate); // 打算两点之间的间隔 var t = curTimestamp - lastTimestamp; // 打算两点之间的韶光差 var curLineWidth = caleLineWidth(s, t, sizeWidth); drawLine(ctx, lastCoordinate.x, lastCoordinate.y, curCoordinate.x, curCoordinate.y, curLineWidth, strokeColor); lastCoordinate = curCoordinate; // 现在坐标更换前一个坐标 lastTimestamp = curTimestamp; lastLineWidth = curLineWidth; } else { // 擦掉 ctx.save(); ctx.beginPath(); ctx.arc(curCoordinate.x, curCoordinate.y, rubberSize/2, 0, Math.PI 2); ctx.clip(); ctx.clearRect(curCoordinate.x - rubberSize/2, curCoordinate.y - rubberSize/2, rubberSize, rubberSize); // 打消涂鸦画布内容 ctx.restore(); } }); $('.canvas').on('touchend', function() { var imageSrc = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); // 画布转换为图片地址 $('.lineBox').append('<img src="' + imageSrc + '" />'); var boxWidth = $('.lineBox img').length 80; // 80为图片宽度(72)+间隔(8) $('.lineBox').css({ // 设置lineBox宽度 width: boxWidth + 'px' }); }); // 根据不同速率打算线的宽度函数 function caleLineWidth(s, t, brushWidth) { var v = s / t; // 获取速率 // 声明最大最小速率和最大最小边界 var maxVelocity = 10, minVelocity = 0.1, maxLineWidth = Math.min(30, canvas.width / brushWidth), // 避免手机端线条太粗 minLineWidth = 1, resultLineWidth; // 用于返回的线宽度 if (v <= minVelocity) { resultLineWidth = maxLineWidth; } else if (v >= maxVelocity) { resultLineWidth = minLineWidth; } else { resultLineWidth = maxLineWidth - (v - minVelocity) / (maxVelocity - minVelocity) (maxLineWidth - minLineWidth); } if (lastLineWidth == -1) { // 开始时候 return resultLineWidth; } else { return resultLineWidth 2 / 3 + lastLineWidth 1 / 3; // lastLineWidth占得比重越大越平滑 } } // 打算两点之间的间隔函数 function calcDistance(lastCoordinate, curCoordinate) { var distance = Math.sqrt(Math.pow(curCoordinate.x - lastCoordinate.x, 2) + Math.pow(curCoordinate.y - lastCoordinate.y, 2)); return distance; } // 坐标转换 function windowToCanvas(x, y) { var bbox = canvas.getBoundingClientRect(); return { x: x - bbox.left, y: y - bbox.top }; } // 绘制直线 function drawLine(context, x1, y1, x2, y2, /optional/ lineWidth, /optional/ strokeColor) { context.beginPath(); context.lineTo(x1, y1); context.lineTo(x2, y2); context.lineWidth = lineWidth; context.lineCap = 'round'; // 线与线交合不会产生空隙 context.lineJoin = 'round'; context.strokeStyle = strokeColor; // 默认笔触玄色 context.stroke(); } // 选择背景 $('.bg-panel img').click(function() { imgSrc = $(this).attr('src'); // 获取图片src drawImg(imgSrc); // 画图 animatePanel('.bg-panel', '-130px', '.control-button', '60px'); }); // 绘制图像到画布 function drawImg(changeValue) { offCtx.clearRect(0, 0, canvas.width, canvas.height); // 先打消画布 var changeImg = new Image(); // changeImg.crossOrigin = 'Anonymous'; changeImg.src = changeValue; changeImg.onload = function() { offCtx.drawImage(changeImg, 0, 0, canvas.width, canvas.height); }; } // 清屏 $('.clearButton').click(function() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 打消涂鸦画布内容 offCtx.clearRect(0, 0, canvas.width, canvas.height); // 打消背景图画布内容 }); // 保存涂鸦效果 $('.saveButton').click(function() { // toDataURL兼容大部分浏览器,缺陷便是保存的文件没有后缀名 if (imgSrc) { // 存在背景图才实行 imgArray.push(offCanvas.toDataURL('image/png').replace('image/png', 'image/octet-stream')); } imgArray.push(canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream')); compositeGraph(imgArray); }); / [离屏合成图] @param {[type]} imgArray [背景图画布和涂鸦画布的地址数组] / function compositeGraph(imgArray) { // 下载后的文件名 var filename = 'canvas_' + (new Date()).getTime() + '.png'; var compositeCanvas = document.createElement('canvas'); compositeCanvas.width = canvas.width; compositeCanvas.height = canvas.height; var compositeCtx = compositeCanvas.getContext('2d'); $.each(imgArray, function(index, val) { $('.offImgs').append('<img src="' + val + '" />'); // 增加img元素用于获取合成 }); $.each($('.offImgs img'), function(index, val) { val.onload = function() { compositeCtx.drawImage(val, 0, 0); // 循环绘制图片到离屏画布 }; }); var timer = setTimeout(function() { var compositeImg = compositeCanvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); saveFile(compositeImg, filename); timer = null; // 注销定时器 }, 50); } / 仿照鼠标点击事宜进行保存 @param {String} data 要保存到本地的图片数据 @param {String} filename 文件名 / function saveFile(data, filename) { var saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); saveLink.href = data; saveLink.download = filename; // download只兼容chrome和firefox,须要兼容全部浏览器,只能用做事器保存 var event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); saveLink.dispatchEvent(event); } // 点击颜色按钮弹精彩彩列表 $('.colorButton').click(function() { animatePanel('.control-button', '-60px', '.colors-panel', '130px'); flag = true; // 点击颜色时候变为涂鸦状态 }); // 点击颜色列表的关闭按钮 $('.colors-panel .closeBtn').click(function() { animatePanel('.colors-panel', '-130px', '.control-button', '60px'); }); // 点击大小按钮弹出大小列表 $('.sizeButton').click(function() { animatePanel('.control-button', '-60px', '.size-panel', '130px'); flag = true; // 点击大小时候变为涂鸦状态 }); // 点击大小列表的关闭按钮 $('.size-panel .closeBtn').click(function() { animatePanel('.size-panel', '-130px', '.control-button', '60px'); }); // 点击背景按钮弹出背景列表 $('.bgButton').click(function() { animatePanel('.control-button', '-60px', '.bg-panel', '130px'); }); // 点击背景列表的关闭按钮 $('.bg-panel .closeBtn').click(function() { animatePanel('.bg-panel', '-130px', '.control-button', '60px'); }); // 点击擦掉按钮弹出橡皮檫大小列表 $('.rubberButton').click(function() { animatePanel('.control-button', '-60px', '.rubber-panel', '130px'); flag = false; // 点击擦掉时候变为橡皮檫状态 }); // 点击橡皮檫大小列表的关闭按钮 $('.rubber-panel .closeBtn').click(function() { animatePanel('.rubber-panel', '-130px', '.control-button', '60px'); }); // 拖动滑动条获取数值 $('.rubbers .second input').on('touchmove', function() { rubberSize = $(this)[0].value; $('.rubberSize').html(rubberSize); }); // 点击历史按钮弹出历史记录列表 $('.historyButton').click(function() { animatePanel('.control-button', '-60px', '.history-panel', '130px'); }); // 点击历史记录列表的关闭按钮 $('.history-panel .closeBtn').click(function() { animatePanel('.history-panel', '-130px', '.control-button', '60px'); }); // 点击历史记录图片绘制到画布 $('.lineBox').on('click', 'img', function() { // 事宜委托 ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage($(this)[0], 0, 0, canvas.width, canvas.height); // 绘制点击的图片到画布 }); // 底部操作栏和弹出框交互函数 function animatePanel(fName, fHeight, sName, sHeight) { $(fName).slideUp(300); $('.footer').animate({'bottom': fHeight}, 300); var timer = setTimeout(function() { $(sName).slideDown(500); $('.footer').animate({'bottom': 0, 'height': sHeight}, 500); timer = null; }, 0); } // 阻挡手机滑动时拖动页面 $('.wrapper').on('touchmove', function(event) { event.preventDefault(); });});

声明变量和初始化数据,详细用场解释都已经有备注,紧张剖析重点:

1、offCanvas用于改换背景图的画布,以是宽高跟涂鸦画布(canvas)同等,默认空缺;

html页面涂鸦canvas实现涂鸦后果色彩配景图橡皮擦汗青记载清屏等 Bootstrap
(图片来自网络侵删)

2、背景图画布(offCanvas)和涂鸦画布(canvas)的高度都须要减去footerHeight,避免被底部操作栏遮住;

3、imgSrc设置背景图片地址,也用于判断是否有背景图;

4、imgArray存储背景图和涂鸦图,用于循环添加到元素img;

5、rubberSize设置橡皮檫默认大小,该值跟html中input[type="range"]的value值同等,后面用于打算打消区域;

6、flag用于判断是涂鸦还是擦除(true为涂鸦,false为擦除);

7、strokeColor设置默认笔触的颜色,跟首页导航栏底部显示的笔墨对应;

8、imgSrc存储背景图片地址,用于绘制图片到画布。

剖析基本函数(重点):

1、caleLineWidth根据不同速率打算线的宽度函数,由于涂鸦过程速率快慢会影响线的宽度,为了更逼真,增加该函数,可根据实际情形对里面数据进行修正;

2、calcDistance打算两点之间的间隔函数,这个是用于caleLineWidth(间隔/韶光),一个大略的两点打算公式(两边长平方后相加再开方);

3、windowToCanvas坐标转换函数,屏幕坐标转换为在画布上面的坐标,不然画出来的线会有偏移;实在该实例是满屏(width: 100%),是可以不用转换,紧张是为了给不是满屏时候用的。

// 根据不同速率打算线的宽度函数function caleLineWidth(s, t, brushWidth) { var v = s / t; // 获取速率 // 声明最大最小速率和最大最小边界 var maxVelocity = 10, minVelocity = 0.1, maxLineWidth = Math.min(30, canvas.width / brushWidth), // 避免手机端线条太粗 minLineWidth = 1, resultLineWidth; // 用于返回的线宽度 if (v <= minVelocity) { resultLineWidth = maxLineWidth; } else if (v >= maxVelocity) { resultLineWidth = minLineWidth; } else { resultLineWidth = maxLineWidth - (v - minVelocity) / (maxVelocity - minVelocity) (maxLineWidth - minLineWidth); } if (lastLineWidth == -1) { // 开始时候 return resultLineWidth; } else { return resultLineWidth 2 / 3 + lastLineWidth 1 / 3; // lastLineWidth占得比重越大越平滑 }}// 打算两点之间的间隔函数function calcDistance(lastCoordinate, curCoordinate) { var distance = Math.sqrt(Math.pow(curCoordinate.x - lastCoordinate.x, 2) + Math.pow(curCoordinate.y - lastCoordinate.y, 2)); return distance;}// 坐标转换function windowToCanvas(x, y) { var bbox = canvas.getBoundingClientRect(); return { x: x - bbox.left, y: y - bbox.top };}

4、函数saveFile,由于canvas没办法直接保存为图片,以是下面的代码利用了仿照鼠标点击事宜进行保存,且能自定义文件名;

/ 仿照鼠标点击事宜进行保存 @param {String} data 要保存到本地的图片数据 @param {String} filename 文件名 /function saveFile(data, filename) { var saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); saveLink.href = data; saveLink.download = filename; // download只兼容chrome和firefox,须要兼容全部浏览器,只能用做事器保存 var event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); saveLink.dispatchEvent(event);}

5、添加阻挡拖动函数,详细代码如下图;由于H5在手机滑动页面时候,页面会被拖动,导致跟手指涂鸦冲突,体验不好,以是须要增加该函数,阻挡页面被拖动;

// 阻挡手机滑动时拖动页面$('.wrapper').on('touchmove', function(event) { event.preventDefault();});

6、添加底部按钮和弹出列表的交互效果(代码如下图),为了提高交互体验,利用了animate、setTimeout和slideUp\Down,并写成一个函数,便于多处调用,代码紧张意思便是先向下隐蔽设置的栏目然后再向上显示须要的栏目;

// 底部操作栏和弹出框交互函数function animatePanel(fName, fHeight, sName, sHeight) { $(fName).slideUp(300); $('.footer').animate({ 'bottom': fHeight }, 300); var timer = setTimeout(function() { $(sName).slideDown(500); $('.footer').animate({ 'bottom': 0, 'height': sHeight }, 500); timer = null; }, 0);}

事理过程剖析:

1、涂鸦实现过程,大略说便是记录触摸时的坐标和滑动时的坐标,然后利用这两个坐标进行画线,从而实现涂鸦效果,详细剖析如下:

第一步,触摸时候记录触摸时坐标并转换为(windowToCanvas函数)canvas的坐标(lastCoordinate),并且保存当前的韶光戳(lastTimestamp);

第二步,滑动时记录滑动到的坐标并转换为canvas坐标(curCoordinate),并且保存当前的韶光戳(curTimestamp);再把lastCoordinate作为开始坐标,curCoordinate作为结束坐标进行画线(drawLine函数),并把curCoordinate赋值给lastCoordinate,curTimestamp赋值给lastTimestamp;以是滑动时候,都是起始点--第一点--第二点--...--末了结束的点,这样两点两点画线,从而产生滑动过程中的一条线,比较符合实际情形,直接打算起始点--结束点的线是不符合实际情形;末了为了符合慢的时候笔触比较大,快的时候笔触比较小,利用了函数curLineWidth进行即时打算,里面的数值可以自己根据实际情形调节。

2、清屏功能比较大略,事理便是点击清屏按钮(clearButton)时候,打消(clearRect)掉涂鸦画布(ctx)和背景图画布(offCtx)的内容;

3、保存功能实现过程,大略说便是把涂鸦画布和背景图画布的内容合成到另一个画布,然后把该画布内容保存成图片到本地,详细剖析如下(点击保存按钮(saveButton)时候):

首先把涂鸦画布和背景图画布的内容转换成图片存储到数组imgArray;

然后把imgArray传值给函数compositeGraph,该函数首先把数组imgArray内容循环转化成html中元素img的内容(该内容是隐蔽的),然后循环该元素img轮流绘画到离屏画布上面,末了把该离屏画布转化成图片并利用函数saveFile保存成图片到本地。

把稳:

图片须要利用onload(val.onload),不然图片未准备就实行,会显示空缺;

转换离屏画布为图片和实行函数saveFile须要利用定时器,不然也会导致保存空缺图片。

4、橡皮檫功能实现过程,大略说便是获取滑动过程中的坐标点,然后利用clearRect打消坐标点周围的涂鸦内容;详细剖析如下(赤色框部分):

跟基本功能代码加了flag区分,else部分为擦掉功能实当代码;

利用了画布打消功能ctx.clearRect对滑动坐标点周围矩形进行打消,由于坐标点是圆心,以是打消的起始坐标(curCoordinate)须要滑动坐标点减去半径(rubberSize/2);

直接用矩形擦除,过程会有锯齿,为了达到更好效果,特意在上面加了圆形(ctx.arc)剪切(ctx.clip),使擦除效果比较光滑。

5、历史记录功能实现过程,大略说便是手指离开屏幕时候,把当前画布内容转化为图片地址,然后新增元素img(src为该图片地址)插入历史记录列表;详细剖析如下(手指离开屏幕时候(touchend)):

把当前画布内容转化为图片地址,然后新增元素img(src为该图片地址)插入历史记录列表;

当操作次数多了之后,历史记录上的图片会一贯增加,为了让超过一屛的图片能正常滑动显示,以是须要实时打算全部图片的宽度(+间隔)的值boxWidth,然后赋值lineBox。

6、实现可改换笔触颜色和大小的功能,详细代码如下图:

查看代码可看出滑动过程中会调用函数drawLine,且函数有参数curLineWidth(笔触大小)和strokeColor(笔触颜色),以是只须要选择颜色和大小的时候,更换这两个参数的值就可以实现功能,选择对应的值便是(sizeWidth(用于打算)和strokeColor);

为了便于用户知道选择了什么颜色和那个大小,也实现了选择回填;

末了实现了点击后关闭弹出框显示操作栏。

7、实现可改换背景图功能,详细代码如下图:

实现事理便是利用点击背景图列表的图片获取src,然后利用canvas的drawImage功能,把图片绘画到offCtx(该画布是处于涂鸦画布的下面),从而实现改换背景图功能;

Tips:背景图列表的图片可改为缩略图加上描述名称有利于体验;绘画新背景之前一定要打消画布(clearRect),不然性能会有问题。

把稳事变

1、由于该实例是用于手机端,以是利用触摸事宜,如果要用于PC端,改为点击事宜即可,但要把稳增加判断点击后才能涂鸦,不然会导致未点击就能涂鸦;

2、toDataURL有跨域问题,以是须要发布到做事器上,才能正常利用;