Check if tiles are loading - javascript

I am using OL-layerswitcher (https://github.com/walkermatt/ol-layerswitcher) to produce a sidebar with my layers and add them to the map when clicking. Unfortunately, this might take some time depending on the internet connection, etc. and thus I would like to add an icon showing that something is happening while it is loading.
I managed to create a div in the middle of my screen showing the icon I want to show but I am not able to check if something is still loading or not.
Since I am using the layerswitcher, my layers are not clearly defined as variables (like in https://openlayers.org/en/latest/examples/tile-load-events.html), thus I can not use the example.
If anyone can help me, thank you.
EDIT: I am trying to get this running with a single layer.Tile now. I thought if i do it like this and add the source-Layer to my map I should get a console-output "Loading" and then "Done", but I do not get an output.
var source = new ol.layer.Tile({
title: "Baden-Württemberg",
zIndex: 2,
visible: false,
source: new ol.source.TileWMS({
url: "https://forestwatch.lup-umwelt.de/app/ows/index.php/geoserver/forestwatch/wms?",
params: {
'LAYERS': "forestwatch:baden_wuertemberg_maske"
}
})
})
var IMG = document.getElementById("loading");
source.on('tileloadstart', function () {
console.log("Loading");
});
source.on('tileloadend', function () {
console.log("Done");
});
PS: I do not really care if I have to use jquery, if there is a solution using it just tell me.
Edit: #Mike made this work using source.getSource().on( ), but right now my map is jumping.
#loading {
position: relative;
display: none;
font-size: 40px;
left: 50%;
top: 50%;
z-index: 10000;
/* width: 30px;
height: 30px;*/
background-color: transparent;
color: black;
}
This is the css for the div. EDIT: position: fixed made it work since it is always in the same position now.

Related

Prevent JavaScript/jQuery from reacting to mouse from under a higher stacked div

I'm running this plugin in WordPress that makes pretty image maps with shapes over images. It uses JS/jQuery extensively. I've used a custom script to show/hide a div when I click a shape. This particular div is stacked above the div that contains the image map. It appears and disappears just fine, but when I mouse over it and/or click on it, for some weird reason the hovers and clicks get through the higher stacked div down to the map div while still working on the popover one. Here's a simplified version of how things are set up:
function toggle_visibility(id) {
var e = document.getElementById(id);
if (e.style.opacity == '1')
setTimeout(() => {
e.style.opacity = '0';
}, this.animationDelay + 2),
setTimeout(() => {
e.style.zIndex = '-30';
}, 400);
else
e.style.zIndex = '999999999',
setTimeout(() => {
e.style.opacity = '1';
}, this.animationDelay + 2);
}
.city {
position: relative;
}
#ipano {
position: fixed;
min-width: 90vw;
left: 5vw;
top: 50%;
transform: translateY(-50%);
opacity: 0;
z-index: -30;
}
<div class="city">
// map code
</div>
<div id="ipano">
//popup code
</div>
The map plugin allows me to assign onClick code to any shape defined, so I added this to make a click on the shape reveal the hidden div like so: toggle_visibility('ipano'); javascript:event.preventDeafult();.
But even if I remove my custom script for revealing the #ipano div, the problem still persists. You can see it in action here.
I think this is somehow due to the map script and how it handles the mapping of the overlay map regions (with an .svg), but I can't put my finger on it.
I've tried changing the divs' order, removing the preventDefault bit, and adding pointer-events: none; to some and all the map's elements, but that didn't help. How's that even possible?
Any suggestions in the right direction greatly appreciated, thank you!

What is missing within my javascript for a disappearing navbar?

