Issue Encountered with FabricJS: Unable to Execute 'drawImage' with Image Subclass

I'm working on a project that requires me to add images of different types to a canvas, save them as JSON, and then load them again. The unique property needed for each type is simply the differentiation in type.

To achieve this, I have created a new class based on fabric.Image called fabric.Icon:

fabric.Icon = fabric.util.createClass(fabric.Image, {
      type: "icon",
      initialize: function (element, options) {
        this.callSuper("initialize", element, options);
      },
      _render: function (ctx) {
        this.callSuper("_render", ctx);
      },
    });
    fabric.Icon.fromObject = function (object, callback) {
      return fabric.Object._fromObject("Icon", object, callback);
    };

After creating the fabric.Icon class, I use an SVG image to add a new object of this specific type to the canvas:

let newImage = new Image();    //HTML Image type, not FabricJS
newImage.onload = () => {
   let icon = new fabric.Icon(newImage);   
   this.canvas.add(icon);
};
newImage.src = "image.svg";

However, when I try to export the canvas into JSON using

let savedJSON = canvas.toJSON()

and then load it back with

canvas.loadFromJSON(savedJSON, function () {
    canvas.requestRenderAll();
}

I encounter the following error:

Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'

Everything works correctly when I use the standard fabric.Image class. Should I override another method in my subclass? Or is there a better way to differentiate between various Image types?

Answer №1

Although it's not a direct solution to the issue, I have discovered a method for effectively distinguishing between objects that persist during saving and loading. This involves setting a custom property on the Object.prototype by overriding its toObject method as illustrated in this example: Extending Fabric js toObject with custom properties without losing default ones Issue resolved!

Answer №2

The process of restoring the fabric Icon class is a bit more intricate compared to the fabric Image class because it requires an icon element in the constructor, which is not serializable.

This is the approach taken in fabricJS for implementing it:

  /**
   * Creates an instance of fabric.Icon from its object representation
   * @static
   * @param {Object} object Object to create an instance from
   * @param {Function} callback Callback to invoke when an icon instance is created
   */
  fabric.Icon.fromObject = function(_object, callback) {
    var object = fabric.util.object.clone(_object);
    fabric.util.loadImage(object.src, function(img, isError) {
      if (isError) {
        callback && callback(null, true);
        return;
      }
      fabric.Icon.prototype._initFilters.call(object, object.filters, function(filters) {
        object.filters = filters || [];
        fabric.Icon.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) {
          object.resizeFilter = resizeFilters[0];
          fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) {
            object.clipPath = enlivedProps[0];
            var icon = new fabric.Icon(img, object);
            callback(icon, false);
          });
        });
      });
    }, null, object.crossOrigin);
  };

You will need to copy this code and replace fabric.Image with fabric.Icon.

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

Issue encountered while attempting to create entity in jhipster

After executing the creation of an entity in the command line, JHipster successfully generated Java and script files but encountered issues with updating the database. No new table was inserted despite starting MySQL and turning off the application befor ...

Incorrectly resolving routes in the generate option of Nuxt JS's .env configuration file

Having trouble using Nuxt JS's 2.9.2 generate object to create dynamic pages as static files by referencing a URL from my .env file: nuxt.config.js require('dotenv').config(); import pkg from './package' import axios from 'a ...

Issues detected with the callback function of jQuery validation engine

I am currently utilizing the jQuery ValidationEngine plugin to validate a form. The validation itself is working fine, however upon completion, instead of redirecting to the previous page as expected, a JSON string is displayed on the screen. Below is the ...

Tips on retrieving Bootstrap selectpicker value by using loops in Jquery

I am attempting to perform a basic validation using jQuery, where I need to iterate through all elements to check for the existence of values. The validation script is working well except for the jQuery selectpicker functionality. Here's what I have t ...

Finding the precise Time zone with date-fns: A comprehensive guide

I've implemented a date pipe using the date-fns library for formatting dates. Here is the code: date.pipe.ts import { Pipe, PipeTransform } from '@angular/core'; import { format } from 'date-fns'; @Pipe({ name: 'formatDate ...

