移动端touch事件有以下几个属性
- ClientX Y 相对于视口的坐标
- pageX Y 相对于页面左上角原点的坐标
- screenX Y 相对于屏幕的坐标标
- movementX Y 相对于上一次坐标的坐标
然而就是没有offset X Y
实现方法:
- 获得触摸点的pageX Y
- 通过offsetTop left计算元素左上角的顶点位置
- 计算相对坐标
代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas画笔</title>
<style>
html,
body {
width: 100%;
height: 100%;
}
* {
margin: 0;
padding: 0;
}
#canvas {
position:relative;
top: 10%;
left: 5%;
width: 90%;
height: 80%;
}
#canvas canvas {
display: block;
}
#clearCanvas,
#saveCanvas {
position: absolute;
bottom: 0;
z-index: 1;
width: 50%;
height: 60px;
border: 1px solid #dedede;
line-height: 60px;
text-align: center;
}
#clearCanvas {
left: 0;
}
#saveCanvas {
right: 0;
}
.errorCanvas {
width: 100%;
height: 100%;
text-align: center;
transform: translateY(40%);
}
</style>
<script>
window.onload = function () {
new lineCanvas({
el: document.querySelector('#canvas'),
clearEl: document.querySelector('#clearCanvas'),
saveEl: document.querySelector('#saveCanvas'),
// lineWidth: 1, // 线条粗细
color: '#0000ff', // 线条颜色
lineShadowColor: '#0000ff', // 线条阴影颜色
// background: '#fff'
});
}
function lineCanvas(obj) {
this.lineWidth = 5;
this.color = '#000'; // 线条颜色
this.lineShadowColor = '#000'; //线条阴影颜色
this.shadowBlur = 1; //线条阴影大小
this.background = '#fff';
// 获取元素相对于body的offsetTop 和 offsetLeft
this.offsetLeft_body = getOffsetTopByBody(obj.el)[0];
this.offsetTop_body = getOffsetTopByBody(obj.el)[1];
for (var i in obj) {
this[i] = obj[i];
};
this.canvas = document.createElement('canvas');
if (!(this.canvas.getContext && this.canvas.getContext('2d'))) {
this.section = document.createElement('section');
this.section.className = 'errorCanvas';
this.section.innerHTML = '对不起,当前浏览器暂不支持此功能!'
this.el.prepend(this.section);
return
}
this.canvas.width = this.el.clientWidth;
this.canvas.height = this.el.clientHeight;
this.el.prepend(this.canvas);
this.cxt = this.canvas.getContext('2d');
this.cxt.fillStyle = this.background;
this.cxt.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.cxt.strokeStyle = this.color;
this.cxt.lineWidth = this.lineWidth;
this.cxt.lineCap = 'round'; // 线条末端添加圆形线帽,减少线条的生硬感
this.cxt.lineJoin = 'round'; // 线条交汇时为原型边角
// 利用阴影,消除锯齿
this.cxt.shadowBlur = this.shadowBlur;
this.cxt.shadowColor = this.lineShadowColor;
// 开始绘制
this.canvas.addEventListener('touchstart', function (e) {
this.cxt.beginPath();
this.cxt.moveTo(e.changedTouches[0].pageX-this.offsetLeft_body, e.changedTouches[0].pageY-this.offsetTop_body);
}.bind(this), false);
// 绘制中
this.canvas.addEventListener('touchmove', function (e) {
this.cxt.lineTo(e.changedTouches[0].pageX-this.offsetLeft_body, e.changedTouches[0].pageY-this.offsetTop_body);
this.cxt.stroke();
}.bind(this), false);
// 结束绘制
this.canvas.addEventListener('touchend', function (e) {
this.cxt.closePath();
}.bind(this), false);
// 清除画布
this.clearEl.addEventListener('click', function () {
this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
}.bind(this), false);
// 保存图片
this.saveEl.addEventListener('click', function () {
var imgBase64 = this.canvas.toDataURL();
var imgPng = this.canvas.toDataURL('image/png');
var imgJpg = this.canvas.toDataURL('image/jpeg', 0.8);
console.log(imgPng);
}.bind(this), false);
// 获取元素相对于body的offsetTop 和 offsetLeft
function getOffsetTopByBody (el) {
let offsetTop = 0
let offsetLeft = 0
while (el && el.tagName !== 'BODY') {
offsetTop += el.offsetTop
offsetLeft+= el.offsetLeft
el = el.offsetParent
}
return [offsetLeft,offsetTop]
}
}
</script>
</head>
<body>
<div id="canvas">
<p id="clearCanvas">清除</p>
<p id="saveCanvas">保存</p>
</div>
</body>
</html>
实现效果:

