change bootstrap button text before rendering d3 svg object - javascript

I've got code aimed at visualizing some complex data. The user first selects a data file to load; after clicking the load button, the page generates a "plot" button with an onclick event handler with the function renderPlots().
When the user clicks the "plot" button, then all the plots are properly generated and I'm happy. However, in the case of a larger data set, the plotting process may take a few seconds so I'd like to change the button text to something like "rendering..." while the plots are being generated so that the user knows their plots are on the way.
As per the bootstrap documentation for dynamically changing button text, I've tried something like
function renderPlots() {
$("#render").button("loading");
rest of code that does all the D3 plot generating...;
$("#render").button("reset");
}
The problem with the above code is that it doesn't actually change the button text first, it's doing things asynchronously and I'm at a loss of how I can force the button text to change on screen before any plotting actually starts.
Any thoughts?

Actually, if I understood the issue, stuff is running synchronously — not asynchronously — which is why the browser doesn't get a chance to refresh the DOM with the new button text prior to starting the big processing task. If you were to console.log the button text somewhere between the two calls to .button() you'd see that the text is set to "loading"; it just doesn't appear yet.
If so, then using setTimeout to delay the start of processing until the next "frame" will fix the issue:
function renderPlots() {
$("#render").button("loading");
setTimeout(function() {
// rest of code that does all the D3 plot generating...;
$("#render").button("reset");
}, 100); // even 0 will do the trick
}

Related

Changes made by Jquery to CSS in Laravel/FancyTree is only reflected at the end of the function

I currently have a fancy tree where when activating a node, it will run through a bunch of ajax/backend code which consumes time.
Desired outcome:
When clicking on a node, the active event handler should catch the event and display a loading icon until all the following code is completed before the loading icon is removed however, the CSS changes made by the jquery is not running until after the function is already completed even though the jquery command has already been called prior to the additional set of ajax and backend code. This results in the loader not being reflected at all.
Poor solution:
Setting a windows timeout between the toggling of the visibility of the loader allows the loader to actually be reflected onto the screen before removing it again.
activate: function(event, d) {
console.log('make loader appear');
$('#loader').css('display','block')
//bunch of random code here
$('#loader').css('display','none')
}
I think that probably because after you show the loading indicator you hide it right away.
See your code in event activate function :
$('#loader').css('display','block') //bunch of random code here $('#loader').css('display','none')

Infinite loop when overriding graphHandlerMouseUp on MxGraph using Angular

I have a difficult question to explain and I'm way out of my comfort zone as far as expertise in Javascript, TrueType, Angular and MxGraph are concerned... Hope to be able to explain.
I have an Angular component displaying and MxGraph. I was able to integrate MxGraph with Angular following this link (How to integrate mxGraph with Angular 4?). Even if I use Angular 7, the solution still works...
The graph is displayed correctly on the page and everything works fine, including my override of the function graphHandlerMouseUp, which I do with this code:
// Save the position of the mouse when releasing the button: used for
// detecting the target in a drag and drop
mx.graphHandlerMouseUp = mx.mxGraphHandler.prototype.mouseUp;
mx.mxGraphHandler.prototype.mouseUp = function( graph, evt ) {
currentdropX = evt.graphX;
currentdropY = evt.graphY;
mx.graphHandlerMouseUp.apply(this, arguments);
}
When I run this page for the first time, no problem happens.
Then through a button I call a page with another component (through routing). If from this page I go back to the first component (again through a routerlink) the page and the component with the MxGraph loads correctly, BUT when I use this function (i.e., release the mouse button).
It seems to me a recoursive problem, as when I put a console output like this:
// Save the position of the mouse when releasing the button: used for
// detecting the target in a drag and drop
mx.graphHandlerMouseUp = mx.mxGraphHandler.prototype.mouseUp;
mx.mxGraphHandler.prototype.mouseUp = function( graph, evt ) {
currentdropX = evt.graphX;
currentdropY = evt.graphY;
// INIFINTE LOOP HERE
console.log("Test");
mx.graphHandlerMouseUp.apply(this, arguments);
}
The "Test" is written a number of times which is continuously growing. Yet, if I understood, this was the correct way of overriding the function. Of course on the first load of the page, "Test" is displayed once. Passing to another component and then back on this it is displayed an "infinite" number of times (until I reach the: "ERROR RangeError: Maximum call stack size exceeded")...
I tried also to remove that override, and besides the obvious lack of the functionality, the very same problem happened to the function "mxDragSource", which is overridden with the same approach.
As I said: I'm not expert enough in javascript, truetype, MxGraph or Angular, so any hint, even if obvious, is very welcome!
Thanks!
The first time you run your code, you store mx library's mouseUp event in a variable and you assign a new function to mouseUp event in which you call the old mouseUpEvent.
The second time you run your code, you store your current mouseUp event (that you have modified) and you assign a function in which you call the old mouseUpEvent, which is the same you stored previously. There goes your recursion !
What you need to do is override the third-party function properly, so you don't execute your code twice.
How to do it ?
You can create a mixin and use this mixin in your componentB/ If you have no idea what is it and how to do it, please reproduce your problem in a stackblitz I'll be glad to help you to implement it.

