Prevent render of fabric-js canvas until fully populated - javascript

In FabricJS canvas.loadFromJSON() seems to run some sort of renderAll function even if not specified? As I'm both loading images from JSON and some from another function, I would like the canvas to stay empty until everything is loaded and then render everything simultaneously.
I have created a short fiddle with a simplified version: https://jsfiddle.net/Xikura/cas6j7b3/168/
The fiddle toggles one of the layers then redraws the canvas, especially if you disable caching you can see that the props shows up on it's own, then the rest of the images a bit later.
Quite minor one might say, but when there are between 10 and 30 images with various blend-settings, the loading could take some time until common images starts to get cached, moving around on the early visible props isn't doing my solution much good...
I see the documentation of loadFromJSON adds the renderAll() in it's callback, I trigger my own preload images in that same callback instead, to be able to add the other images.
if (!jsonCanvas) {
// First load
preload(images);
} else {
// Loading from saved JSON
canvas.loadFromJSON(jsonCanvas, function () {
preload(images);
});
}
Right now I can't seem to grasp why loadFromJSON seem to trigger some sort of render so the props are displayed first? Does FabricJS have any functionality I could use to prevent a render until I trigger it myself with renderAll() ?
I found the FabricJS-setting which one would think would solve this: renderOnAddRemove which I set to false, it did fix some other render-difficulties I had earlier, but had no effect on the loadFromJSON-part.

So I have been working the whole day on this, but after completing my question I decided to give it a rest and move on to other problems. By accident while trying to optimize the performance of my application I stumbeled upon this Improving FabricJS speed-site, which both answers my question and solves my problem.
By switching out loadFromJSON with fabric.util.enlivenObjects I'm able to trigger my own callback and not the (undocumented?) canvas.renderAll() which loadFromJSON calls.
if (!jsonCanvas) {
// First load
preload(images);
} else {
// Loading from saved JSON
fabric.util.enlivenObjects(jsonCanvas.objects, (objs) => {
objs.forEach((item) => {
canvas.add(item);
});
preload(images);
})
}
I updated my fiddle to include this fix.

Related

AmMaps MapImage appears on window resize/move after deleteObject() call on it

I need to show pulsar animation in the map point on an event. I add circle image to the map and remove it after some time. I animate the image using CSS. All works ok, but if I try to resize the window, the image appears again and is never removed after.
Here is the issue screencast:
See the codepen (the event is illustrated using setTimeout()).
Am I using the wrong method for image deletion or missing smth?
Typically you're supposed to call validateData() or validateNow() on the entire map when adding new images. Since you're using tap.validate() to add a single image, you have to leverage some internal APIs similar to what was suggested in this ticket to make that work. Using your code as a base:
tap.validate();
this.map.dataProvider.images.push(tap);
// add to internal objects
this.map.imagesProcessor.allObjects.push(tap);
this.map.imagesProcessor.allSvgObjects.push(tap.displayObject);
tap.parentArray = map.dataProvider.images;
setTimeout(() => {
tap.deleteObject();
}, 1000);
Updated codepen

Access jQuery Object After Calling Initial Function

Plugin I'm working with: 3D Gallery (Source code here)
I can get this gallery to work with no issue, but I'm having trouble extending the functionality to include a play and pause button. I've set up a fiddle with how I'm currently getting the slideshow up and running.
I believe the bit that matters is here:
_startSlideshow: function() {
var _self = this;
this.slideshow = setTimeout(function() {
_self._navigate('next');
if (_self.options.autoplay) {
_self._startSlideshow();
}
}, this.options.interval);
}
From what I gather, all I need to do is update the gallery object's autoplay property so that the next time it hits the start slideshow function, it just pauses instead. The problem I'm having is I have no idea how to access that once I've started the slideshow up. Just to have a little more control over things, I've even pulled out the javascript from the fiddle and entered it into the Chrome console to run it there so I can see all the worky bits, still can't seem to update it. One last note, it seems the only public function in there is destroy, which I'm also not able to call on my object after starting the slideshow. If I could get that working, I'd absolutely have just written a setAutoplay(bool) function.
I assume this is just some sort of scope issue mixed with my novice understanding of syntax, but I'd sure appreciate some help.
-- Here's an updated fiddle that includes some of the ways I'm trying to access/update the autoplay stuff, none working. Also showed the destroy function doing nooothing. https://jsfiddle.net/wzrooqof/2/
I've took a look at the library's code. You can do it without needing to change its code. It is exposed, so you can temper with it and leave the source code as is.
In your JS code add this before using it:
$.Gallery.prototype.pause = function() {
clearTimeout(this.slideshow);
this.options.autoplay = false;
}
$.Gallery.prototype.resume = function() {
this.options.autoplay = true;
this._startSlideshow();
}
Then you can pause/resume a slide show like this:
var slideshow = $('#dg-container').gallery({autoplay: true});
slideshow.data("gallery").pause();
slideshow.data("gallery").resume();
JSFiddle example.

