I have a panel within which I have two more panels. When you click on panel1 then information in panel2 is loaded. Since the information is quite huge there is some delay when its being loaded. During this interim period I wish to add a loading mask which intimates the user that its getting loaded.
For the same I have done this:
var myMask = new Ext.LoadMask(Ext.getCmp('eventsPanel'), {
msg:"Please wait..."
});
myMask.show();
// eventsPanel is the main panel under which panel1 and panel2 lie.
// This code is in the selectionchange listener of panel1 whose code
// is inside the main eventsPanel code.
However, nothing is being displayed on the screen. Its still the same, i.e., for some amount of time the screen freezes and then after a delay of like 2-3 seconds the information is loaded. Can you please advise as to where am I going wrong?
I would suggest you to first show your masking like the way you are doing:
var myMask = new Ext.LoadMask(Ext.getCmp('eventsPanel'), {
msg:"Please wait..."
});
myMask.show();
Then make a delayed task
var task = new Ext.util.DelayedTask(function(){
//your loading panel2 with heavy data goes here
myMask.hide();
});
//start the task after 500 miliseconds
task.delay(500);
This should solve your problem.
I make a custom mask as follows:
var componentToMasK = Ext.ComponentQuery.query('#myChildComponent')[0];
var customMask = Ext.get(componentToMasK.getEl()).mask('My mask text...');
var task = new Ext.util.DelayedTask(function() {
customMask.fadeOut({
duration : 500,
remove:true
});
});
task.delay(1000);
Normally when a event is triggered in a first component, caused, for example, the loading of a grid in the second component, the mask appears in both components in order to avoid user errors by clicking on the first component as the second component is loading the grid or is loading the mask.
In this case:
var componentToMasK = Ext.ComponentQuery.query('#myParentComponent')[0]; //HBox, BBox layout, tab, etc. with the two child components
Hope this helps!
Edit: 10-06-2015
The 'duration:500' and the 'delay(1000)' is only to illustrate. You can adjust these values to the needs of each component that you apply a mask.
If you remove the mask abruptly the user can not even see
loading the message, that's why I use fadeOut.
Thus, you can apply a mask on virtually any component such as, for example, a fieldset, when you add it fields dynamically.
task -> http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.util.DelayedTask
Ex.get -> http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext-method-get
fadeOut - > http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.dom.Element-method-fadeOut
You can also do the following:
var task = new Ext.util.DelayedTask(function() {
Ext.getBody().unmask();
});
task.delay(1000);
You can read more about this technique in the book: Mastering Ext JS - Second Edition (Loiane Groner)
Edit: 10-06-2015
One more detail:
If we apply one mask on a Hbox layout, containing as one of the childs a grid, we have two mask: HBOX mask and grid mask.
In these cases, I turn off dynamically the grid mask:
var grid = Ext.ComponentQuery.query('#griditemId')[0];
if(grid){
grid.getView().setLoading(false);
}
Hope this helps.
Related
I'm trying to implement a page with infinite scroll and add tooltips to some items. Infinite scroll works fine, but tooltips only appear on the first page, before adding new items with the scroll. This is the example:
https://stage.superbiajuridico.es/news/
The tooltip is in the small yellow circle, when placing the cursor over it. If you scroll down, in the following pages, the rest of the tooltips are not built, although I'm using the append event to build them each time the page is reloaded.
Apparently the code is very simple and I do not know what I'm doing wrong:
// TOOLTIPS
// ------------------
var miTootip = $('.tooltip-item');
new Tooltip(miTootip, {
// options
});
// INFINITE SCROLL
// ------------------
var inf = $('.infinite-scroll-container').infiniteScroll({
// options
});
inf.on('append.infiniteScroll', function(event, response, path, items) {
// THIS IS THE PART THAT DOESN'T WORK
new Tooltip(miTootip, {
// options
});
});
This is not working. I'have not much experience with JS so I think I'm doing wrong something obvious.
EDIT: When trying to codepen, I realized that the error is elsewhere. The tooltip only appears in the first item (it does not have to do with infinite-scroll). This is the pen: https://codepen.io/aitormendez/pen/yRGyZW
As I understand, your new Tooltip(miTootip) takes HtmlElement and replaces with tooltip. So in your append.infiniteScroll event's callback you have to add element with class .tooltip-item, and then create Tooltip.
UPD
You selected .tooltip-item and with this element, using Tooltip constructor, created tooltip, just for one item. So, if you want this tooltip for all items, that this tooltip need, you have to do smth like that:
inf.on('append.infiniteScroll', function(event, response, path, items)
{
$('.infinite-scroll-container').append('<div class="tooltip-item"></div>')
const miTooltip = $('.tooltip-item')
new Tooltip(miTooltip, {
// options
});
});
Tooltips must to be created iterating the jQuery object with a loop.
let myTooltip = $('.tooltip-item');
myTooltip.each(function(){
new Tooltip(this, {
title: "Tooltip",
trigger: "hover",
});
})
I am new to D3 /Javascript / html and I just made my first interactive viz. Its 93% done, but I have coded myself into a corner. There is a toggle switch on the graph which changes the numbers from counts to percentages. When the toggle is switched the graph appears, but I can't figure out how to get the graph to render upon loading without the click event while maintaining the functionality of the toggle feature which happens to load the data.
The likely culprits are here:
document.addEventListener('DOMContentLoaded', function () {
//Initialize with vanilla counts
var fileName = "data.csv"
var checkbox = document.querySelector('input[type="checkbox"]');
checkbox.addEventListener('change', function () {
if (checkbox.checked) {
The full code is available here:
https://www.philippou.us/jensweb/interactive_viz.html
How can I get my D3 graph to load without someone clicking on the toggle switch?
Put all the code after "checkbox.addEventListener('change', function () {", i.e., from "if (checkbox.checked) {" down, into a function, e.g., "function drawGraph() { ...}". Calling the function in the change event will be exactly what you're doing now. Then add a call to the function at the end of loading the page, e.g., "[script]drawGraph();[/script]" just before the "[/body]" statement. (Note: I'm using square brackets rather than angle brackets around script and body because they don't display otherwise and I don't know how to make them display. Sorry.)
Here is what should happen:
I have a button with a label and an icon.
When I tap the button some actions will take place which will take some time. Therefore I want to replace the icon of the button with some loading-icon during the processing.
Normal Icon:
Icon replaced by loading gif:
So in pseudo code it would be:
fancyFunction(){
replaceIconWithLoadingIcon();
doFancyStuff();
restoreOldIcon();
}
However the screen isn't updated during the execution of the function. Here ist my code:
onTapButton: function(view, index, target, record, event){
var indexArray = new Array();
var temp = record.data.photo_url;
record.data.photo_url = "img/loading_icon.gif";
alert('test1');
/*
* Do magic stuff
*/
}
The icon will be replaced using the above code, but not until the function has terminated. Meaning, when the alert('1') appears, the icon is not yet replaced.
I already tried the solution suggested here without success.
I also tried view.hide() followed by view.show() but these commands weren't executed until the function terminated, too.
Let me know if you need further information. Any suggestions would be far more than welcome.
I finally found a solution displaying the mask during my actions are performed. The key to my solution was on this website.
In my controller I did the following:
showLoadingScreen: function(){
Ext.Viewport.setMasked({
xtype: 'loadmask',
message: 'Loading...'
});
},
onTapButton: function(view, index, target, record, event){
//Show loading mask
setTimeout(function(){this.showLoadingScreen();}.bind(this),1);
// Do some magic
setTimeout(function(){this.doFancyStuff(para,meter);}.bind(this),400);
// Remove loading screen
setTimeout(function(){Ext.Viewport.unmask();}.bind(this),400);
},
The replacing of the icons worked quite similar:
onTapButton: function(view, index, target, record, event){
//Replace the icon
record.data.photo_url = 'img/loading_icon.gif';
view.refresh();
// Do some magic
setTimeout(function(){this.doFancyStuff(para,meter);}.bind(this),400);
},
doFancyStuff: function(para, meter){
/*
* fancy stuff
*/
var index = store.find('id',i+1);
var element = store.getAt(index);
element.set('photo_url',img);
}
Thank you for your help Barrett and sha!
I think the main problem here is that your execution task is executing in the main UI thread. In order to let UI thread do animation you need to push your doFancyStuff() function into something like http://docs.sencha.com/touch/2.2.1/#!/api/Ext.util.DelayedTask
Keep in mind though, that you would need to revert it your icon only after fancy stuff is complete.
To update any button attributes you shoudl try to access the button itself. Either with a ComponentQuery or through the controllers getter. For Example:
var button = Ext.ComponentQuery.query('button[name=YOURBUTTONNAME]')[0];
button.setIcon('img/loading_icon.gif');
that shold update your button's icon.
also when you get a ref to the button you will have access to all the methods availble to an Ext.Button object:
http://docs.sencha.com/touch/2.2.1/#!/api/Ext.Button-method-setIcon
Heyho,
I´am working on a project in my university and I´d like to use "Hammer.js".
I´ve downloaded the Carousel-Example and it works perfectly for me.
But I would like to start a the middle pane of my code and it´s not so simple I think.
It´s something like this:
http://img203.imageshack.us/img203/6326/schemeas.jpg
so Hammer.js starts always with the green screen. But I like to start with the yellow one.
I´ve added one swipe right to the init function but it looks horrible when the page is loading and could not be the goal ^^
I hope anyone of you have an idea how to solve my problem.
Try calling
carousel.showPane(1);
That will display the second pane instantly. You will want to put this near the bottom, right after where it says.
carousel.init();
If you're feeling adventurous you could try and make it automatically start with that pane as there's a variable inside the Carousel function called current_pane which is set to a default of 0 (the first pane). Altering this may work too but might require more code somewhere else. Experiment!
edit
NULL is right, it does animate it. Here's a more in depth method to set it without animation:
I found that the method responsible for changing which pane is showing was the setContainerOffset mthod which could be passed a variable to animate it. I previously told you to use showPane(2) but that then called
setContainerOffset(offset, true)
which caused the animation occur. What you should do instead is make a slightly different version of showPane...
this.setPane = function( index ) {
// between the bounds
index = Math.max(0, Math.min(index, pane_count-1));
current_pane = index;
var offset = -((100/pane_count)*current_pane);
setContainerOffset(offset, false);
};
You'll find it's almost identical to showPane except for the name and the fact that it calls setContainerOffset with animation: false. This will immediately show the pane of your choice and can be called using
carousel.setPane(index);
What I've done is added this to the init function so that it looks like this:
this.init = function() {
setPaneDimensions();
var c = this;
$(window).on("load resize orientationchange", function() {
setPaneDimensions();
c.setPane(current_pane);
//updateOffset();
})
};
Now you can change
var current_pane = 0;
to whatever you want and the carousel will always start with that pane when it's initialised! simple!
I'm currently working on a web application which has a page which displays a single chart (a .png image). On another part of this page there are a set of links which, when clicked, the entire page reloads and looks exactly the same as before except for the chart in the middle of the page.
What I want to do is when a link is clicked on a page just the chart on the page is changed. This will speed things up tremendously as the page is roughly 100kb large, and don't really want to reload the entire page just to display this.
I've been doing this via JavaScript, which works so far, using the following code
document.getElementById('chart').src = '/charts/10.png';
The problem is that when the user clicks on the link, it may take a couple of seconds before the chart changes. This makes the user think that their click hasn't done anything, or that the system is slow to respond.
What I want to happen is display a spinner / throbber / status indicator, in place of where the image is while it is loading, so when the user clicks the link they know at least the system has taken their input and is doing something about it.
I've tried a few suggestions, even using a psudo time out to show a spinner, and then flick back to the image.
A good suggestion I've had is to use the following
<img src="/charts/10.png" lowsrc="/spinner.gif"/>
Which would be ideal, except the spinner is significantly smaller than the chart which is being displayed.
Any other ideas?
I've used something like this to preload an image and then automatically call back to my javascript when the image is finished loading. You want to check complete before you setup the callback because the image may already be cached and it may not call your callback.
function PreloadImage(imgSrc, callback){
var objImagePreloader = new Image();
objImagePreloader.src = imgSrc;
if(objImagePreloader.complete){
callback();
objImagePreloader.onload=function(){};
}
else{
objImagePreloader.onload = function() {
callback();
// clear onLoad, IE behaves irratically with animated gifs otherwise
objImagePreloader.onload=function(){};
}
}
}
You could show a static image that gives the optical illusion of a spinny-wheel, like these.
Using the load() method of jQuery, it is easily possible to do something as soon as an image is loaded:
$('img.example').load(function() {
$('#spinner').fadeOut();
});
See: http://api.jquery.com/load-event/
Use the power of the setTimeout() function (More info) - this allows you set a timer to trigger a function call in the future, and calling it won't block execution of the current / other functions (async.).
Position a div containing the spinner above the chart image, with it's css display attribute set to none:
<div> <img src="spinner.gif" id="spinnerImg" style="display: none;" /></div>
The nbsp stop the div collapsing when the spinner is hidden. Without it, when you toggle display of the spinner, your layout will "twitch"
function chartOnClick() {
//How long to show the spinner for in ms (eg 3 seconds)
var spinnerShowTime = 3000
//Show the spinner
document.getElementById('spinnerImg').style.display = "";
//Change the chart src
document.getElementById('chart').src = '/charts/10.png';
//Set the timeout on the spinner
setTimeout("hideSpinner()", spinnerShowTime);
}
function hideSpinner() {
document.getElementById('spinnerImg').style.display = "none";
}
Use CSS to set the loading animation as a centered background-image for the image's container.
Then when loading the new large image, first set the src to a preloaded transparent 1 pixel gif.
e.g.
document.getElementById('mainimg').src = '/images/1pix.gif';
document.getElementById('mainimg').src = '/images/large_image.jpg';
While the large_image.jpg is loading, the background will show through the 1pix transparent gif.
Building on Ed's answer, I would prefer to see something like:
function PreLoadImage( srcURL, callback, errorCallback ) {
var thePic = new Image();
thePic.onload = function() {
callback();
thePic.onload = function(){};
}
thePic.onerror = function() {
errorCallback();
}
thePic.src = srcURL;
}
Your callback can display the image in its proper place and dispose/hide of a spinner, and the errorCallback prevents your page from "beachballing". All event driven, no timers or polling, plus you don't have to add the additional if statements to check if the image completed loading while you where setting up your events - since they're set up beforehand they'll trigger regardless of how quickly the images loads.
Some time ago I have written a jQuery plugin which handles displaying a spinner automatically http://denysonique.github.com/imgPreload/
Looking in to its source code should help you with detecting when to display the spinner and with displaying it in the centre of the loaded image.
I like #duddle's jquery method but find that load() isn't always called (such as when the image is retrieved from cache in IE). I use this version instead:
$('img.example').one('load', function() {
$('#spinner').remove();
}).each(function() {
if(this.complete) {
$(this).trigger('load');
}
});
This calls load at most one time and immediately if it's already completed loading.
put the spinner in a div the same size as the chart, you know the height and width so you can use relative positioning to center it correctly.
Aside from the lowsrc option, I've also used a background-image on the img's container.
Be aware that the callback function is also called if the image src doesn't exist (http 404 error). To avoid this you can check the width of the image, like:
if(this.width == 0) return false;
#iAn's solution looks good to me. The only thing I'd change is instead of using setTimeout, I'd try and hook into the images 'Load' event. This way, if the image takes longer than 3 seconds to download, you'll still get the spinner.
On the other hand, if it takes less time to download, you'll get the spinner for less than 3 seconds.
I would add some random digits to avoid the browser cache.