Creating methods in Vue that can alter elements created during the mounted lifecycle hook can be achieved by defining functions

I am trying to implement a button that can recenter the canvas. The idea is that when the button is clicked, it will trigger the rec() method which should reposition the canvas that was created in the mounted() function.

However, this setup is not working as expected. I suspect that the methods are having trouble referencing elements created within the mounted() function.

Any suggestions on how to resolve this issue?

<div id="main">
    <canvas id="c" width="400" height="400"></canvas>
</div>
<button v-on:click="recenter">Recenter</button>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.js"></script>

<script>
    const app = new Vue(
        {
            el: '#main',
            methods: {
                recenter: function rec() {
                    var fabric_canvas = new fabric.Canvas('c')
                    fabric_canvas.setViewportTransform([1,0,0,1,0,0]);
                }
            },
            mounted() {
                var fabric_canvas = new fabric.Canvas('c');
                var group = [];
                var myurl = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Svg_example1.svg";
                fabric.loadSVGFromURL(
                    myurl,
                    function(objects,options) {
                        var loadedObjects = new fabric.Group(group);
                        fabric_canvas.add(loadedObjects);
                        fabric_canvas.renderAll();
                    },
                    function(item, object) {
                        group.push(object);
                    }
                );
            }
        }
    );
</script>

Answer №1

To store the current instance of the fabric class, utilize the window property; I have implemented a computed function for this purpose and a state to determine the status of the class.

If an instance of the fabric class is created, then the value of fabricHaveAnActiveInstance will be set to true.

In the computed function, it checks if the value is true so as not to create another instance and retrieves them from the window object instead.

To access a computed function within methods or when mounted, simply use the this keyword in Vue.

I have also designated an active object, as clicking the recenter button without selecting an object would result in an error.

Note regarding method definition: You are not required to assign a name to your function.

Below is a functional example based on your code:

const app = new Vue(
        {
            el: '#main',
            data: function(){
                return {
                    fabricHaveAnActiveInstance: false
                }
            },
            methods: {
                recenter: function () {
                  // this.fabric_canvas.setViewportTransform([1,0,0,1,0,0]);
                    let object = this.fabric_canvas.getActiveObject()
                    let objWidth = object.getScaledWidth()
                    let objHeight = object.getScaledHeight()
                    let zoom = this.fabric_canvas.getZoom()
                    let panX = 0
                    let panY = 0
                    
                    console.log("object width is: " + object.width)
                    console.log(" object.getScaledWidth.x is: " + object.getScaledWidth())
                    

                    panX = ((this.fabric_canvas.getWidth() / zoom / 2) - (object.aCoords.tl.x) - (objWidth / 2)) * zoom
                    panY = ((this.fabric_canvas.getHeight() / zoom / 2) - (object.aCoords.tl.y) - (objHeight / 2)) * zoom
                                          
                    this.fabric_canvas.setViewportTransform([zoom, 0, 0, zoom, panX, panY])
                      
                }
            },
            mounted() {
                console.log(this.fabric_canvas)
                var fabric_canvas = this.fabric_canvas;
                var group = [];
                var myurl = "https://upload.wikimedia.org/wikipedia/commons/a/a0/Svg_example1.svg";
                fabric.loadSVGFromURL(
                    myurl,
                    function(objects,options) {
                        var loadedObjects = new fabric.Group(group);
                        fabric_canvas.add(loadedObjects);
                        fabric_canvas.renderAll();
                        fabric_canvas.setActiveObject(fabric_canvas.item(0))
                    },
                    function(item, object) {
                        group.push(object);
                    }
                );
                
            },
            computed:{
                fabric_canvas: function(){
                    if(this.fabricHaveAnActiveInstance){
                        return window.fabric_canvas
                    }else{
                        const fabric_instance = new fabric.Canvas('c'); 
                        window.fabric_canvas = fabric_instance;
                        this.fabricHaveAnActiveInstance = true;
                        return fabric_instance;
                    }
                }

            }
        }
    );
<div id="main">
    <canvas id="c" width="400" height="400"></canvas>

    <button v-on:click="recenter">Recenter</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4533302005776b736b7471">[email protected]</a>/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.js"></script>

Reference: To center the object, I used a function in this pen (pen link)

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

Objects remaining static

I'm currently working on a VueJS component that has the ability to export data into .xlsx format. To achieve this functionality, I am utilizing the json2xls library, which requires an array of objects with identical keys (representing column names) to ...

Encountering a client component error with the app router in Next.js version 13.4.9

Encountering an error in Nextjs that persists until the 'use client' directive is removed. Warning: Rendering <Context.Consumer.Consumer> is not supported and will be removed in a future major release. Did you mean to render <Context.Con ...

