Recently, I want to develop a sketch paper function, so I learned the simple drawing board function of Canvas. However, we know that MouseEvent can be used to monitor our mouse click operations on PC, and TouchEvent can be used to monitor our finger touch operations on mobile. So we have to write two sets of logic if we want to make a drawing board with both mouse clicks and finger touches. But don’t forget, there is also a PointerEventer, it can listen for mouse, finger touch and touch pen, support multi-touch, it has a special parameter, pressure sensor, on the pressure sensor screen can get the pressure sensor pen, as long as according to the pressure sensor, we can control the thickness of the stroke
1. Events corresponding to PointerEvent, MouseEvent, and TouchEvent
PointerEvent | MouseEvent | TouchEvent |
---|---|---|
poninterdown | mousedown | touchstart |
pointermove | mousemove | touchmove |
pointerup | mouseup | touchend |
pointerleave | mouseleave | – |
pointercancel | – | touchcancel |
2. Make a sketchpad
1) Shared parts
Write the common sketchpad part of the code first, and then just write the different event listener part of the code
<style>
body {
padding: 0;
margin: 0;
height: 100vh;
overflow: hidden;
}
.canvas-block {
position: relative;
width: 100%;
height: 200px;
}
#canvas {
position: absolute;
top: 0;
left: 0;
}
#canvas {
z-index: 1;
}
</style>
<div class="canvas-block">
<canvas id="canvas" width="400" height="200"></canvas>
</div>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
let width = canvas.width
let height = canvas.height
if (window.devicePixelRatio) {
canvas.style.width = width + 'px'
canvas.style.height = height + 'px'
canvas.height = height * window.devicePixelRatio
canvas.width = width * window.devicePixelRatio
ctx.scale(window.devicePixelRatio, window.devicePixelRatio)
}
canvas.getContext('2d').imageSmoothingEnabled = true
let lineWidth = 3
let lineColor = '#fff'
let painting = false
</script>
Copy the code
2) Use MouseEvent to listen for events
Codepen. IO/klren0312 / p…
/ / put pen to paper
canvas.onmousedown = e= > {
painting = true
const event = e || window.event
ctx.lineCap = 'round'
ctx.lineJoin = 'round'
const x = event.offsetX
const y = event.offsetY
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineWidth = lineWidth
ctx.strokeStyle = lineColor
}
/ / move
canvas.onmousemove = e= > {
if(! painting) {return
}
const event = e || window.event
const x = event.offsetX
const y = event.offsetY
ctx.lineTo(x, y)
ctx.stroke()
}
/ / pen up
canvas.onmouseup = () = > {
if(! painting) {return false
}
painting = false
ctx.closePath()
}
// Leave the artboard
canvas.onmouseleave = () = > {
if(! painting) {return false
}
painting = false
ctx.closePath()
}
Copy the code
The effect
3) use the TouchEvent
Codepen. IO/klren0312 / p…
// Press your finger down
canvas.ontouchstart = e= > {
console.log(e.touches)
painting = true
const event = e.touches[0]
ctx.lineCap = 'round'
ctx.lineJoin = 'round'
const x = event.pageX
const y = event.pageY
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineWidth = lineWidth
ctx.strokeStyle = lineColor
}
// Move your finger
canvas.ontouchmove = e= > {
if(! painting) {return
}
const event = e.touches[0]
const x = event.pageX
const y = event.pageY
ctx.lineTo(x, y)
ctx.stroke()
}
// Raise your finger
canvas.ontouchend = () = > {
if(! painting) {return false
}
painting = false
ctx.closePath()
}
// Finger out of the area
ontouchcancel = () = > {
if(! painting) {return false
}
painting = false
ctx.closePath()
}
Copy the code
The effect
3) use PointerEvent
This is the focus of this time, so a new project to write
Source address: klren0312 / drawboard: drawboard with pressure (can use pen pressure sketchpad) (github.com) the sample address: klren0312. Making. IO/drawboard /
Note:
- On the mobile terminal, events such as page scrolling and browser zooming will occur when the page is touched. At this time, you need to set the canvas
touch-action: none;
Style to set that no action is taken when a touch event occurs on an element - Because we need to live according to the pressure to set the contrast, so in every move as a start and end of the path, so of course we need to record each move eventually coordinates, when pointermove events trigger again, moving coordinates to the coordinates of the end of the last, it ensures the continuity of the strokes
/** * @param {PointerEvent} e */ function startDraw(e: PointerEvent) { painting = true pointerId = e.pointerId ctx.lineCap = 'round' ctx.lineJoin = 'round' doDraw(e, */ function moveDraw(e: PointerEvent) {if (! painting && e.pointerId ! == pointerId) { return } else { doDraw(e) } } function cancelDraw(e: PointerEvent) { console.log('cancel') pointerId = -1 if (! painting) { return false } painting = false historyList.push(ctx.getImageData(0, 0, canvas.width, Canvas.height)) ctx.closepath ()} /** * draw * @param {PointerEvent} e event * @param {Boolean} isStart is the starting point */ function doDraw(e, isStart = false) { if (isPen.value && e.pointerType ! == 'pen') { return } const event: PointerEvent = e || window.event const x: number = event.offsetX const y: number = event.offsetY ctx.lineWidth = getLineWidth(event) ctx.strokeStyle = lineColor.value ctx.beginPath() if (! isStart) { ctx.moveTo(startXY.x, startXY.y) ctx.lineTo(x, y) } else { ctx.moveTo(x, y) } ctx.closePath() ctx.stroke() startXY = { x: x, y: Y}} /** * @description * @param {PointerEvent} e * @return {number} line width */ function getLineWidth(e: PointerEvent): number { switch (e.pointerType) { case 'touch': { if (e.width < 10 && e.height < 10) { return (e.width + e.height) * 2 + 10; } else { return (e.width + e.height - 40) / 2; } } case 'pen': return e.pressure * 8; default: return (e.pressure) ? e.pressure * 8 : 4; }}Copy the code
As you can see in the code above, we save an image to the historyList array at the end of each full stroke.
historyList.push(ctx.getImageData(0.0, canvas.width, canvas.height))
Copy the code
This is mainly to achieve the backback operation of strokes. When clicking the backback button, we can take out the picture saved in the previous step and draw it to canvas to achieve this function
The function of clearing the screen is relatively simple. You can use Canvas clearRect to clear the canvas
ctx.clearRect(0.0, canvas.width, canvas.height)
Copy the code
The effect
The resources
Developer.mozilla.org/zh-CN/docs/… Developer.mozilla.org/zh-CN/docs/… Developer.mozilla.org/zh-CN/docs/… Developer.mozilla.org/zh-CN/docs/… Useful. Javascript. The info/pointer – eve… Github.com/klren0312/d…