3

I'm trying to display some shapes using the Fabric.js library. From the console, seems like the fabric.canvas is built correctly, but nothing is being rendered. My code:

HTML

<template>
    <lightning-card title="testFabric" icon-name="custom:custom19">
        <div class="slds-var-m-around_medium">
            <canvas
                    width="500"
                    height="500"
                    id="c"
                    class="c"
                    lwc:dom="manual"
            ></canvas>
        </div>
    </lightning-card>
</template>

JS

import { LightningElement, api } from 'lwc';
import fabricLib from '@salesforce/resourceUrl/fabric';
import { loadScript } from 'lightning/platformResourceLoader';
       
export default class ShowShapes extends LightningElement {

    @api recordId;

    //retrieve canvase and context
    renderedCallback() {
        Promise.all([
            loadScript(this, fabricLib + '/fabric.min.js')
        ])
            .then(() => {
                console.log(fabric?.Canvas, 'canvas');

                let canvas = this.__canvas = new fabric.Canvas('c');

                console.log(canvas, 'created canvas');

                var rect = new fabric.Rect({left: 100,top: 50,fill: '#D81B60',width: 50,height: 50,strokeWidth: 2,stroke: "#880E4F",rx: 10,ry: 10,angle: 45,scaleX: 3,scaleY: 3,hasControls: true});

                canvas.add(rect);
                console.log(canvas);
                canvas.requestRenderAll();
                canvas.renderAll();
            })
            .catch((error) => {
                console.log(error);
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Error loading Fabric',
                        message: error.message,
                        variant: 'error'
                    })
                );
            });
    }
}

Console logs: enter image description here

LWC canvas: enter image description here

1 Answer 1

13
+50

I'm afraid that Lightning Locker won't allow you to use that js lib, for the several reasons:

  1. new fabric.Canvas() constructor can take either <canvas> element or its id to initialize an instance on. Passing the id invokes document.getElementById(id) method under the hood but Locker will return null. It is possible to pass the element into the fabric.Canvas constructor directly adding the data-id attribute to the canvas:

HTML

<canvas
    width="500"
    height="500"
    class="c"
    data-id="c"
    lwc:dom="manual"
></canvas>

JS

const canvasEl = this.template.querySelector('[data-id="c"]');
let canvas = = new fabric.Canvas(canvasEl);
  1. But then you face another problem is that the lwc:dom="manual" directive makes it possible to call the appendChild() method on the HTMLElement to manually insert the DOM. This does not mean it is allowed to perform element.parentNode.replaceChild(e, t) not to mention the manipulation of global objects such as window, document, etc.

Unfortunately, Fabric.js library tries to create a parent wrapper element (<div class='canvas-container'/>) during the initialization phase and, for obvious reasons (lwc:dom="manual" element must be empty), Locker throws an error:

Error: Access denied: {"from":{"namespace":"c"}}

That is, in order for this library to be compatible with Locker, it must be rewritten taking into account at least the above restrictions.

But there is also good news.

Recently there was introduced Lightning Web Security (LWS) a new client-side security architecture for Lightning Web Components.

Lightning Web Security is designed to make it easier for your components to use secure coding practices and aims to replace Lightning Locker for Lightning web components (LWC). It works along with Lightning Locker, which is still used for Aura components.

Lightning Web Security (LWS) is modeled after the latest TC39 standards to provide innovative usable security for any UI component. This approach enables teams to safely use code from third parties without fear of threats such as cross-site scripting (XSS) attacks. The result is a more secure way to control the execution of code within the UI layer without forcing developers to jump through hoops or abandon desired functionality.

Before enabling LWS you should consider the next things:

  1. If you want to do it in your scratch org/sandbox it is OK.
  2. If you want to enable LWS in your production org please read When to Enable Lightning Web Security.

If all requirements are taken into account and met, in order to enable LWS in your org go to

Setup -> Home -> Security -> Session Settings

On the Session Settings page, select Use Lightning Web Security for Lightning web components and save.

Clear your browser cache after enabling or disabling Lightning Web Security to ensure the correct files are loaded in the browser.

Having that done, just look at this beauty:

enter image description here

It is even draggable, resizable, and rotatable:

enter image description here

It's safe to say that LWS is a revolution in Salesforce front-end development. Thanks to all those who participated in its development.

1
  • Hi Oleh, I was afraid that it's being caused by the Locker Service. Thanks a lot for suggesting switching to the LWS, totally didn't think about that. Seems like it's working now!
    – Michal_LFC
    Jun 21, 2022 at 16:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .