Part 3: Fabric.js on React — fabric.Image.fromURL(‘…’)

April Escobar
5 min readApr 19, 2021
(Image Source)

Introduction:

Hello there 🙋‍♀️

Welcome to my personal notes on learning the Fabric.js library on React. We’ll be taking in bite-size information to digest everything we learn.

In every bite-size read, we’ll cover syntax, go over what we need, do some sample coding, and finally view the end result.

(We’re going to assume we have a basic understanding of React.)

I’m a huge fan of ES6 syntax and hooks, so we’ll be utilizing those throughout our learning experience.

Feel free to correct me in anything I write as, again, these are my personal notes I’m publishing to the world~

Cheers!

Recap of the end code and results from Part 2:

import React, { useState, useEffect } from 'react';
import { fabric } from 'fabric';
const App = () => {
const [canvas, setCanvas] = useState('');
useEffect(() => {
...
}, []);

const initCanvas = () => (
...
);
const addRect = canvi => {
const rect = new fabric.Rect({
height: 280,
width: 200,
fill: 'yellow'
});
canvi.add(rect);
canvi.renderAll();
}
return(
<div>
<h1>Fabric.js on React - fabric.Canvas('...')</h1>
<button onClick={() => addRect(canvas)}>Rectangle</button>
<br/><br/>
<canvas id="canvas" />
</div>
);
}

Part 3: Fabric.js on React — fabric.Image.fromURL(‘…’)

new fabric.Image.fromURL('...')

Rectangles are cool and all, but you know what would be even cooler? Adding images to the canvas 🕶 ✨ — Which is exactly what we’re doing in this bite-size read. We’ll go over the basics of fabric.Image.fromURL.

Its purpose and uses:

  • Extends fabric.Object
  • Another fabric object with properties we can manipulate

Because a fabric.Image just another fabric object, adding it to our canvas is quite similar to adding rectangles. One key difference in this case is that we’re utilizing the .fromURL(‘…’) method.

With the .fromURL(‘…’) method, it allows our users to input any image URL link to render on our canvas (phase 1 of adding images).

Understanding the syntax:

  • Takes in two parameters, a url link and a callback function
  • Returns an instance of a fabric.Image
new fabric.Image.fromURL('my_img.png', image => {
image.scale(0.75);
canvas.add(image);
canvas.renderAll();
})

What we need:

  1. A state variable to store and access the image URL.
  2. A basic input form to invoke the rendering of the object.
  3. A dynamic function to handle the form submission and reset the input field.

Let’s code it!

Step 1: Define a state variable to store and access the image URL.

const [imgURL, setImgURL] = useState('');

Step 2: Create a basic input form to invoke the rendering of the object.

<form onSubmit={e => addImg(e, imgURL, canvas)}>
<div>
<input
type="text"
value={imgURL}
onChange={ e => setImgURL(e.target.value)}
/>
<button type="submit">Add Image</button>
</div>
</form>

Step 3: Create a function to handle the form submission and reset the input field.

const addImg = (e, url, canvi) => {
e.preventDefault();
new fabric.Image.fromURL(url, img => {
img.scale(0.75);
canvi.add(img);
canvi.renderAll();
setImgURL('');
});
}

Final Code:

import React, { useState, useEffect } from 'react';
import { fabric } from 'fabric';
const App = () => {
const [canvas, setCanvas] = useState('');
const [imgURL, setImgURL] = useState('');
useEffect(() => {
...
}, []);

const initCanvas = () => (
...
);
const addRect = canvi => {
...
}
const addImg = (e, url, canvi) => {
e.preventDefault();
new fabric.Image.fromURL(url, img => {
img.scale(0.75);
canvi.add(img);
canvi.renderAll();
setImgURL('');
});
}
return(
<div>
<h1>Fabric.js on React - fabric.Canvas('...')</h1>
<button onClick={() => addRect(canvas)}>Rectangle</button>
<form onSubmit={e => addImg(e, imgURL, canvas)}>
<div>
<input
type="text"
value={imgURL}
onChange={ e => setImgURL(e.target.value)}
/>
<button type="submit">Add Image</button>
</div>
</form>
<br/><br/>
<canvas id="canvas" />
</div>
);
}

End Result:

If all goes well, we should see something like this:

Things to note: Please TEST!

Although this bite-size read neatly summarizes the creation of the fabric.Image.fromURL feature, it‘s imperative that you still TEST everything from start to finish.

Testing throughout the creation of this feature would include:

  • Temporarily using a hard-coded image URL to feel out the function.
const testURL = 'https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg'...const addImg = (e, url, canvi) => {
e.preventDefault();
new fabric.Image.fromURL(url, img => {
img.scale(0.75);
canvi.add(img);
canvi.renderAll();
setImgURL('');
});
}
...<form onSubmit={e => addImg(e, imgURL, canvas)}>
<div>
<input
type="text"
value={imgURL}
onChange={ e => setImgURL(e.target.value)}
/>
<button type="submit">Add Image</button>
</div>
</form>
  • Playing with the image scale.

The true chronological steps:

  1. Add an input form that invokes the rendering of the object.
  2. TEST the form submission functionality.
  3. Create a function that handles the event and renders a fabric.Image object.
  4. TEST the function with a hard-coded image URL.
  5. Define a state variable to store and access the image URL.
  6. TEST the function with the state value.

Remember, creating features will never be done perfectly in one shot. Practice, testing and experience will make coding smoother, just keep in mind that those also take time to develop. 😇

Side note:

If you’re getting cross-origin-isolation error due to Google Chrome’s updates it’s a pretty easy fix (thankfully). All we need to do is upgrade to the latest React version.

Error message:

[Deprecation] SharedArrayBuffer will require cross-origin isolation as of M91, around May 2021. See https://developer.chrome.com/blog/enabling-shared-array-buffer/ for more details.

Easy fix:

npm i react@latest react-dom@latest

If you haven’t noticed, we haven’t really added any styling to our mini-project. I do apologize for the eyesore but there will be a post or two on customizing the styling of our project!

As always, thank you for your time in reading my stories. Do give this story a clap or two (or fifty 😉) if you enjoyed following/coding along or if you learned something new or just want to show your support.

Until next time, cheers!

--

--