Highcharts - SetState (inactive) not working after redraw - highcharts

Consider the following toy example: jsfiddle
chart: {
events: {
render: myfunc
}
},
...
function myfunc() {
var chart = this;
chart.series.forEach(function(s) {
s.setState('inactive', true);
});
chart.series[0].setState('hover');
}
The intended behavior is to set the state of the first series as hover while setting all other series as inactive after load and redraw events.
The code works as intended after load
However, it doesn't work after redraw (via the select box). After selecting an option in the box, the series are rendered as normal instead of as inactive UNLESS any series had been previously hovered. That is, the code works if you interact with any series AND THEN select an option in the box, but it doesn't work if you select an option in the box immediately after the loading without interacting on the series.
Surprisingly, after some inspection in the console, I noted that in any case the intended states are properly passed to the series object. So, why the states are not properly rendered?
*NOTE: In my actual application the hovered series is not necessarily the first one, but it varies depending on the output of other function. I'm aware that "myfunc" could be simplified in the current example, but for general purposes please suggest an answer keeping the basic structure if possible.

This seems to be related to this issue from HighChart's GitHub. In your case, HighCharts is correctly updating the series' state. However, while rendering it fails to set the proper opacity value associated with the 'inactive' state. The workaround is to explicitly set the opacity of the series to the same value it should have in the 'inactive' state.
// F U N C T I O N S E T S T A T E
function myfunc() {
var chart = this;
chart.series.forEach(function(s) {
//explicit opacity
s.opacity = 0.2;
s.setState('inactive', true);
});
chart.series[0].setState('hover');
}

Thank you for sharing this issue, it seems that it is a regression after the last release.
In the previous version it used to work fine: https://jsfiddle.net/BlackLabel/Lbpvdwam/
<script src="https://code.highcharts.com/8.1.0/highcharts.js"></script>
<script src="https://code.highcharts.com/8.1.0/highcharts-more.js"></script>
I reported it on Highcharts Github issue channel where you can follow this thread: https://github.com/highcharts/highcharts/issues/13719
If you don't need any new features/bugfixes use the previous version as a temporary workaround.

Related

Issue with mobile.loading and timing - JQuery Mobile

I am trying to show the loading animation during a function call that takes some time. The function call is searching a large array that is already loaded. After the search, matching items are inserted into a table. The table is cleared prior to starting the search.
The problem is the animation only displays during the brief moment when the page updates.
Here is my code:
var interval = setInterval(function ()
{
$.mobile.loading('show');
clearInterval(interval);
}, 1);
DoSearch(term, function ()
{
var interval = setInterval(function ()
{
$.mobile.loading('hide');
clearInterval(interval);
}, 1000);
});
//The search function looks like this (detail omitted for brevity):
function DoSearch(term)
{
$("table#tableICD tbody").html('');
// also tried:
/*$("table#tableICD tbody")
.html('')
.table()
.closest("table#tableICD")
.table("refresh")
.trigger("create");*/
var tr = '';
$.each(codes, function (key, value)
{
// determine which items match and add them as table rows to 'tr'
});
$("table#tableICD tbody")
.append(tr)
.closest("table#tableICD")
.table("refresh")
.trigger("create");
callback();
}
The search works properly and adds the rows to the table. I have two unexpected behaviors:
The table does not clear until the search is complete. I have tried adding .table("refresh").trigger("create") to the line where I set the tbody html to an empty string. This does not help. (see commented line in the code)
As I mentioned, the animation displays briefly while the screen is refreshing. (Notice I set the interval to 1000 in the second setInterval function just so I could even see it.)
The suggestions I have read so far are to use setInterval instead of straight calling $.mobile.loading, which I have done and placing the search in a function and using a callback, which I have also done.
Any ideas?
Let me give you a few suggestions; they will probably not solve all your issues but they may help you found a solution.
jQuery Mobile is buggy, and for some features, we will never know were they intended to work like that or are they just plain bugs
You can call $.mobile.loading('show') on its own only in pageshow jQuery Mobile event. In any other case, you need to do it in interval or timeout.
It is better to do it in timeout, mostly because you are using less code. Here an example I made several years ago: http://jsfiddle.net/Gajotres/Zr7Gf/
$(document).on('pagebeforecreate', '[data-role="page"]', function(){
setTimeout(function(){
$.mobile.loading('show');
},1);
});
$(document).on('pageshow', '[data-role="page"]', function(){
// You do not need timeout for pageshow. I'm using it so you can see loader is actualy working
setTimeout(function(){
$.mobile.loading('hide');
},300);
});
It's difficult to enhance any jQuery Markup in real time after a page was loaded. So my advice is to first generate new table content, then clean it, and then update markup using .table("refresh").
Do table refresh only once, never do it several times in the row. It is very resourced heavy method and it will last a very long time if you run it for every row
If you are searching on keypress in the input box then showing it in the table; that is the least efficient method in jQuery Mobile. jQM is that slow, it is much better to use listview component which is least resource extensive.

