Solving the issue of refreshing HTML Canvas drawings in Vue3 using the Composition API

In my typescript code base, I have successfully created a Sudoku board by directly manipulating the DOM and utilizing an HTML Canvas element with its API.

Now, I am looking to elevate my project to a full website and integrate what I have into a Vue3 project. I am employing the Composition API alongside typescript. Although I have made progress, I am currently stuck on a board refresh issue.

Below is the initial code snippet for 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 imported CanvasManager class is a utility that contains various drawing helpers using the Canvas API.

The current code functions correctly upon initial load. The call to

manager.drawGrid(4, 4, 1, 'black')
within onMounted successfully draws a 4x4 grid on the canvas.

However, when the grow method is called to increase the canvas size, although the border expands visibly, the subsequent call to

manager.drawGrid(4, 4, 1, 'black')
inside the grow method does not redraw the grid inside the border.

I am relatively new to using Vue (any version) and would appreciate any guidance on how to tackle this debugging challenge.

No errors appear in the console. I have added console logs to the drawGrid method in CanvasManager and confirmed that it is indeed being triggered.

Any assistance you can provide would be greatly valued.

Thank you!

Answer №1

Whenever there is a change in data, Vue will render the component again without re-mounting it. However, if your canvas is only prepared to draw onMounted, the previous drawing may be lost when the node is re-rendered. One way to address this issue is by also adding onUpdated:

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);

To further improve the code, avoid creating a new CanvasManager object on every render and do it 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();
});

Check out this demo for some other minor structural improvements

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Compiling TypeScript: Using the `as` operator to convert and then destructure an array results in a compilation error, requiring an

I am currently utilizing TypeScript version 2.9.2. There is a static method in a third-party library called URI.js, which is declared as follows: joinPaths(...paths: (string | URI)[]): URI; I have a variable named urlPaths that is defined as urlPaths: s ...

Common Errors in Angular 2 due to TSLint

I am encountering multiple errors in my code. I am using Angular 2 with TSLint: constructor(http: Http) { this.http = http; --> let currentUser = JSON.parse(localStorage.getItem("currentUser")); this.token = currentUser && currentUser.t ...

I am curious about the types of props for the methods within the 'components' object in react-markdown

Having some trouble using 'react-markdown' in NextJs 13 with typescript. TypeScript is showing errors related to the props of the 'code' method, and after searching online, I found a solution that involves importing 'CodeProps&apos ...

Exploring the process of incorporating types for a Vue plugin

I am currently trying to integrate a self-made plugin for Vue with TypeScript. However, when I try to use the method from my vue prototype, I encounter an issue where my method $auth is not recognized on type 'myComponent'. I have also included ...

Tips for resolving TypeScript issues with Vuex mapGetters

When utilizing mapGetters, TypeScript lacks insight into the getters linked to the Vue component, leading to error messages. For instance: import Vue from 'vue'; import { mapActions, mapGetters } from 'vuex'; export default Vue.extend ...

Vuex 3: The State Remains Unknown

software versions: "vue": "2.4.2", "vue-router": "2.7.0", "vuex": "3.0.1" I'm working on simulating a basic login feature with two input fields that will eventually utilize JWT for authenticated logins. However, I'm encountering an issue w ...

Encountering a getStaticProps error while using Typescript with Next.js

I encountered an issue with the following code snippet: export const getStaticProps: GetStaticProps<HomeProps> = async () => { const firstCategory = 0; const { data }: AxiosResponse<MenuItem[]> = await axios.post( ...

What advantages does using an RxJS Subject have over handling multiple event listeners individually in terms of speed

After investigating a page's slow performance, I identified an angular directive as the root cause. The culprit was a piece of code that registered event listeners on the window keydown event multiple times: @HostListener('window:keydown', ...

The Calendly widget fails to function properly after a page refresh when in live mode

Initially, the calendly widget functions properly. However, upon refreshing the page in a live website environment, it ceases to work. Interestingly, this issue doesn't occur during local development. I've also observed that when navigating to t ...

'The signatures of each of these values are not compatible with one another.' This error occurs when using find() on a value that has two different array types

Here's the code snippet I'm attempting to run within a TypeScript editor: type ABC = { title: string } type DEF = { name: string } type XYZ = { desc: ABC[] | DEF[] } const container: XYZ = { desc: [{title: & ...

The Vue.js app is functioning properly in the development environment, but it is encountering issues when trying to load the template in the production environment with Rails 5.2.0 and Webpacker

I am currently utilizing Rails 5.2.0 in conjunction with the Webpacker gem for deploying a Vue application. Within the show.html.erb file, the code is very straightforward: <div data-behavior="vue-app"><MyComponent></MyComponent></di ...

What are the steps to defining a static constant within a TypeScript class?

What is the best way to define a TypeScript static constant within a class so that it can be accessed without initializing the class instance? Below is an example of my class structure: export class CallTree{ public static readonly active = 1; .. ...

Changing the name of a tab within a p-tabview

Setting up a p-tabview with tabs containing specific content involves the following code: <p-tabView class="tabmain" > <ng-container *ngFor="let tab of tabs"> <p-tabPanel [header]="tab.header" > ...

Is it possible for @load to trigger once the component has been dismounted?

Hey there, I'm currently working on a Vue 3 app and I've come across some unusual behavior that's leaving me puzzled. I have a question in mind: Can the @load event trigger after the component has been unmounted? If so, what steps can be ...

Eliminate duplicated partial objects within a nested array of objects in TypeScript/JavaScript

I'm dealing with a nested array of objects structured like this: const nestedArray = [ [{ id: 1 }, { id: 2 }, { id: 3 }], [{ id: 1 }, { id: 2 }], [{ id: 4 }, { id: 5 }, { id: 6 }], ] In the case where objects with id 1 and 2 are already grou ...

The module 'SharedModule' has imported an unexpected value of 'undefined'

When working with an Angular application, I want to be able to use the same component multiple times. The component that needs to be reused is called DynamicFormBuilderComponent, which is part of the DynamicFormModule. Since the application follows a lib ...

Steps for generating an instance of a concrete class using a static method within an abstract class

Trying to instantiate a concrete class from a static method of an abstract class is resulting in the following error: Uncaught TypeError: Object prototype may only be an Object or null: undefined This error occurs on this line in ConcreteClass.js: re ...

What is the best method for incorporating new data into either the root or a component of Vue 3 when a button is pressed?

One issue I'm facing is the challenge of reactively adding data to either the Vue root or a Vue component. After mounting my Vue app instance using app.mount(), I find it difficult to dynamically add data to the application. As someone new to the fram ...

There is an issue I encounter when trying to start a new Vue project

Recently, I began diving into vuejs and encountered an issue when trying to set up a new vue project using the terminal. The loadDep status line seems to be stuck in a constant spinning motion, as shown in the image link provided. Any guidance or assistanc ...

What sets the Virtual DOM apart from the Shadow DOM?

During my exploration of Vue.js, I delved into the realm of shadow DOM to grasp the essence of a fundamental Vue.js Component. As I studied shadow DOM and its similarities to virtual DOM, I embarked on a quest for diverse information pertaining to both con ...