FabricJS: Cannot read property of 'e' of undefined - javascript

Getting the following error and even though I know what the error means (an object is undefined/null so its property e fails), I'm not sure why it's getting this error. Pretty sure it is related to some FabricJS object and not just plain Javascript. If anyone that knows FabricJS can help me out, that would be great.
fabric.js:8466 Uncaught TypeError: Cannot read property 'e' of undefined
at klass.onMouseDown (fabric.js:8466)
at HubConnection.<anonymous> (chat.js:128)
My code: This function is client side code for receiving a mousedown event from the server (which gets that info from the sending client). It create a new PencilBrush object on the receiving client, and starts it at the same position the sending client presses mousedown. Basically I'm trying to display what the sending client is drawing to receiving client in live time, and this is one of the functions that helps with that.
connection.on("ReceiveMouseDown", function (user, coordinate) { //coordinate is a string
console.log("inside receive mouse down: " + coordinate); //this returns {x: value, y: value}
var coordinateObject = JSON.parse(coordinate);
console.log('coordinateObject is: ' + coordinateObject); //this returns [object object]
brush = new fabric.PencilBrush(canvas);
brush.onMouseDown(coordinateObject); //this is line 128, exception occurs here
//brush.onMouseDown(coordinate); I have also tried this way, but same exception happens
canvas.renderAll();
});
My findings: I think the PencilBrush.onMouseDown() method takes a Pointer (as seen here http://fabricjs.com/docs/fabric.PencilBrush.html ), but the docs aren't very good at explaining what a Pointer object is.

If any one is trying with recent fabric js and facing the same issue, try following. I am using version 4.4.0
var canvas = new fabric.Canvas(document.getElementById('canvasId'));//Primary canvas
var canvas2 = new fabric.Canvas(document.getElementById('canvasId2'));//Drawing programmatically on second canvas
//Getting points from first canvas
const pointer = canvas.getPointer(e);
//Drawing on second convas
let options = {pointer,e:{}};
canvas2.freeDrawingBrush.onMouseDown(initialPointer,options);

I think you are using version 3.3. Try using version 3.2 instead of version 3.3... the source code has been changed a bit to require an extra param.

Related

Detecting net::ERR_FILE_NOT_FOUND with only JS

I have recreated a blueprint, which has 60+ rooms, as an inline SVG.
There are functions that display information, such as pictures, when you select or hover a room. I'm using one div container to display the pictures by setting its background property to url('path-of-image.ext'), as can be seen below.
var cla = document.getElementsByClassName('cla');
for (i = 0; i < cla.length; i++) {
cla[i].addEventListener('mouseenter', fun);
}
function fun(){
var str = 'url("media/' + this.id.slice(4) + '.jpg")';
pictureFrame.style.background = str;
pictureFrame.style.backgroundSize = 'cover';
pictureFrame.style.backgroundPosition = 'center'
}
The reason I'm not using the background property's shorthand is because I plan on animating the background-position property with a transition.
However, not all rooms have pictures. Hence console throws the following error, GET ... net::ERR_FILE_NOT_FOUND, when you select or hover said rooms. The error doesn't cause the script to break, but I would prefer not to run that code every single time a room is hovered, even when a given room doesn't have pictures.
Even though I know this can be done imperatively with if/else statements, I'm trying to do this programmatically since there are so many individual rooms.
I've tried using try/catch, but this doesn't seem to detect this sort of error.
Any ideas?
Is it even possible to detect this kind of error?
You could attempt to read it using FileReader and catch/handle NotFoundError error.
If it were to error, you could assign it to an object or array which you would first check upon hover. If the file was in that array, you could avoid attempting to read it again and just handle however you like.
Here is a good article by Nicholas Zakas on using FileReader
First off I would see if there is a way of checking if the file exists before the document even loads so that you don't make unnecessary requests. If you have a database on the backend which can manage this that would serve you very well in the long term
Since you make it sound like the way you only know a file exists is by requesting it, here's a method that will allow you to try this:
function UrlExists(url)
{
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
This won't request the image twice because of browser caching. As you can see that method is itself being depricated and overall the best way you can remedy this problem is checking before the page even loads; if you have a database or datastructure of any sort, add a class or property to the element if the image exists or not. Then, in your existing method, you can call something like document.getElementsByClassName('cla-with-image') to get only records that you've determined has an image (much more efficient than trying to load images that don't exist).
If you end up using that UrlExists method, then you can just modify your existing method to be
function fun(){
var url = "media/' + this.id.slice(4) + '.jpg";
if (UrlExists(url)) {
var str = 'url(' + url + ')';
pictureFrame.style.background = str;
pictureFrame.style.backgroundSize = 'cover';
pictureFrame.style.backgroundPosition = 'center'
}
}

Electron fails when sending a large object with BrowserWindow.webContents.send between renderers

I am finding impossible to move a large object full of data with
console.log('here')
BrowserWindow.webContents.send('test',data)
console.log('again')
There's no error message but I don't get the 'again' log.
If I build the data piece by piece, it works with simple data, but when I copy a large portion it doesn't. I cannot reproduce it since the amount of items I have in the object-to-pass is very large (see image), but I JSON-serialize it without problems.
Is there any alternative to pass this variable from a Renderer to another Renderer in Electron?
You can try the opposite with IPC:
send a sync message from the Renderer and automatically return the message that you want from the Main.
var data= ipcRenderer.sendSync("msg", "ping");
and
ipcMain.on("msg", (event, arg) => {
event.returnValue = data
})

What does "uncaught exception: out of memory" mean and how do you track the cause? [duplicate]

I am debugging a javascript/html5 web app that uses a lot of memory. Occasionally I get an error message in the console window saying
"uncaught exception: out of memory".
Is there a way for me to gracefully handle this error inside the app?
Ultimately I need to re-write parts of this to prevent this from happening in the first place.
You should calclulate size of your localStorage,
window.localStorage is full
as a solution is to try to add something
var localStorageSpace = function(){
var allStrings = '';
for(var key in window.localStorage){
if(window.localStorage.hasOwnProperty(key)){
allStrings += window.localStorage[key];
}
}
return allStrings ? 3 + ((allStrings.length*16)/(8*1024)) + ' KB' : 'Empty (0 KB)';
};
var storageIsFull = function () {
var size = localStorageSpace(); // old size
// try to add data
var er;
try {
window.localStorage.setItem("test-size", "1");
} catch(er) {}
// check if data added
var isFull = (size === localStorageSpace());
window.localStorage.removeItem("test-size");
return isFull;
}
I also got the same error message recently when working on a project having lots of JS and sending Json, but the solution which I found was to update input type="submit" attribute to input type="button". I know there are limitations of using input type="button"..> and the solution looks weird, but if your application has ajax with JS,Json data, you can give it a try. Thanks.
Faced the same problem in Firefox then later I came to know I was trying to reload a HTML page even before setting up some data into local-storage inside if loop. So you need to take care of that one and also check somewhere ID is repeating or not.
But same thing was working great in Chrome. Maybe Chrome is more Intelligent.

ChromeWorker set pointer to the memory or send big data. How?

We trying send 500kb through ChromeWoker and get out of memory error in console.
This code:
let charArray= ctypes.ArrayType(ctypes.char);
let base641 = new charArray(9999999);
var {ChromeWorker} = Cu.import("resource://gre/modules/Services.jsm", null);
var chworker = new ChromeWorker(self.data.url("async.js"));
chworker.onmessage = function(e){
console.error(e.data);
};
chworker.postMessage(base641);
return error:
stack:"#undefined:undefined:undefined
CuddlefishLoader/options<.load#resource://gre/modules/commonjs/sdk/loader/cuddlefish.js:129:9
run#resource://gre/modules/commonjs/sdk/addon/runner.js:169:9
startup/<#resource://gre/modules/commonjs/sdk/addon/runner.js:113:7
Handler.prototype.process#resource://gre/modules/Promise-backend.js:863:11
this.PromiseWalker.walkerLoop#resource://gre/modules/Promise-backend.js:742:7"
What is undefined? Can we set pointer to the memory through ChromeWorker?
To pass a ctypes array, you'd take the address() and post that in a message and construct another pointer from that address on the other side. This works, but is rather nasty, of course. You'd also need to make sure that garbage collection does not collect stuff while the other side it still using it!
You might be better off using ArrayBuffer/typed arrays which you can pass directly, also from non-privileged code.

Can't change dconf-entry with GSettings

I'm currently building a simple application on Gjs, which should change the background-image of my gnome-shell. A solution on how this can be done using the gsettings-tool can be found here.
Since I want to build a desktop-application around it, I want to change the org.gnome.desktop.background.picture-uri-key by using Gio's GSettings-class. But using the set_X()-method does not change the value of the key.
This is my code to change the gsettings value:
var gio = imports.gi.Gio;
// Get the GSettings-object for the background-schema:
var background = new gio.Settings({schema: "org.gnome.desktop.background"});
// Read the current Background-Image:
print( "Current Background-Image: "+background.get_string("picture-uri") );
if (background.is_writable("picture-uri")){
// Set a new Background-Image (should show up immediately):
if (background.set_string("picture-uri", "file:///path/to/some/pic.jpg")){
print("Success!");
}
else throw "Couldn't set the key!";
} else throw "The key is not writable";
Reading the value does work as expected, the is_writable()-method returns true and the set_string()-method also returns true.
I have checked that I'm not in "delay-apply" mode and the key has a GVariantType of string, so the set_string()-method should work.
Using the normal gsettings command-line tool (as explained in the linked post) works just fine.
I can't figure out what the problem is, is there any place I can look for logs or something?
After not getting any responses here I asked the same question on the gjs-mailing list.
It turned out that the writes to dconf were not yet on the disk when my script exited, so they were never really applied.
The solution was to call the g_settings_sync() function (JsDoc) right after the set_string() function, to ensure that all writes had finished.
if (background.set_string("picture-uri", "file:///path/to/some/pic.jpg")){
gio.Settings.sync()
print("Success!");
}
Thanks to Johan Dahlin and his answer.

Categories