Remove background url but only AFTER an image has fully loaded

I am loading an image from the client side using createObjectURL. Sometimes, the image is big, so I wanted to put a "loading" animated gif in there.
I have a container div (fileDisplay) and an img (imgDisplay).
fileDisplay has the background set to the animated gif. So, as imgDisplay is loading a big file, you see the loading gif. When imgDisplay is done loading, it covers the gif. So, its still there, but you dont see. I figured that should be fine. All is well--as long as the img is a square, which distorts the img proportions.
But, if the image loaded into imgDisplay is resized with correct proportions and not square (fileDisplay dimensions are 45x45 pixles) you still see the gif in the background.
So what I need is to be able to turn off the animated gif (background url=none on fileDisplay), or cover it with another div, or something. But only when the image has fully loaded.
I can see by now, after trying everything I can think of, that there is no way to change backgrounds, turn divs on/off, etc and do this. It seems everything is processed and then the final results are all painted at once as opposed to incrementally as if it were, say, a VB app.
Can anyone help me with working out how to do this--I'm assuming it CAN be done. And I think the solution is "promise." I have looked for samples, read what I can find, but just can't seem to grasp it.
The "uploadButton on change" event fires this code:
imgSrc = window.URL.createObjectURL(this.files[0]);
//document.getElementById("imgDisplay" + justNumber).src = imgSrc;
getImgSize(imgSrc, useImgSize);
Where the commented line just displays the image as a 45x45. But the getImgSize function calculates the size and displays the image resized--which is when the problem occurs. Just try to load an image that is not square and you will see the issue.
A complete fiddle is here: https://jsfiddle.net/msith718/xfuv79b3/334/
So to do this you want to remove the gif/img element from the parent div when you load the new image into the div. Which you would do with the element.removeChild() function.
//Put this code as soon as you want to remove the loading gif
//This gets the node or the element you want to remove
var node = document.getElementById("gif");
//This removes the node from the parent div
document.getElementById("parentDiv").removeChild(node);
Here is one way of solving this problem https://jsfiddle.net/xfuv79b3/353/. Because you are wanting to change something after the image has loaded we need to add the code somewhere after the onload event has been called. I chose to pass in an id to my imgLoader that gets passed on to the callback that processes the image once loaded. Then finally use that id to modify the background of the div once the img element has loaded the new image. What you ne
getImgSize(imgSrc, useImgSize, justNumber);
//...
img.onload = function() {
fn({
width: img.width,
height: img.height
},id);
}
//...
document.getElementById("imgDisplay" + id).onload=function(){
document.getElementById('fileDisplay'+ id).style.background='none';
}
//Also to reset the background if upload is canceled
document.getElementById("fileDisplay" + justNumber).style.background = '';
Extra Note
From your reference to vb and painted I'm guessing your background is more geared towards a main loop that handles all of the interactions and holds all the data or state of your application. Javascript is very different from this in that user interactions happen through events which are asynchronous. This means data has to be explicitly passed around if need inside a certain callback.
Think about it like this. Your program starts in a resting state, but is listening for events that signal some change has happened. If an event happens (such as a user clicks a button) your program calls an event handler. This happens asynchronously meaning two things. One the only data available to it is the data passed into the handler and the data available from its parent scope. And two it means any subsequent actions or data processing have to be called from that event handler. So each event handler must perform all the actions needed and any state change updates to the program before returning to the resting state. Then your program waits for the next event.
This is very simplified (e.g. multiple events can be fired at the same time) and hopefully helpful, but once you get the hang of it javascript makes a whole lot more sense. I'd suggest reading up on event driven programming with javascript since I'm sure there are much better tutorials and explanations out there, but hopefully this gets you headed in the right direction.