How to set start time for primefaces clock widget?

Is it possible to set start time for PrimeFaces clock widget?
I know about Analog Clock from PrimeFaces Extensions, but I need digital clock with this option.
I have tried to override javascript method for this clock, but it doesn't work.
PrimeFaces.widget.Clock = PrimeFaces.widget.BaseWidget.extend({
init: function(cfg) {
this._super(cfg);
this.cfg.value = 1430304817141;
this.current = this.isClient() ? new Date() : new Date(this.cfg.value);
var $this = this;
},
isClient: function() {
return this.cfg.mode === 'client';
},
});
The first problem was that you were overriding the widget too late, after PrimeFaces has instantiated its original unmodified widget. According to PrimeFaces Customizable Resource Ordering the right place to override would be in h:head.
The second problem is that you're overriding the widget with a crippled version, that doesn't contain many necessary functions that were present in the original widget.
I wouldn't recommend this approach at all - to basically break the whole PrimeFaces widget like that. What if you'd want to use the normal unchanged clock? Copy-pasted code is harder to maintain too. I advise going the more localized approach: tweak only a single widget instance.
<p:clock id="my_clock" />
<script>
// get widgetVar via EL function, since p:clock doesn't have the widgetVar attribute
var myClockVar = #{p:widgetVar('my_clock')};
myClockVar.current = new Date(1430304817141);
</script>
Just be careful not to update the clock with AJAX requests, or it will to reset to showing client time; and not to update the script, or the clock will reset to the specified time again.

How to register map move / map pan events in OpenLayers 3

I'm looking for OpenLayer 3 map event for map move/map pan, something like:
map.on('move', function(){
...
}
Does anyone know how to implement?
The moveend event might be the one you search for - it detects any move made, even those not invoked by dragging.
map.on('moveend', function (e) {
console.log("moved");
});
See http://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html
UPDATE:
These events are no longer present in recent versions. Please refer to the more recent answer for an up-to-date information.
Names of the events you're looking for are drag and/or dragend (it's probably a better idea to depend on properties names, though: ol.MapBrowserEvent.EventType.DRAG but it didn't work on the demo page):
map.on('drag', function() {
console.log('Dragging...');
});
map.on('dragend', function() {
console.log('Dragging ended.');
});
Reverse-engineered by looking inside mapbrowserevent.js, the documentation explicitly mentions events are not documented yet.
MoveEnd trigger if u move the map with a script.
I have use that in OpenLayers 6:
map.on('pointerdrag', function (event) {
is_map_center = false;
})
hf gl!
I believe this functionality exists in 2 functions within the View of a map, not the map itself. You can monitor the center property of the View by listening for change:center events. There is also a getInteracting() method in ol.View that will return a boolean if an interaction (zooming or panning) is occurring.
https://openlayers.org/en/v4.6.5/apidoc/ol.View.html#getInteracting

Is there any way to control the layout of the close button on a jQuery Mobile custom select menu?

I have a custom select menu (multiple) defined as follows:
<select name="DanceStyles" id="DanceStyles" multiple="multiple" data-native-menu="false">
Everything works fine except that I want to move the header's button icon over to the right AND display the Close text. (I have found some mobile users have a problem either realising what the X icon is for or they have trouble clicking it, so I want it on the right with the word 'Close' making too big to miss.) There don't seem to be any options for doing that on the select since its options apply to the select bar itself.
I have tried intercepting the create event and in there, finding the button anchor and adding a create handler for that, doing something like this (I have tried several variations, as you can see by the commenting out):
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn').button({
create: function (event, ui) {
var $btn = $(this);
$btn.attr('class', $btn.attr('class').replace('ui-btn-left', 'ui-btn-right'));
$btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// $(this).button({ iconpos: 'right' });
// $btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// // $btn.attr('data-iconpos', 'left');
$(this).button('refresh');
}
});
}
});
});
So I have tried resetting the button options and calling refresh (didn't work), and changing the CSS. Neither worked and I got weird formatting issues with the close icon having a line break.
Anyone know the right way to do this?
I got this to work cleanly after looking at the source code for the selectmenu plugin. It is not in fact using a button; the anchor tag is the source for the buttonMarkup plugin, which has already been created (natch) before the Create event fires.
This means that the markup has already been created. My first attempt (see my question) where I try to mangle the existing markup is too messy. It is cleaner and more reliable to remove the buttonMarkup and recreate it with my desired options. Note that the '#search' selector is the id of the JQ page-div, and '#DanceStyles' is the id of my native select element. I could see the latter being used for the id of the menu, which is why I select it first and navigate back up and down to the anchor; I couldn't see any other reliable way to get to the anchor.
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn')
.empty()
.text('Done')
.attr('class', 'ui-btn-right')
.attr("data-" + $.mobile.ns + "iconpos", '')
.attr("data-" + $.mobile.ns + "icon", '')
.attr("title", 'Done')
.buttonMarkup({ iconpos: 'left', icon: 'arrow-l' });
}
});
});
The buttonMarkup plugin uses the A element's text and class values when creating itself but the other data- attributes result from the previous buttonMarkup and have to be removed, as does the inner html that the buttonMarkup creates (child span, etc). The title attribute was not recreated, for some reason, so I set it myself.
PS If anyone knows of a better way to achieve this (buttonMarkup('remove')? for example), please let us know.
the way i achieved it was changing a bit of the jquery mobile code so that the close button always came to the right, without an icon and with the text, "Close"
not the best way i agree. but works..
I got a similar case, and I did some dirty hack about this :P
$("#DanceStyles-button").click(function() {
setTimeout(function(){
$("#DanceStyles-dialog a[role=button]").removeClass("ui-icon-delete").addClass("ui-icon-check");
$("#DanceStyles-dialog .ui-title").html("<span style='float:left;margin-left:25px' id='done'>Done</span>Dance Styles");
$("#DanceStyles-dialog .ui-title #done").click(function() {
$("#DanceStyles").selectmenu("close")
});
},1);
} );

