I am trying to add fabric.js to an empty Blazor server-server side app. I did the following:
Added the following scripts in _Host.cshtml
<script src="https://unpkg.com/fabric@latest/dist/fabric.js"></script>
<script src="~/js/ImageEditor.js"></script>
Created this file under wwwroot/js
:
window.fabricFunctions = {
setup: function() {
var canvas = new fabric.Canvas('canvasId');
// create a rect object
var deleteIcon = "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";
var img = document.createElement('img');
img.src = deleteIcon;
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.cornerColor = 'blue';
fabric.Object.prototype.cornerStyle = 'circle';
return canvas;
},
add: function (canvas) {
var rect = new fabric.Rect({
left: 100,
top: 50,
fill: 'yellow',
width: 200,
height: 100,
objectCaching: false,
stroke: 'lightgreen',
strokeWidth: 4,
});
canvas.add(rect);
canvas.setActiveObject(rect);
}
};
Placed the following in a razor page:
@page "/"
@inject IJSRuntime jsRuntime;
<div class="controls">
<p>
<button id="add" @onclick="Add">Add a rectangle</button>
</p>
</div>
<canvas id="canvasId" width="400" height="300" style="border:1px solid #ccc"></canvas>
@code {
private async Task Add()
{
var canvas = await jsRuntime.InvokeAsync<object>("fabricFunctions.setup");
await jsRuntime.InvokeVoidAsync("fabricFunctions.add", canvas);
}
}
After calling setup
, I do have a canvas
object that I pass to the add
function. But I get an exception when calling canvas.add(rect)
, stating the add is not a function of canvas.
Is there a better way to keep an instance of canvas
in the javascript code instead of passing it around the methods?
2
Answers
See here:
How to get JS object and pass it back?.
If you want to pass an object by reference from one JavaScript function to another, the workaround is to create a JavaScript function to do this directly, e.g.:
Blazor Component:
It seems like you’re facing an issue where the
canvas
object passed to theadd
function is not recognized as a valid Fabric.js canvas instance. This might be due to the way JavaScript and Blazor interoperate. To address this issue and improve the organization of your code, you can make a few adjustments:1.Separate JavaScript Initialization:
Move the canvas setup and any other related initialization code into the
ImageEditor.js
file. This way, you ensure that the canvas instance is properly created and maintained within the JavaScript scope.2. Global Scope for Canvas:
Instead of returning the canvas instance from the
setup
function, create a global variable within the JavaScript scope to hold the canvas instance. This will allow other functions to access the canvas instance without passing it as a parameter.Here’s how you can modify your code:
In
ImageEditor.js:
In your Blazor component:
This approach maintains the canvas instance within the JavaScript scope without needing to pass it explicitly between functions. Just be cautious with using global variables, as they can lead to unexpected behavior in more complex scenarios. In this case, since you’re dealing with a single canvas instance, it should work well.