WebPack bundling causing issues with Knockout Validation

I am developing a web application using Knockout along with the Knockout-Validation plugin, and I want to utilize WebPack for bundling. However, I encountered an issue where Knockout-Validation seems to break when incorporated with WebPack. To illustrate ...

Using BeautifulSoup to extract data from a webpage containing JavaScript

Hello everyone! I am reaching out for help once more. While I am comfortable scraping simple websites with tags, I recently came across a more complex website that includes JavaScript. Specifically, I am looking to extract all the estimates located at the ...

AngularJS: Struggling to Set Up Controller

I recently started my journey with AngularJS a few days back, and I've encountered this frustrating issue. Every time I run into this error: Error: ng:areq Bad Argument Argument 'NewStudentCtrl' is not a function, got undefined All my ot ...

Enhancing your Vue.js component props with descriptive hints

I am currently integrating new components into a project and I want to include information about a specific prop, such as hints or acceptable values that can be passed. Is there a way for my component to display this information when users press ctrl+space ...

Using webGL for rendering drawElements

I am working with face-indices that point to specific points to draw triangles in a loop. Unfortunately, when executing my code, I encountered the following error in the web console: WebGL: drawElements: bound element array buffer is too small for given c ...

Switch up the font style of the title element

Is it possible to modify the font-family of the title attribute in an input field using either JavaScript or jQuery? <input type="text" title="Enter Your Name" id="txtName" /> ...

Tips for preventing directly mutating a prop within a recursive component

The child operates on its own copy of the prop data and can notify the parent using `$emit` when a change occurs. Imagine dealing with a recursive tree structure, like a file system for example: [ { type: 'dir', name: 'music', childr ...

Node.js encountered an SFTP error stating "Error: connect: An existing SFTP connection is already defined."

Working within my node.js application, I have implemented ssh2-sftp-client to upload an image every 5 seconds. The initial upload functions correctly, but upon repeating the process, I encounter an error message: node .\upload.js uploaded screenshot ...

The property 'join' is undefined for null values

I've recently started learning AngularJS, but I'm having trouble figuring out what's causing issues in my code. Despite trying various approaches, the outcome is always incorrect. <!DOCTYPE html> <html lang="en" ng-app="myApp"> ...

Enhance mix-blend mode or filtering effects in SCSS using an SVG component in VueJS

I am currently developing a fixed navbar at the top of a webpage with several SVGs inside anchor tags. I want the SVGs to appear black when displayed over lighter colored divs (other Vue components) and white when displayed over darker colored ones. The ba ...

What is the method for dynamically updating and showcasing a JSON file upon the click of a button?

I'm currently developing an add-on that will display a panel with checkboxes and a save button when a toolbar button is clicked. The goal is to allow users to select checkboxes, then save the selected data in a JSON file that can be accessed and updat ...

Determine in JavaScript whether a character is 32-bit or not

Is there a way to determine if a specific character is 32 bits using JavaScript? I attempted to use charCodeAt() but it was unsuccessful for identifying 32-bit characters. Any guidance or assistance on this matter would be greatly valued. ...

Navigating to a Laravel web route directly from a Vue component without relying on Vue Router

This question may seem repetitive, but I have searched everywhere for a solution. I am using laravel-vujs mix and have integrated web routes and api routes in the same project. Currently, I am working on creating a register API function called registerna ...

Ways to extract the initial layer of information from a JSON document

I have a JSON file named movie.json stored externally, and it follows this format: { "action": [ { "id": "1001", "name": "Matrix" }, { "id": "1002", & ...

Dealing with Errors When Working with Angular Promises

Currently, I am in the process of mastering promises within Angular. In my code snippet, I have two "GET" requests that I need to execute sequentially. Everything is functioning properly, but I'm unsure about how to handle errors in this scenario. If ...

Switching between multiple images using Jquery on a click event

Hi there, I am currently working on a project where I need to use jQuery to switch between three images when clicked. Once the third image is clicked, it should cycle back to the first picture. I was wondering if there is a way to modify the code below so ...

Dayjs is failing to retrieve the current system time

Hey everyone, I'm facing an issue with using Dayjs() and format to retrieve the current time in a specific format while running my Cypress tests. Despite using the correct code, I keep getting an old timestamp as the output: const presentDateTime = da ...

Switch between showing and hiding a div by clicking on the panel header and changing the symbol from + to

I need assistance with a panel feature on my website. The panel should expand when the "+" symbol is clicked, displaying the panel body, and the "+" symbol should change to "-" indicating it can be collapsed by clicking it again. There is a slight twist t ...