Send the innerHTML content to the data layer in Tag Manager

As a newcomer to HTML and CSS, I apologize if this question has already been asked. I am currently working on implementing tags for a new website that keeps track of the number of times sections are viewed on a page. The section names are stored in a var ...

Exploring Techniques for Adjusting Website to User's Screen Resolution

My website is currently designed for a screen resolution of 1024x768. However, I am aware that when viewed on computers with smaller or larger screen resolutions, the layout starts to distort. Is there a way to make the website adaptable to any user&apos ...

A guide on incorporating a JavaScript plugin using Vue.use() into a TypeScript project equipped with typings

Currently, I am facing an issue while attempting to integrate Semantic-UI-Vue into my Vue project. Upon trying to execute Vue.use(SuiVue), the following error message is displayed: Argument of type 'typeof import("semantic-ui-vue")' is not ass ...

Issue with Heroku deployment: unable to locate JavaScript file

I encountered an issue while deploying my node.js app. Everything seemed to be working fine but it couldn't locate the JavaScript files. The error message displayed was: proove.herokuapp.com/:16 GET 404 (Not Found) Here is the server.js code snip ...

Can AJAX be exploited by hackers?

Today, I had a fascinating experience with my built systems. Someone managed to "hack" into everything and attributed the issue to AJAX. Here are his exact words: you are relying on AJAX when I have access to user's browser I have acc ...

Parse a JSON object to conduct time series analysis

My goal is to create a table displaying the changes in stock prices over various time periods such as 1M, 3M, 6M, etc. When making an API call for a specific day in the past, the returned JSON looks like this: { "date": "2018-01-02", "data": { ...

How can I retrieve the value of a radio button using jQuery

My goal is to retrieve the selected/checked radio button value using the .get function. I believe my code is correct, but the sequence seems to be off. $.get('burgerorder_check.php', function(data) { inputVal = $('input[type ...

What is the best approach to comparing two times in JavaScript to ensure accuracy after an NTP time update?

We are facing an issue with a JavaScript function that retrieves the start and end times of two events: var startTime = new Date().getTime(); // A lengthy task is executed var endTime = new Date().getTime(); The problem we encountered is that getTime() s ...

Tips for adjusting the font size of choices within the Material UI autocomplete component

Hey there, I'm currently working on a project using the Material Table and I'm looking to adjust the font size of the options in the Material UI Autocomplete. Any tips would be greatly appreciated! Thanks https://i.sstatic.net/ZM17w.png import R ...

Disable button with Checkbox Javascript functionality

In my PHP code, I have an array of users that I pass to the view (in Laravel) and use a foreach loop to display all users in a table. Everything is working fine so far. However, I want to make a "send" button visible when a checkbox is clicked, instead of ...

Creating dynamic flags with specific parameters using Pentaho and JavaScript

I am looking to optimize my code by finding a better way to achieve this. I have a variable called "hour" and I need to create flags for each hour of the day like so: if (hour == 0) {flag12AM = 'yes'} else {flag12AM == 'no'} if (hour ...

Activate the action using the onclick interaction

window.addEventListener(mousewheelEvent, _.throttle(parallaxScroll, 60), false); My current setup involves an event listener that responds to a mousewheelEvent by executing a function. However, when attempting to directly trigger this function on a separa ...

Having difficulty communicating with the smart contract using JavaScript in order to retrieve the user's address and the balance of the smart contract

Hi there, I am a newcomer to the world of blockchain technology. Recently, I created a smart contract designed to display both the contract balance and user data, including the address and balance of the user. The smart contract allows users to deposit fun ...

Establishing a Goal in Google Analytics using JavaScript

My approach to recording Goals in Google Analytic tool via JS involves adding code directly to the page: <meta name="description" content="iReserve"> <link rel="shortcut icon" href="/ico/favicon.ico" /> & ...

What is the reason behind JavaScript subtracting the timezone offset for ISO dates when passed into the Date() function?

In my function, I handle different valid date strings to produce a JavaScript Date object. Most strings work as expected, however, when an ISO formatted date (YYYY/MM/DD) is provided, the user's timezone offset is deducted from the date. For example ...