Canvas cursor draw - do not use save and restore. (#9)

This commit is contained in:
Miroslav Šedivý 2022-08-25 00:14:47 +02:00 committed by GitHub
parent bada3d1243
commit 9a77f6adea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 28 deletions

View File

@ -63,8 +63,7 @@
// synchronize intrinsic with extrinsic dimensions // synchronize intrinsic with extrinsic dimensions
const { width, height } = this._overlay.getBoundingClientRect() const { width, height } = this._overlay.getBoundingClientRect()
this._overlay.width = width * CANVAS_SCALE this.canvasResize({ width, height })
this._overlay.height = height * CANVAS_SCALE
// store last drawing points // store last drawing points
this._last_points = {} this._last_points = {}
@ -74,9 +73,14 @@
@Watch('canvasSize') @Watch('canvasSize')
onCanvasSizeChange({ width, height }: Dimension) { onCanvasSizeChange({ width, height }: Dimension) {
this.canvasResize({ width, height })
this.canvasUpdateCursors()
}
canvasResize({ width, height }: Dimension) {
this._overlay.width = width * CANVAS_SCALE this._overlay.width = width * CANVAS_SCALE
this._overlay.height = height * CANVAS_SCALE this._overlay.height = height * CANVAS_SCALE
this.canvasUpdateCursors() this._ctx.setTransform(CANVAS_SCALE, 0, 0, CANVAS_SCALE, 0, 0)
} }
// start as undefined to prevent jumping // start as undefined to prevent jumping
@ -107,9 +111,8 @@
} }
canvasDrawPoints(percent: number = 1) { canvasDrawPoints(percent: number = 1) {
// clear & scale canvas // clear canvas
this.canvasClear() this.canvasClear()
this._ctx.setTransform(CANVAS_SCALE, 0, 0, CANVAS_SCALE, 0, 0)
// draw current position // draw current position
for (const p of this._points) { for (const p of this._points) {
@ -204,6 +207,9 @@
x = Math.round((x / this.screenSize.width) * width) x = Math.round((x / this.screenSize.width) * width)
y = Math.round((y / this.screenSize.height) * height) y = Math.round((y / this.screenSize.height) * height)
// reset transformation, X and Y will be 0 again
this._ctx.setTransform(CANVAS_SCALE, 0, 0, CANVAS_SCALE, 0, 0)
// use custom draw function, if available // use custom draw function, if available
if (this.cursorDraw) { if (this.cursorDraw) {
this.cursorDraw(this._ctx, x, y, id) this.cursorDraw(this._ctx, x, y, id)
@ -214,7 +220,6 @@
const cursorTag = this.sessions[id]?.profile.name || '' const cursorTag = this.sessions[id]?.profile.name || ''
// draw inactive cursor tag // draw inactive cursor tag
this._ctx.save()
this._ctx.font = '14px Arial, sans-serif' this._ctx.font = '14px Arial, sans-serif'
this._ctx.textBaseline = 'top' this._ctx.textBaseline = 'top'
this._ctx.shadowColor = 'black' this._ctx.shadowColor = 'black'
@ -225,7 +230,6 @@
this._ctx.shadowBlur = 0 this._ctx.shadowBlur = 0
this._ctx.fillStyle = 'white' this._ctx.fillStyle = 'white'
this._ctx.fillText(cursorTag, x, y) this._ctx.fillText(cursorTag, x, y)
this._ctx.restore()
} }
canvasClear() { canvasClear() {

View File

@ -124,8 +124,7 @@
// synchronize intrinsic with extrinsic dimensions // synchronize intrinsic with extrinsic dimensions
const { width, height } = this._overlay.getBoundingClientRect() const { width, height } = this._overlay.getBoundingClientRect()
this._overlay.width = width * CANVAS_SCALE this.canvasResize({ width, height })
this._overlay.height = height * CANVAS_SCALE
let ctrlKey = 0 let ctrlKey = 0
let noKeyUp = {} as Record<number, boolean> let noKeyUp = {} as Record<number, boolean>
@ -462,8 +461,7 @@
@Watch('canvasSize') @Watch('canvasSize')
onCanvasSizeChange({ width, height }: Dimension) { onCanvasSizeChange({ width, height }: Dimension) {
this._overlay.width = width * CANVAS_SCALE this.canvasResize({ width, height })
this._overlay.height = height * CANVAS_SCALE
this.canvasRequestRedraw() this.canvasRequestRedraw()
} }
@ -482,6 +480,12 @@
} }
} }
canvasResize({ width, height }: Dimension) {
this._overlay.width = width * CANVAS_SCALE
this._overlay.height = height * CANVAS_SCALE
this._ctx.setTransform(CANVAS_SCALE, 0, 0, CANVAS_SCALE, 0, 0)
}
@Watch('hostId') @Watch('hostId')
@Watch('cursorDraw') @Watch('cursorDraw')
canvasRequestRedraw() { canvasRequestRedraw() {
@ -512,6 +516,8 @@
// get intrinsic dimensions // get intrinsic dimensions
let { width, height } = this.canvasSize let { width, height } = this.canvasSize
// reset transformation, X and Y will be 0 again
this._ctx.setTransform(CANVAS_SCALE, 0, 0, CANVAS_SCALE, 0, 0) this._ctx.setTransform(CANVAS_SCALE, 0, 0, CANVAS_SCALE, 0, 0)
// get cursor position // get cursor position
@ -536,10 +542,9 @@
// draw cursor tag // draw cursor tag
const cursorTag = this.sessions[this.hostId]?.profile.name || '' const cursorTag = this.sessions[this.hostId]?.profile.name || ''
if (cursorTag) { if (cursorTag) {
x += this.cursorImage.width const x = this.cursorImage.width
y += this.cursorImage.height const y = this.cursorImage.height
this._ctx.save()
this._ctx.font = '14px Arial, sans-serif' this._ctx.font = '14px Arial, sans-serif'
this._ctx.textBaseline = 'top' this._ctx.textBaseline = 'top'
this._ctx.shadowColor = 'black' this._ctx.shadowColor = 'black'
@ -550,7 +555,6 @@
this._ctx.shadowBlur = 0 this._ctx.shadowBlur = 0
this._ctx.fillStyle = 'white' this._ctx.fillStyle = 'white'
this._ctx.fillText(cursorTag, x, y) this._ctx.fillText(cursorTag, x, y)
this._ctx.restore()
} }
} }

View File

@ -514,7 +514,6 @@
y -= 4 y -= 4
// draw arrow path // draw arrow path
ctx.save()
const arrowPath = new Path2D('M5 5L19 12.5L12.3286 14.465L8.29412 20L5 5Z') const arrowPath = new Path2D('M5 5L19 12.5L12.3286 14.465L8.29412 20L5 5Z')
ctx.globalAlpha = 0.5 ctx.globalAlpha = 0.5
ctx.translate(x, y) ctx.translate(x, y)
@ -527,15 +526,12 @@
ctx.lineJoin = 'round' ctx.lineJoin = 'round'
ctx.strokeStyle = colorDark ctx.strokeStyle = colorDark
ctx.stroke(arrowPath) ctx.stroke(arrowPath)
ctx.restore()
ctx.save()
// draw cursor tag // draw cursor tag
if (cursorTag) { if (cursorTag) {
x += 20 // box margin x const x = 20 // box margin x
y += 20 // box margin y const y = 20 // box margin y
ctx.save()
ctx.globalAlpha = 0.5 ctx.globalAlpha = 0.5
ctx.font = '10px Arial, sans-serif' ctx.font = '10px Arial, sans-serif'
ctx.textBaseline = 'top' ctx.textBaseline = 'top'
@ -547,7 +543,6 @@
ctx.shadowBlur = 0 ctx.shadowBlur = 0
ctx.fillStyle = 'white' ctx.fillStyle = 'white'
ctx.fillText(cursorTag, x, y) ctx.fillText(cursorTag, x, y)
ctx.restore()
} }
}, },
) )
@ -576,7 +571,6 @@
y -= 4 y -= 4
// draw arrow path // draw arrow path
ctx.save()
const arrowPath = new Path2D('M5 5L26 16.5L15.9929 19.513L9.94118 28L5 5Z') const arrowPath = new Path2D('M5 5L26 16.5L15.9929 19.513L9.94118 28L5 5Z')
ctx.translate(x, y) ctx.translate(x, y)
ctx.fillStyle = colorLight ctx.fillStyle = colorLight
@ -588,7 +582,6 @@
ctx.lineJoin = 'round' ctx.lineJoin = 'round'
ctx.strokeStyle = colorDark ctx.strokeStyle = colorDark
ctx.stroke(arrowPath) ctx.stroke(arrowPath)
ctx.restore()
// draw cursor tag // draw cursor tag
if (cursorTag) { if (cursorTag) {
@ -596,15 +589,14 @@
const boxPaddingX = 9 const boxPaddingX = 9
const boxPaddingY = 6 const boxPaddingY = 6
x += 22 // box margin x const x = 22 // box margin x
y += 28 // box margin y const y = 28 // box margin y
// prepare tag text // prepare tag text
ctx.font = '500 ' + fontSize + 'px Roboto, sans-serif' ctx.font = '500 ' + fontSize + 'px Roboto, sans-serif'
ctx.textBaseline = 'ideographic' ctx.textBaseline = 'ideographic'
// create tag container // create tag container
ctx.save()
const txtWidth = ctx.measureText(cursorTag).width const txtWidth = ctx.measureText(cursorTag).width
const w = txtWidth + boxPaddingX * 2 const w = txtWidth + boxPaddingX * 2
const h = fontSize + boxPaddingY * 2 const h = fontSize + boxPaddingY * 2
@ -618,7 +610,6 @@
ctx.closePath() ctx.closePath()
ctx.fillStyle = colorDark ctx.fillStyle = colorDark
ctx.fill() ctx.fill()
ctx.restore()
// fill in tag text // fill in tag text
ctx.fillStyle = fontColor ctx.fillStyle = fontColor