Reputation: 160
I have a typescript code base in which I have created a working Sudoku board, just dealing with the DOM directly and specifically drawing on an HTML Canvas element using it's API.
I want to expand my project to a full site now and I am trying to merge what I already have into a Vue3 project. I am using the Composition API with typescript. I've started to make progress but have halted on a board refresh problem.
Here is the code for the start of my Board Component:
<template>
<button @click="grow">Grow</button>
<br><br>
<div class="board">
<canvas ref='myCanvas' :width="size.w" :height="size.h" tabindex='0'
style="border:1px solid #000000;"
></canvas>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref, reactive } from 'vue'
import { CanvasManager } from '@/managers/canvasmanager'
export default defineComponent({
setup() {
let myCanvas = ref(null)
let myContext = ref(null)
let manager = ref(null)
let size = reactive({
w: 200,
h: 200
})
function grow() {
size.w += 10
size.h += 10
manager.drawGrid(4, 4, 1, 'black')
}
onMounted(() => {
myContext = myCanvas.value.getContext('2d')
manager = new CanvasManager(myContext, size.w, size.h)
manager.drawGrid(4, 4, 1, 'black')
})
return {
myCanvas,
size,
grow
}
}
})
</script>
The CanvasManager
that is imported here is a utility class I wrote that holds various Canvas API drawing helpers.
This code works when first loading. The manager.drawGrid(4, 4, 1, 'black')
call inside onMounted
works and draws a 4 by 4 grid on the canvas.
The grow method also increases the size of the canvas and the border can be seen growing, however, the call to manager.drawGrid(4, 4, 1, 'black')
inside the grow method has no effect. The grid inside the border vanishes and is not redrawn.
I've only been using Vue (any version) for a couple of weeks and I'm not sure how to go about debugging at the moment.
I get no errors in the console. I've added console logging to the drawGrid method in the CanvasManager and can see that it is definitely being called.
Any help would be greatly appreciated.
Cheers
Upvotes: 3
Views: 8755
Reputation: 63119
Vue renders the component again whenever there is a data change, but that doesn't mean re-mounting, and your canvas is only prepared to draw onMounted
. So when the component re-renders the node, the previous drawing is lost. One quick way to fix this would be to draw onUpdated
as well:
function draw() {
myContext = myCanvas.value.getContext('2d')
manager = new CanvasManager(myContext, size.w, size.h)
manager.drawGrid(4, 4, 1, 'black')
}
onMounted(draw);
onUpdated(draw);
But I would improve the code further by not creating a new CanvasManager
object on every render, that can be done just once.
function draw() {
manager.drawGrid(4, 4, 1, 'black')
}
onMounted(() => {
myContext = myCanvas.value.getContext('2d')
manager = new CanvasManager(myContext, size.w, size.h)
draw();
});
onUpdated(() => {
draw();
});
Here is a demo with some other minor structural improvements
Upvotes: 8