jQuery Draggable + Sortable - How to reject a drop into the sort?

I have a sortable list of videos and a draggable set of videos. Basically I want to make sure that the videos dragged in are not in the first 5 minutes of video. As the video lengths vary I want to test this on the drop - add up the time up to then and if not 5mins revert and show an error.
I have tried hooking into all of the callbacks for draggable and sortable (including the undocumented revert callback) to do my test but whatever I try, the dom always gets changed (and sortable calls its update callback)...
Does anyone have any suggestions?
You can revert the drag operation by calling the cancel method of the draggable widget (that method is undocumented, but its name does not start with an underscore, which arguably makes it "safer" to use reliably). It only works during the start event, though, as other events occur too late to trigger the revert animation.
However, the sortable widget will still register a drop even if the drag operation is canceled, so you also have to remove the newly-added item (during the stop event, as the start event occurs too early):
$("#yourSortable").sortable({
start: function(event, ui) {
if (!canDropThatVideo(ui.item)) {
ui.sender.draggable("cancel");
}
},
stop: function(event, ui) {
if (!canDropThatVideo(ui.item)) {
ui.item.remove();
// Show an error...
}
}
});
You can see the results in this fiddle (the fourth item will always revert).
Update: As John Kurlak rightfully points out in the comments, the item does not revert because of the call to draggable("cancel"), but because ui.sender is null in our case. Throwing anything results in the same behaviour.
Alas, all the other combinations I tried result in the item being reverted without the animation taking place, so maybe our best bet is to avoid accessing ui.sender and instead write something like:
start: function(event, ui) {
if (!canDropThatVideo(ui.item)) {
throw "cancel";
}
}
The uncaught exception will still appear in the console, though.
I found a different way. If you dont mind not having the animation of it floating back to it's original place you can always use this
.droppable({
drop: function (event, ui) {
var canDrop = false;
//if you need more calculations for
//validation, like me, put them here
if (/*your validation here*/)
canDrop = true;
if (!canDrop) {
ui.draggable.remove();
}
else{
//you can put whatever else you need here
//in case you needed the drop anyway
}
}
}).sortable({
//your choice of sortable options
});
i used this because i needed the drop event either way.

Resources