I want to avoid jQuery so I can get a better feel for Javascript. For now I have a Codepen set up that displays a large majority of my first project. I know the code is probably sloppy and I am a beginner. I simply want to get the JS working with my navbar completely disappearing onScroll then I will optimize it from there. Thanks!
I have searched youtube, google, SO but everyone seems to use jQuery.
https://codepen.io/dev20tx/pen/wbKyJq
The CSS:
.nav {
border-bottom: 1px solid #EAEAEB;
text-align: right;
height: 70px;
line-height: 70px;
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: white;
opacity: 0.8;
z-index: 2;
}
And the Javascript:
window.onscroll = function() {navFunction()};
function navFunction() {
if (document.body.scrollTop > 50 ||
document.documentElement.scrollTop > 50) {
document.queryselector(".nav").className = "test";
} else {
document.queryselector(".nav").className = "";
}
}
Disappearing navbar.
I've updated the codepen at https://codepen.io/anon/pen/rgOdXy
Following is the updated JavaScript code, first problem was that you was attaching event listener to window, instead of the element which is to be scrolled and second mistake was the spelling mistake of querySelector method
function navFunction(e) {
if (e.target.scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.querySelector(".nav").className = "nav test";
} else {
document.querySelector(".nav").className = "nav";
}
}
document.querySelector(".container").addEventListener("scroll",navFunction);
Allright, so, few things.
First, queryselector should be querySelector (with a capital S). Also note that setting the .nav's className to "test" or "" will remove the "nav" class from that element.
Second, you should make sure you attach the onscroll event after the page has loaded.
Lastly, you're attaching the onscroll event to the window, but you actually want to attach it to the .container element, as that's the element you're scrolling.
I'm not just throwing the entire solution in your lap, as you seem to want to play around yourself a little bit. If you do want a more elaborate answer, don't hesitate to ask.

jQuery slide animation on existing divs after prependTo

