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.)
Related
I've got a container that includes several icons the user can hover over and be shown a block of text next to it. I'm grabbing the blocks of text from an array and have a randomize function so that they're always shown a different block of text when revisiting the page.
I ran into an issue where every time you hover over an icon, it keeps adding more array elements, because the function gets called each time you hover over the icon. So I decided to use the one() method so the function only runs once, however that's where my real issue is. Using the one() method doesn't show ANY text, and I'm pretty sure it's due to the nested function I have.
You can test this out here: http://www.evanvolmering.com/bootstrap/docs/examples/carousel/eyeswideshut.html
In the banner a video will play, and shortly into it a little icon will appear in the bottom of left of the banner. Hovering over it will show some text. When you hover over it again it adds another array item, and so on. It works, but I don't want it to keep adding array items.
10 seconds later another icon will appear to the top right, which currently has the one() method applied to it. As you can see nothing happens when you hover over it. Not sure where to go from here.
My randomize code (which I got from another StackOverflow answer):
var numRandoms = 14;
function makeUniqueRandom() {
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
uniqueRandoms.splice(index, 1);
return val;
}
My code which currently 'works' but keeps adding more array items on hover:
$('img.button1').hover(function(){
$('p.trivia1').fadeIn("slow");
$( 'p.trivia1' ).append(makeUniqueRandom());
},
function(){
$("p.trivia1").stop().fadeOut("slow");
});
My code that uses one() but doesn't do anything on hover:
$('img.button2').one("hover",function(){
$('p.trivia2').fadeIn("slow");
$( 'p.trivia2' ).append(makeUniqueRandom());
},
function(){
$("p.trivia2").stop().fadeOut("slow");
});
Use mouseenter/mouseleave instead of hover
$('img.button1').on('mouseenter',function(){
$('p.trivia1').fadeIn("slow");
$( 'p.trivia1' ).append(makeUniqueRandom());
}).on('mouseleave',function(){
$("p.trivia1").stop().fadeOut("slow");
});
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.
I have implemented a simple bar chart,
ive added tooltip feature using highlighter but i am facing an issue with the same.
When i move the mouse down and exit the chart canvas the tooltip doesnt dismiss
I have tried adding
$.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
$.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMove]);
But it doesnt work , i get the error handleMove is not defined
Here is the code fiddle for the same
https://jsfiddle.net/9j2na3L7/
I finally got this working :)
-- PROBLEM:
Mouse cursor escaping too fast from canvas, prevents event form fireing
-- SOLUTION:
First of all grab a handle of jplot object
var plotBar = $.jqplot('task_brk_bar_chart', [...
So we can use it to manipulate it on run-time.
Then we will use jqplotDataHighlight and jqplotDataUnHighlight events to change the graph properties and replot() function to apply them on fly.
$('#task_brk_bar_chart').bind('jqplotDataHighlight', function () {
plotBar.showTooltip = true;
plotBar.replot();
});
$('#task_brk_bar_chart').bind('jqplotDataUnhighlight', function () {
plotBar.showTooltip = false;
plotBar.repolot();
});
Working fiddle : https://jsfiddle.net/urahara/9j2na3L7/1/
Note: Copy your old css to override my setting, it was for testing purposes only.
Cheers!
This is a question related to Basic Javascript loading message while js processing completes
My main problem is that cursor not is changed before my two functions drawlegend() and display() are called, but changes after everthing has finnished.
With the code as below where the restore of the cursor temporary commented out, I get the hourglass, but after everything has finnished.
How to get my cursor to change to an hourglass before my slow functions are called?
examplefunc()
{
mini.append("text")
.text(series[i].name)
.attr("x",30)
.attr("y",(15+(15*i)))
.attr("stroke",(d3.rgb(192,192,192)))
.attr("fill",(d3.rgb(192,192,192)))
.attr("stroke-width",0)
.style("font-size","12px")
.attr("text-anchor","start")
.attr("id","legend")
.on('mouseup', legendclick);
}
//===== legend clicked
function legendclick()
{
//--- get mouse pos
var origin = d3.mouse(this);
//--- get channel
var ch=Math.floor((origin[1]-4)/15);
//--- toggle active state
if (series[ch].active==true)
series[ch].active=false;
else
series[ch].active=true;
setTimeout(setcursor("wait"),5);
drawlegend();
display();
//setTimeout(setcursor("default"),5); // temp removed to see any result at all
}
//===== set cursor
function setcursor(cursor)
{
d3.select("body").style("cursor", cursor);
}
It is known that executing things in javascript, hangs your application. This means that only the eventual output is displayed on your screen. Thus, when you change the cursor to "wait" and after execution to "cursor", the javascript hasn't changed it, because the ui thread was busy calculating the things in the functions "drawlegend" and "display". However, I think when you execute the "drawlegend" and "display" asynchronous like
setTimeout(function () {
drawLegend();
display();
setcursor("default");
}, 0);
then things should go like you want to.
Let me know if this works for you.
Extra info: on this slideshare (especially slide 5) is explained what your problem is.
Using OpenLayers, I have a OpenLayers.Control.SelectFeature installed on a layer, with the hover option set to true. When creating the layer I call
<layer>.events.register("featureselected",...)
and
<layer>.events.register("featureunselected",...)
to register functions that create and destroy a popup. This all works fine. Now I want to add a small delay before the popup is created in order to avoid the popup flickering that currently occurs when moving the mouse across multiple features. However, I can't seem to figure out how to do this. I did find the OpenLayers.Handler.Hover handler, which has a delay option, but I don't know how to combine that with the SelectFeature control (if I even can).
I think this post has some valuable info, which I'm about to verify. Some answers down, someone talks about the flickering.
edit: In case you are making your own labels, I noticed the effect is less when you raise the labelOutlineWidth . It seems that only the letters of the label count as 'hover' and not the whole PointRadius radius. When you make the label outline too big, the label looks like a fly that hit a windscreen though (not a square but it follows the label contours, the letters more specifically).
update: apparently this is why when you hover a text label , check this out: pointer events properties. set this attribute (pointerEvents: ) in your OpenLayers.Style and try value 'all' and the others. It sure makes a difference for me.
I bind my feature selections a little different, here's a quick (untested) example that should get you what you need.
var timer,
delay = 500, //delay in ms
hover = new OpenLayers.Control.SelectFeature( <layer> , {
hover: true,
onSelect: function (feature) {
// setup a timer to run select function
timer = window.setTimeout(function () {
// your select code
}, delay);
},
onUnselect: function () {
// first cancel the pending timer (no side effects)
window.clearTimeout(timer);
// your unselect code
}
});
<map>.addControl(hover);
hover.activate();