Added data disappear

jQuery Core 3.1.0
Chrome, Firefox
Below is a model of jquery.ajax() success behaviour.
Shortly: I managed to fetch data via AJAX. In this model example the data is represented by "Just something" placeholder. Now I want to add the data to the document.
<script>
var add_date = $("#add_date");
function add_date_ajax(){
$('.frame_date').append("Just something");
debugger; // 1
}
debugger; // 2
add_date.click(add_date_ajax);
</script>
A problem: the data appear and then disappear in half a second.
I placed breakpoints.
When the page is loading, it stops at breakpoint 2. That is correct.
When I click #add_date element, the script stops at breakpoint 1. That is also correct.
But when I click "resume script execution", the script again goes to breakpoint 2. This seem strange to me. As if the page is reloaded. Maybe that is why the added text disappears.
Could you help me cope with the problem?
Added later:
https://jsfiddle.net/mv1yu3zw/1/
It disappears because you are reloading the page. The html
Add date
should be
Add date
To bind all your events, you should use the ready on document.
To avoid the reloading of your page (because of the href of the a tag), you have to call preventDefault or use a button.
You should write your code like this:
$(document).ready(function() {
$("#add_date").on("click", add_date_ajax);
});
function add_date_ajax(event) {
event.preventDefault();
$('.frame_date').append("Just something");
}

How to make jquery div replacement take effect instantly

I have a javascript function which creates an image dynamically, then shows that image either in a div or on a separate page.
Since the image creation takes a few seconds I'd like to display a simple 'please wait' message so that the user knows something is happening, and I am doing this by replacing the contents of an initially empty div with some text.
$('#chartImage').html('Please wait...');
This works fine on it's own - the div contents are displayed immediately when the triggering link is clicked. The problem is when I add the actual image creation code after it, the 'please wait' does not show up until after the image creation is complete, and only for a split second, so it's kinda pointless.
Is there something like a flush method to make sure all actions have taken effect before continuing?
Alternatively if there is a better way to do this I'm happy to hear it...
-------------EDIT-----------------
Here is a more complete description of what I'm doing, using open flash chart to make an image:
function createChartImage(chartid)
{
$('#chartImageDiv'+chartid).html('Please wait...');
ofc = findSWF("ofc_chart_"+chartid);
x = ofc.post_image( getUploadChartURL(chartid), 'doneChartUpload', false );
setTimeout("",1000); //allow some time for upload to complete
window.location.href = getViewChartImageURL(chartid);
}
The 'please wait' appears to take effect immediately before the final line. If I change the div's contents again at that point, the 'please wait' never shows at all.
(According to the docs for the charts I'm using, the function 'doneChartUpload' should be called when the upload is complete which would remove the need for the setTimeout, but I spent a long time trying to get it working, even copying code verbatim from the page below, to no avail.)
http://teethgrinder.co.uk/open-flash-chart-2/adv-upload-image.php
From assessing your code i would definitely split it up:
function generateChartImageProcess(chartid){
displayLoader();
createChart(chartid);
}
function createChart(chartID){
ofc = findSWF("ofc_chart_"+chartid);
x = ofc.post_image( getUploadChartURL(chartid), 'doneChartUpload', false );
setTimeout("",1000); //these two lines here to be replaced by your chart generations complete process
window.location.href = getViewChartImageURL(chartid);
}
function displayLoader(){
$('#chartImageDiv'+chartid).html('Please wait...');
}
function chartGeneratedComplete(arguments){
//TODO
}
This happens because the image isn't loaded yet, and it takes some time for the browser to load it before it can be displayed.
You could try using the jquery.load() method to add a callback for the event of the image being loaded like this, (supposing the div containing the image has the id #imageContainer):
$('#imageContainer img').load(function() {
// Remove the Please wait
});
BlockUI is a good tool to use for these situations: http://jquery.malsup.com/block/. In both cases (using BlockUI or rolling your own), trigger the "waiting" code first, run your image generator, and then remove the waiting effect after the image is loaded.

Categories

Resources