Image viewer/editor with CamanJS

I am trying to make a simple image viewer application using Electron and with the possibility to edit images. I am using CamanJS for image manipulation effects but I have a small problem. When I load the folder with all images, I can scroll through them, also, I can apply some filters to image number 3 for example, save it and scroll no next one. But when I am trying to edit another image, say number 5, when I press the button it renders the image nr 3 and apply the effects to image nr 3. I have tried to resolve this bug but with no success. Can someone help me? Bellow is some code.
Here is the image on the "web page"
<canvas id="currentImage" class="img-thumb center"></canvas>
I have an array of indexes with images from the folder and I iterate through it to change the image that is displayed. Below is the function how I change the image:
var onPreviousClick = function() {
var currentImageId = $currentImage.data('currentIndex');
if (currentImageId > 0) {
showImage(--currentImageId);
}
};
And this is how I apply the Lomo effect to the image:
$lomobtn.on('click', function() {
Caman('#currentImage', function() {
this.lomo().render();
});
});
I suppose that is something related to this. First time when I press the button it references to the first image, and second time when I press the button it also references to the first image.
UPDATE
I find out that I have to use the function reloadCanvasData() to refresh the data from canvas, but I can't find out how to use this function. https://github.com/meltingice/CamanJS/blob/master/src/core/caman.coffee#L387-L392
Can someone help me to use this function? Tried different methods to call this function and I receive and error.
This is a few months old question, but hopefully still relevant for you or someone else.
I had the same issue. Just use it like this:
$lomobtn.on('click', function() {
Caman('#currentImage', function() {
this.reloadCanvasData() // <--- here, before you apply your filter
this.lomo().render();
});
});

Getting a Callback after visjs finishes loading chart

I'd like to get a callback from visjs after it finishes loading a chart so I can then unhide the chart and stop a loading animation. However, i don't see anyway to registrar a callback in the docs.
Now, I'm new to javascript so perhaps i'm not thinking about this correctly? Hoping someone can point me in the right direction. Thanks!
I'm one of the creators of vis.js.
The visualizations of vis.js should load synchronously so there is no need for a callback. After checking though for the Timeline and Graph2d I saw this is not the case anymore, this is no intentional behavior. I've opened an issue for this here: https://github.com/almende/vis/issues/1541
I don't know which visualization you're using, but a workaround for the Timeline and Graph2d is: the visualization is loaded synchronously, and the items are loaded on the next tick. So you can set a callback on a timeout after 0 ms:
var timeline = new vis.Timeline(...);
alert('The Timeline is visible but the items not yet (this is a bug)')
setTimeout(function () {
alert('Now everything is loaded!');
}, 0);
i solved the trouble with change event on first show.
var firstshow=true;
$scope.timeline.on("changed", function (properties) {
if(firstshow)
{
$scope.timeline.focus($scope.timeline.getVisibleItems());
firstshow=false;
}
The solution that worked for me was this:
timeline.on('finishedRedraw', function() {
console.log('do something');
});
Seems this still hasn't been fixed. You can also hook into the currentTimeTick Timeline event. Note this events keep triggering so you can unsubscribe after the first time it triggers.
this.timeline.on("currentTimeTick", (prop) => {
// Do something here
// After fired the first time we un-subscribed
this.timeline.off("currentTimeTick")
})

Override js-events

It's a long shot which is not that investigated yet, but I'm throwing the question while I'm looking for answers to hopefully get on the right track.
Building a Wordpress site with the theme Dante. This has an image slider function for products, handled in jquery.flexslider-min.js. In my first attempt i used wp_dequeue_script( 'sf-flexslider' ); to stop using this, and then added my own js which works perfect. The problem, however, is that in the bottom of the page there's another slider for displaying other products that uses this file, so i can not simply just dequeue this script.
I've tried to put my js-file both before and after the jquery.flexslider-min.js but this is always the primary. It there a way to, in my js-file, do something like "for obects in [specified div], skip instructions from jquery.flexslider-min.js"?
EDIT: Found this thread and tried the .remove() and the .detach() approach and add it again, but this makes no difference.
I really want to get rid of that flexslider on this particullar object. I can, of course, "hack" the output and give the flexslider item another class or something, but that would bring me so much work i don't have time for.
Maybe, You can monkey patch the flexslider behavior. There's a good tutorial here:
http://me.dt.in.th/page/JavaScript-override/
Something like:
var slider = flexSlider;
var originalSlide = slider.slide;
slider.slide= function() {
if ( some condition) {
// your custom slide function
} else {
// use default behavior
originalSlide.apply(this, arguments);
}
}

Categories

Resources