optimize cursor moving with canvas rendering.

This commit is contained in:
Miroslav Šedivý 2021-02-11 21:17:47 +01:00
parent 6cfe39e6c5
commit 873e9250cc

View File

@ -1,5 +1,5 @@
<template> <template>
<div <canvas
ref="overlay" ref="overlay"
class="neko-overlay" class="neko-overlay"
:class="isControling ? 'neko-active' : ''" :class="isControling ? 'neko-active' : ''"
@ -17,18 +17,7 @@
@dragleave.stop.prevent="onDragLeave" @dragleave.stop.prevent="onDragLeave"
@dragover.stop.prevent="onDragOver" @dragover.stop.prevent="onDragOver"
@drop.stop.prevent="onDrop" @drop.stop.prevent="onDrop"
> />
<img
v-if="cursorPos && !isControling"
:src="control.cursor.image.uri"
class="cursor"
:style="{
top: (cursorPos.y / screenHeight) * 100 + '%',
left: (cursorPos.x / screenWidth) * 100 + '%',
transform: 'translate(' + control.cursor.image.x * -1 + 'px, ' + control.cursor.image.y * -1 + 'px)',
}"
/>
</div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -72,7 +61,8 @@
name: 'neko-overlay', name: 'neko-overlay',
}) })
export default class extends Vue { export default class extends Vue {
@Ref('overlay') readonly _overlay!: HTMLElement @Ref('overlay') readonly _overlay!: HTMLCanvasElement
private _ctx: any = null
private keyboard = GuacamoleKeyboard() private keyboard = GuacamoleKeyboard()
private focused = false private focused = false
@ -109,6 +99,13 @@
} }
mounted() { mounted() {
this._ctx = this._overlay.getContext('2d')
// synchronize intrinsic with extrinsic dimensions
const { width, height } = this._overlay.getBoundingClientRect()
this._overlay.width = width
this._overlay.height = height
// Initialize Guacamole Keyboard // Initialize Guacamole Keyboard
this.keyboard.onkeydown = (key: number) => { this.keyboard.onkeydown = (key: number) => {
if (!this.focused) { if (!this.focused) {
@ -149,10 +146,11 @@
} }
} }
private mousepos: { x: number; y: number } = { x: 0, y: 0 }
setMousePos(e: MouseEvent) { setMousePos(e: MouseEvent) {
const pos = this.getMousePos(e.clientX, e.clientY) const pos = this.getMousePos(e.clientX, e.clientY)
this.webrtc.send('mousemove', pos) this.webrtc.send('mousemove', pos)
Vue.set(this, 'cursorPos', pos) Vue.set(this, 'mousepos', pos)
} }
onWheel(e: WheelEvent) { onWheel(e: WheelEvent) {
@ -257,6 +255,34 @@
} }
} }
private cursorElem: HTMLImageElement = new Image()
@Watch('control.cursor.image')
onCursorImageChange({ uri }: { uri: string }) {
this.cursorElem.src = uri
}
@Watch('control.cursor.position')
onCursorPositionChange({ x, y }: { x: number; y: number }) {
if (this.isControling || this.control.cursor.image == null) return
// synchronize intrinsic with extrinsic dimensions
const { width, height } = this._overlay.getBoundingClientRect()
if (this._overlay.width != width || this._overlay.height != height) {
this._overlay.width = width
this._overlay.height = height
}
// redraw cursor
this._ctx.clearRect(0, 0, width, height)
this._ctx.drawImage(
this.cursorElem,
(x / this.screenWidth) * width - this.control.cursor.image.x,
(y / this.screenHeight) * height - this.control.cursor.image.y,
this.control.cursor.image.width,
this.control.cursor.image.height,
)
}
private reqMouseDown: any | null = null private reqMouseDown: any | null = null
private reqMouseUp: any | null = null private reqMouseUp: any | null = null
@Watch('isControling') @Watch('isControling')
@ -270,6 +296,13 @@
this.webrtc.send('mouseup', { key: this.reqMouseUp.button + 1 }) this.webrtc.send('mouseup', { key: this.reqMouseUp.button + 1 })
} }
if (isControling) {
const { width, height } = this._overlay
this._ctx.clearRect(0, 0, width, height)
} else {
this.onCursorPositionChange(this.mousepos)
}
this.reqMouseDown = null this.reqMouseDown = null
this.reqMouseUp = null this.reqMouseUp = null
} }
@ -291,11 +324,5 @@
this.$emit('implicit-control-release') this.$emit('implicit-control-release')
} }
} }
private cursorPos: { x: number; y: number } | null = null
@Watch('control.cursor.position')
onCursorPositionChange({ x, y }: { x: number; y: number }) {
this.cursorPos = { x, y }
}
} }
</script> </script>