I have this semi-slider-style UI where new terms are added in from the left: http://jsfiddle.net/v4v5cvkz/. I'm using the jQuery prependTo function to do this. My issue is that I want the terms that are already displayed to perform an animated slide to the right when a new term gets added, rather than suddenly "appear" in the correct position. I did try adding a "displayed" class to terms that had successfully shown up, and tried adding a slide-to-right animation after that, but that didn't quite achieve the effect I was going for (the "displayed" objects were moved much further to the right than I expected).
Here is the problematic code (you'll probably want to view the fiddle to see it in context though):
function addToStream(term, delay) {
setTimeout(function(){
$("<div />")
.addClass("stream_term")
.html(term)
.css({
opacity: 0
})
.prependTo("#stream_terms")
.animate({opacity:1},
{ duration: 1000,
complete: function() {
$(this).addClass("displayed");
}
});
}, delay);
}
Any help here would be greatly appreciated. Thank-you!
*Note: I have access to jQuery UI in my code, though it isn't linked in the fiddle. Also, if anyone knows of a plugin that can do this sort of thing better than I can, please let me know. The closest one I was able to find was Fraction Slider, but I didn't find it obvious how to create a similar UI with it (it might also be overkill for my purposes).
Here's a way to do it:
function addToStream(term, delay) {
setTimeout(function(){
var newDiv = $("<div />");
newDiv.addClass("stream_term")
.html(term)
.css({
opacity: 0,
display: 'none'
}).prependTo("#stream_terms");
var width = newDiv.width();
var height = newDiv.height();
newDiv.css({
width: 0,
height: height,
display: 'inline-block'
})
.animate({
width: width,
margin: '0 10px',
padding: '5px 10px'
}, 1000)
.animate({opacity: 1}, 1000, function(){
$(this).addClass("displayed");
});
}, delay);
}
It also needs the following CSS changes:
.stream_term {
padding: 0;
margin: 0;
overflow: hidden;
}
DEMO: http://jsfiddle.net/StathisG/hqg29p6r/1/

ExtJS4 splash screen app.js returns error

I have a initially long loading app, so I tried making a splash screen. It "almost" works perfectly. I'm getting the following error: Uncaught TypeError: Cannot read property 'style' of undefined which points to a specific line in my app.js. However, I just can't see what's wrong with it. The splash screen loads fine and fades out fine (almost). What I notice is that it appears the div I created is still there yet you can't see it but it's still masking the body from input. Here's my app.js:
Ext.Loader.setConfig({
enabled: true
});
var splashscreen;
Ext.onReady(function () {
// Start the mask on the body and get a reference to the mask
splashscreen = Ext.getBody().mask('Dashboard Loading...', 'splashscreen');
// Add a new class to this mask as we want it to look different from the default.
splashscreen.addCls('splashscreen');
// Insert a new div before the loading icon where we can place our logo.
Ext.DomHelper.insertFirst(Ext.query('.x-mask-msg')[0], {
cls: 'x-splash-icon'
});
});
Ext.create('Ext.app.Application', {
controllers: ['Main'],
stores: ['Saless', 'ProdGrid002s', 'ProdGrid008s', 'ProdGrid009s', 'Unitcosts', 'Prepaids',
'Logintakes', 'WasteTickets', 'InventoryFinisheds', 'InventoryRoughs', 'Shipments'],
name: 'Dash1',
appFolder: '/html/cgi-dev/millapps/dashboards/Dash1/app',
launch: function () {
// Setup a task to fadeOut the splashscreen
var apptask = new Ext.util.DelayedTask(function () {
// Fade out the body mask
splashscreen.fadeOut({
duration: 2000,
remove: true
});
// Fade out the icon and message
splashscreen.next().fadeOut({
duration: 2000,
remove: true,
listeners: {
afteranimate: function () {
// Set the body as unmasked after the animation
Ext.getBody().unmask();
}
}
});
});
// Run the fade after launch.
apptask.delay(1000);
},
autoCreateViewport: true
});
my style sheet:
.x-mask.splashscreen {
background-color: white;
opacity: 1;
}
.x-mask-msg.splashscreen,
.x-mask-msg.splashscreen div {
font-size: 18px;
padding: 110px 110px 50px 110px;
border: none;
background-color: transparent;
background-position: top center;
}
.x-message-box .x-window-body .x-box-inner {
min-height: 200px !important;
}
.x-splash-icon {
/* Important required due to the loading symbols CSS selector */
background-image: url('/resources/images/logo.jpg') !important;
margin-top: -30px;
margin-bottom: 20px;
}
The error points to the line of code Ext.getBody().unmask(); which is in the afteranimate function. I'm stumped.....
Unrelated, but you've got a race condition in that code that made you error hard to reproduce. I've had to delay the Ext.getBody().unmask() call to trigger it.
The problem is that your anims are destroying the DOM elements that the unmask method tries to access, because of the remove: true options. However, since Ext keeps track of the mask internally, you are indeed required to call unmask() to avoid unpredictable behaviors later on.
So the solution is simply to remove the two remove: true lines in your anims config, and unmask will take care of disposing of the DOM elements itself.

Wait cursor over entire html page

Is it possible to set the cursor to 'wait' on the entire html page in a simple way? The idea is to show the user that something is going on while an ajax call is being completed. The code below shows a simplified version of what I tried and also demonstrate the problems I run into:
if an element (#id1) has a cursor style set it will ignore the one set on body (obviously)
some elements have a default cursor style (a) and will not show the wait cursor on hover
the body element has a certain height depending on the content and if the page is short, the cursor will not show below the footer
The test:
<html>
<head>
<style type="text/css">
#id1 {
background-color: #06f;
cursor: pointer;
}
#id2 {
background-color: #f60;
}
</style>
</head>
<body>
<div id="id1">cursor: pointer</div>
<div id="id2">no cursor</div>
Do something
</body>
</html>
Later edit...
It worked in firefox and IE with:
div#mask { display: none; cursor: wait; z-index: 9999;
position: absolute; top: 0; left: 0; height: 100%;
width: 100%; background-color: #fff; opacity: 0; filter: alpha(opacity = 0);}
<a href="#" onclick="document.getElementById('mask').style.display = 'block'; return false">
Do something</a>
The problem with (or feature of) this solution is that it will prevent clicks because of the overlapping div (thanks Kibbee)
Later later edit...
A simpler solution from Dorward:
.wait, .wait * { cursor: wait !important; }
and then
Do something
This solution only shows the wait cursor but allows clicks.
If you use this slightly modified version of the CSS you posted from Dorward,
html.wait, html.wait * { cursor: wait !important; }
you can then add some really simple jQuery to work for all ajax calls:
$(document).ready(function () {
$(document).ajaxStart(function () { $("html").addClass("wait"); });
$(document).ajaxStop(function () { $("html").removeClass("wait"); });
});
or, for older jQuery versions (before 1.9):
$(document).ready(function () {
$("html").ajaxStart(function () { $(this).addClass("wait"); });
$("html").ajaxStop(function () { $(this).removeClass("wait"); });
});
I understand you may not have control over this, but you might instead go for a "masking" div that covers the entire body with a z-index higher than 1. The center part of the div could contain a loading message if you like.
Then, you can set the cursor to wait on the div and don't have to worry about links as they are "under" your masking div. Here's some example CSS for the "masking div":
body { height: 100%; }
div#mask { cursor: wait; z-index: 999; height: 100%; width: 100%; }
This seems to work in firefox
<style>
*{ cursor: inherit;}
body{ cursor: wait;}
</style>
The * part ensures that the cursor doesn't change when you hover over a link. Although links will still be clickable.
I have been struggling with this problem for hours today.
Basically everything was working just fine in FireFox but (of course) not in IE.
In IE the wait cursor was showing AFTER the time consuming function was executed.
I finally found the trick on this site:
http://www.codingforums.com/archive/index.php/t-37185.html
Code:
//...
document.body.style.cursor = 'wait';
setTimeout(this.SomeLongFunction, 1);
//setTimeout syntax when calling a function with parameters
//setTimeout(function() {MyClass.SomeLongFunction(someParam);}, 1);
//no () after function name this is a function ref not a function call
setTimeout(this.SetDefaultCursor, 1);
...
function SetDefaultCursor() {document.body.style.cursor = 'default';}
function SomeLongFunction(someParam) {...}
My code runs in a JavaScript class hence the this and MyClass (MyClass is a singleton).
I had the same problems when trying to display a div as described on this page. In IE it was showing after the function had been executed. So I guess this trick would solve that problem too.
Thanks a zillion time to glenngv the author of the post. You really made my day!!!
Easiest way I know is using JQuery like this:
$('*').css('cursor','wait');
css: .waiting * { cursor: 'wait' }
jQuery: $('body').toggleClass('waiting');
Why don't you just use one of those fancy loading graphics (eg: http://ajaxload.info/)? The waiting cursor is for the browser itself - so whenever it appears it has something to do with the browser and not with the page.
To set the cursor from JavaScript for the whole window, use:
document.documentElement.style.cursor = 'wait';
From CSS:
html { cursor: wait; }
Add further logic as needed.
Try the css:
html.waiting {
cursor: wait;
}
It seems that if the property body is used as apposed to html it doesn't show the wait cursor over the whole page. Furthermore if you use a css class you can easily control when it actually shows it.
Here is a more elaborate solution that does not require external CSS:
function changeCursor(elem, cursor, decendents) {
if (!elem) elem=$('body');
// remove all classes starting with changeCursor-
elem.removeClass (function (index, css) {
return (css.match (/(^|\s)changeCursor-\S+/g) || []).join(' ');
});
if (!cursor) return;
if (typeof decendents==='undefined' || decendents===null) decendents=true;
let cname;
if (decendents) {
cname='changeCursor-Dec-'+cursor;
if ($('style:contains("'+cname+'")').length < 1) $('<style>').text('.'+cname+' , .'+cname+' * { cursor: '+cursor+' !important; }').appendTo('head');
} else {
cname='changeCursor-'+cursor;
if ($('style:contains("'+cname+'")').length < 1) $('<style>').text('.'+cname+' { cursor: '+cursor+' !important; }').appendTo('head');
}
elem.addClass(cname);
}
with this you can do:
changeCursor(, 'wait'); // wait cursor on all decendents of body
changeCursor($('#id'), 'wait', false); // wait cursor on elem with id only
changeCursor(); // remove changed cursor from body
I used a adaptation of Eric Wendelin's solution. It will show a transparent, animated overlay wait-div over the whole body, the click will be blocked by the wait-div while visible:
css:
div#waitMask {
z-index: 999;
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100%;
cursor: wait;
background-color: #000;
opacity: 0;
transition-duration: 0.5s;
-webkit-transition-duration: 0.5s;
}
js:
// to show it
$("#waitMask").show();
$("#waitMask").css("opacity"); // must read it first
$("#waitMask").css("opacity", "0.8");
...
// to hide it
$("#waitMask").css("opacity", "0");
setTimeout(function() {
$("#waitMask").hide();
}, 500) // wait for animation to end
html:
<body>
<div id="waitMask" style="display:none;"> </div>
... rest of html ...
My Two pence:
Step 1:
Declare an array. This will be used to store the original cursors that were assigned:
var vArrOriginalCursors = new Array(2);
Step 2:
Implement the function cursorModifyEntirePage
function CursorModifyEntirePage(CursorType){
var elements = document.body.getElementsByTagName('*');
alert("These are the elements found:" + elements.length);
let lclCntr = 0;
vArrOriginalCursors.length = elements.length;
for(lclCntr = 0; lclCntr < elements.length; lclCntr++){
vArrOriginalCursors[lclCntr] = elements[lclCntr].style.cursor;
elements[lclCntr].style.cursor = CursorType;
}
}
What it does:
Gets all the elements on the page. Stores the original cursors assigned to them in the array declared in step 1. Modifies the cursors to the desired cursor as passed by parameter CursorType
Step 3:
Restore the cursors on the page
function CursorRestoreEntirePage(){
let lclCntr = 0;
var elements = document.body.getElementsByTagName('*');
for(lclCntr = 0; lclCntr < elements.length; lclCntr++){
elements[lclCntr].style.cursor = vArrOriginalCursors[lclCntr];
}
}
I have run this in an application and it works fine.
Only caveat is that I have not tested it when you are dynamically adding the elements.
BlockUI is the answer for everything. Give it a try.
http://www.malsup.com/jquery/block/
This pure JavaScript seems to work pretty well ... tested on FireFox, Chrome, and Edge browsers.
I'm not sure about the performance of this if you had an overabundance of elements on your page and a slow computer ... try it and see.
Set cursor for all elements to wait:
Object.values(document.querySelectorAll('*')).forEach(element => element.style.cursor = "wait");
Set cursor for all elements back to default:
Object.values(document.querySelectorAll('*')).forEach(element => element.style.cursor = "default");
An alternative (and perhaps a bit more readable) version would be to create a setCursor function as follows:
function setCursor(cursor)
{
var x = document.querySelectorAll("*");
for (var i = 0; i < x.length; i++)
{
x[i].style.cursor = cursor;
}
}
and then call
setCursor("wait");
and
setCursor("default");
to set the wait cursor and default cursor respectively.
Lots of good answers already, but none of them mentions the <dialog> element.
Using this element we can create a solution similar to the masking <div>.
Here we use showModal() to "hide" elements, and we use ::backdrop to set the cursor style to wait on the entire page:
function showWaitDialog() {
document.getElementById('id_dialog').showModal();
}
#id_dialog, #id_dialog::backdrop {
cursor: wait;
}
<button onclick="showWaitDialog()">click me</button>
<dialog id="id_dialog">busy...</dialog>
The dialog is hidden by default, and can be shown using either the show() method, or the showModal() method, which prevents clicking outside the dialog.
The dialog can be forced to close using the close() method, if necessary.
However, if your button links to another page, for example, then the dialog will disappear automatically as soon as the new page is loaded.
Note that the dialog can also be closed at any time by hitting the Esc key.
CSS can be used to style the dialog however you like.
The example uses the html onclick attribute, just for simplicity. Obviously, addEventListener() could also be used.
Late to the party but simply give the Html tag an id by targeting
document.documentElement
and in the CSS place at the top
html#wait * {
cursor: wait !important;
}
and simply remove it when you want to stop this cursor.

Categories

Resources