Highcharts not zooming series using option Highcharts.Series.prototype.drawPoints = function() { } - hover

I am creating a graph where I want to show the markers of the series only when hovering. I already tried the solution as shown on this question (Highcharts markers on legend and hover ONLY), and it works perfectly to show the markers when I want to.
However, I have another graph in the same html page that needs to show the markers and when I applied the solution presented on that question on the graph that I want (first graph) and I zoom at the other graph (second graph) the series that are represented by dots does not zoom, they keep all the markers on the graph.
The option
Highcharts.Series.prototype.drawPoints = function() { };
is on line 37 of the jsfiddle https://jsfiddle.net/erifel/sx3dcmny/

You should be able to use marker.enabled: false and series.states.hover.lineWidthPlus: 0 for achieving your chart without reseting drawPoints function. This will give you a possibility to redraw your markers when zooming on you chart.
If you want to show hidden markers in your legend, you can wrap renderItem function in your Legend prototype:
H.wrap(H.Legend.prototype,'renderItem',function(proceed,item){
var enabled = item.options.marker.enabled;
item.options.marker.enabled = true;
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
item.options.marker.enabled = enabled;
});
Here you can see an example how it can work: https://jsfiddle.net/sx3dcmny/12/

Related

Wrong code in tutorial for event listeners

I am following this tutorial to build a store locator page with a Mapbox map.
I don't want to add custom markers because I already have custom map labels (symbols?), which means I don't need the optional last section of the tutorial and stop right after Add Event Listeners.
Once this is completed, the page should react to clicks in the side panel list, as well as on the map (2 event listeners). However, in the demo provided in the tutorial for that particular step, you can tell the code for the second event listener, the one making the map clickable, is not functioning, which makes me believe there is a mistake in the provided code:
// Add an event listener for when a user clicks on the map
map.on('click', function(e) {
// Query all the rendered points in the view
var features = map.queryRenderedFeatures(e.point, { layers: ['locations'] });
if (features.length) {
var clickedPoint = features[0];
// 1. Fly to the point
flyToStore(clickedPoint);
// 2. Close all other popups and display popup for clicked store
createPopUp(clickedPoint);
// 3. Highlight listing in sidebar (and remove highlight for all other listings)
var activeItem = document.getElementsByClassName('active');
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
// Find the index of the store.features that corresponds to the clickedPoint that fired the event listener
var selectedFeature = clickedPoint.properties.address;
for (var i = 0; i < stores.features.length; i++) {
if (stores.features[i].properties.address === selectedFeature) {
selectedFeatureIndex = i;
}
}
// Select the correct list item using the found index and add the active class
var listing = document.getElementById('listing-' + selectedFeatureIndex);
listing.classList.add('active');
}
});
Would anyone be able to tell what is wrong with this code?
Turns out the code is incomplete in that the cursor doesn't change to a pointer as you hover over a map label/marker so it doesn't clue you into realising you can click on it, hence my assumption it wasn't working at all. I assume the general users who would then face the map would be equally deceived unless the pointer shows up. So in the tutorial, if you do go ahead and click the marker, it will have the expected behaviour and display the popup, although no pointer is shown.
Here is how to create the pointer, based on this fiddle: https://jsfiddle.net/Twalsh88/5j70wm8n/25/
map.on('mouseenter', 'locations', function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'locations', function() {
map.getCanvas().style.cursor = '';
});

URLImage on MapContainer not displayed on actual device and flickering in simulator

My app features a map, on which the user's avatar is displayed in the center and where markers including photo should be added when the user moves the map.
On the simulator, the markers are added but the images disappear as soon as I release the pointer then only the placeholders remain (this is what I call flickering). On the device, nothing is shown apart from the user's avatar.
As you can see the image does not remain on the map, only the placeholder does. The user icon is southern on the map but it is shown.
Please note: I am not receiving 404 errors and there is only one listener on the map (see below):
Here is how I trigger the map update:
googleMap.addMapListener((source, zoom, center) -> {
showReportsOnMap(googleMap, center, theme, currentForm, selectCategoryButton.getWidth());
});
And here is how I add the reports the map:
public void showReportsOnMap(
MapContainer currentMap,
Coord center,
Resources theme,
Form f,
int reportImageWidth) {
/**
* Get the map borders (CAUTION : it can be NaN)
*/
Coord NE = currentMap.getCoordAtPosition(currentMap.getAbsoluteX() + currentMap.getWidth(), currentMap.getAbsoluteY());
Coord SW = currentMap.getCoordAtPosition(currentMap.getAbsoluteX(), currentMap.getAbsoluteY() + currentMap.getHeight());
boolean bordersKnownAndValid = false;
// Checks that the borders does not contain NaN as longitudes and latitudes
if (!Double.isNaN(NE.getLatitude())
&& !Double.isNaN(NE.getLongitude())
&& !Double.isNaN(SW.getLatitude())
&& !Double.isNaN(SW.getLongitude())) {
// The borders can be used
bordersKnownAndValid = true;
}
if (bordersKnownAndValid) {
ArrayList<Report> localReports = (ArrayList<Report>) (Report.getReportsWithinBoundingBounds(NE, SW, selectedCategoryIdToBeShownOnMap).get(1));
// Revalidate only if we have something new to show
if (localReports.size() > 0) {
currentMap.clearMapLayers();
currentMap.addMarker(ParametresGeneraux.getCurrentUser().getUserIcon(),
new Coord(ParametresGeneraux.getCurrentUser().getCurrentUserLocation().getLatitude(),
ParametresGeneraux.getCurrentUser().getCurrentUserLocation().getLongitude()),
ParametresGeneraux.getCurrentUser().getUserNickname(), "", null);
Image tempPlaceholder = Image.createImage(
reportImageWidth,
reportImageWidth,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, reportImageWidth, reportImageWidth, 0, 360);
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
// Add the report on the map
for (Report report : localReports) {
String photoFilenameInStorage = Report.getFilename(report.getPhotoPath())
+ ParametresGeneraux.SUFFIX_ON_MAP_IMAGE;
EncodedImage reportIcon = EncodedImage.createFromImage(URLImage.createToStorage(roundPlaceholder,
photoFilenameInStorage,
report.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
),
false); // we want transparency png otherwise it shows black edges
currentMap.addMarker(reportIcon,
new Coord(report.getLocation().getLatitude(), report.getLocation().getLongitude()
),
report.getCategory().getName(), "",
(evt) -> {
// Opens the detail form about this report
new ReportDetailsForm(theme, report, f.getClass()).show();
});
}
currentMap.setCameraPosition(new Coord(center.getLatitude(), center.getLongitude()));
currentMap.zoom(new Coord(center.getLatitude(),
center.getLongitude()),
ParametresGeneraux.getUserZoomLevelOnMap());
currentMap.animate();
//f.forceRevalidate();
}
}
}
So I guess that the flickering in the simulator is a kind of slow motion of what happens on the device although the device does not show the placeholder.
What should I do to make the markers appear with an image?
EDIT March 8th 2017
On simulator, if I show a Dialog just before adding the marker to the map with this code :
Dialog.show("Photo", report.getAddress(), Dialog.TYPE_INFO, reportIcon, "OK", null);
The icon is well displayed in the Dialog (see screen capture below)
and then the image appears on the map without flickering any more as depicted below :
However on an actual Android device even the Dialog does not appear.
Finally I don't know why the Dialog makes then the markers behave as expected on the simulator but not on the device, so I am a bit at lost!
Any help would be precious.
The problem is that URLImage may not have finished downloading by the time you added it as a marker. If you call EncodedImage.createFromImage(urlImage) before URLImage has finished downloading, then you'll be creating an encoded image of the urlImage's placeholder.
the com.codename1.io.Util class includes quite a few methods for downloading images from URLs. Some are blocking, and some use a callback. Either way you just need to ensure that the image is actually downloaded before adding it to a map.
NOTE: Normally this wouldn't be an issue with URLImage - e.g. if you were adding it to a Button or a Label. It is only a problem here because the MapContainer is native, and it actually needs to pass the image data to the native layer at the time that setMarker() is called.

Leaflet 0.7.7 Zoombased layer switching separated by theme

We are working on a school project where the aim is to create a map in which based on the amount of zoom the layer switches from one aggregate level to a smaller aggregate level. Additionally, we have several groups of layers based on a theme for which this needs to apply. So you'd click on a theme and a new group of layers that switches based on zoom level become active and when you click another theme another group of layers become active and switch based on zoom level. This means that the themes are exclusionary, ideally you can't have more than one theme active at a time.
We tried to make this work in several ways already but without much success. Using the L.Control.Layers we were unable to group different layers together under one radio button and have them switch based on zoom since the layer control build into leaflet always splits them up into separate ones. Even using L.layerGroup to combine several layer variables or creating several layers into one variable and then adding them to the map using l.control.layer.
We also tried to use L.easyButton (https://github.com/CliffCloud/Leaflet.EasyButton). This allowed us to put the variables under one button and add a zoom based layer switching inside of it. However, the issue here is that we are unable to deactivate the functionality once activated. Which results in several of them being active at one point and overlapping each other.
If possible we would like to know if we should use a different approach or if either the leaflet control function or the use of easyButton could work and how?
This is example code for one of the buttons, which would appear several times but show a different theme:
L.easyButton( '<span class="star">&starf;</span>', function (polygon) {
var ejerlav_polygon = new L.tileLayer.betterWms(
'http://[IP]:[PORT]/geoserver/prlayer/wms', {
layers: 'prlayer:ejerlav',
transparent: true,
styles: 'polygon',
format: 'image/png'});
var municipality_polygon = new L.tileLayer.betterWms(
'http://[IP]:[PORT]/geoserver/prlayer/wms', {
layers: 'prlayer:municipality',
transparent: true,
styles: 'polygon',
format: 'image/png'});
map.on("zoomend", function() {
if (map.getZoom() <= 10 && map.getZoom() >= 2) {
map.addLayer(municipality_polygon);
} else if (map.getZoom() > 10 || map.getZoom() < 2) {
map.removeLayer(municipality_polygon);
}
});
map.on("zoomend", function() {
if (map.getZoom() <= 11 && map.getZoom() >= 11) {
map.addLayer(ejerlav_polygon);
} else if (map.getZoom() > 11 || map.getZoom() < 11) {
map.removeLayer(ejerlav_polygon);
}
});
}).addTo(map);
If my understanding is correct, you would like to give the user the ability to switch between "themes" (some sort of group of layers that switch themselves based on the map current zoom level), possibly using Leaflet Layers Control?
And regarding the switch based on map zoom, you cannot just change the Tile Layer template URL because you use some WMS?
As for the latter functionality (switching layers within a group / theme based on map zoom), a "simple" solution would be to create your own type of layer that will listen to map "zoomend" event and change the Tile Layer WMS accordingly.
L.LayerSwitchByZoom = L.Class.extend({
initialize: function (layersArray) {
var self = this;
this._layersByZoom = layersArray;
this._maxZoom = layersArray.length - 1;
this._switchByZoomReferenced = function () {
self._switchByZoom();
};
},
onAdd: function (map) {
this._map = map;
map.on("zoomend", this._switchByZoomReferenced);
this._switchByZoom();
},
onRemove: function (map) {
map.off("zoomend", this._switchByZoomReferenced);
this._removeCurrentLayer();
this._map = null;
},
addTo: function (map) {
map.addLayer(this);
return this;
},
_switchByZoom: function () {
var map = this._map,
z = Math.min(map.getZoom(), this._maxZoom);
this._removeCurrentLayer();
this._currentLayer = this._layersByZoom[z];
map.addLayer(this._currentLayer);
},
_removeCurrentLayer: function () {
if (this._currentLayer) {
map.removeLayer(this._currentLayer);
}
}
});
You would then instantiate that layer "theme" / group by specifying an array of layers (your Tile Layers WMS), where the array index corresponds to the zoom level at which that Tile Layer should appear.
var myLayerSwitchByZoomA = new L.LayerSwitchByZoom([
osmMapnik, // zoom 0, osmMapnik is a Tile Layer or any other layer
osmDE, // zoom 1
osmFR, // zoom 2
osmHOT // zoom 3, etc.
]);
Once this new layer type is set, you can use it in the Layers Control like any other type of Layer / Tile Layer, etc.
L.control.layers({
"OpenStreetMap": myLayerSwitchByZoomA,
"ThunderForest": myLayerSwitchByZoomB
}).addTo(map);
Demo: http://jsfiddle.net/ve2huzxw/85/
Note that you could further improve the implementation of L.LayerSwitchByZoom to avoid flickering when changing the layer after zoom end, etc.

Change Drupal Gmap marker z-index

I have a Drupal ExtendedGmap View. View results show as markers on the map. Marker type is determined by a custom field (NOT a field on the content type, but rather a PHP field calculated from the View) so the first view result marker is set to 'orange' and all other row markers are set to 'green'. The problem I have is that I want my first (orange) marker to show above the others. I have found a way to change the first marker z-index value in THEME_preprocess_gmap_views_view_gmapextended function:
$vars['markers'][0]['opts']['zindex'] = '9999';
But this is not reflected on the map and the first marker is still buried (in fact the first marker ends up somewhere in the middle of the stack).
How do I get my first View row marker on top?
I tried the Javascript mentioned on this page but don't really understand it and it doesn't work for me.
Drupal.gmap.addHandler('gmap',
function (elem)
{
var obj = this;
obj.bind('preparemarker',
function (marker)
{
marker.opts.zIndexProcess =
function (marker,b)
{
return this.zindex ? this.zindex : -99999;
};
}
);
});
I am using Drupal 7 and Gmap 7.x-2.9
Found the problem. Googlemaps API V3 uses zIndex (capital 'I') instead of zindex. Changed that and works as expected - markers stack correctly.
Example code:
$vars['markers'][0]['opts']['zIndex'] = '9999';

highcharts panning

I'm trying to implement highcharts panning based on this example:
http://jsfiddle.net/HXUmK/5/
But I want to be able to zoom with the left mouse button and pan with the right mouse button. So I modified the code above and managed to make it work a little, but when I pan holding the right mouse button, the charts also zoomes.
Is there a way I can disable right mouse button zooming in highcharts?
Edit: Sorry for not being very clear about it. The code in the jsfiddle is not my code. Forget that code, it's just an example form witch I started. I am trying to modify that code in order to get left button zoom and right button pan. So I disabled the mousewheel zoom and activated the standars highcharts zoom
Edit2: Here is my code: http://jsfiddle.net/TKPQN/
You can try with selection event:
chart: {
...
events:{
selection: function(event) {
if (lastButton == 1)
event.preventDefault();
}
}
}
See http://jsfiddle.net/TKPQN/48/
I've wanted to use the Shift key for zooming, so this is my solution
$('#container').highcharts('StockChart', {
chart: {
//zoomType: 'x', // we declare it without zoom, so the pan is enabled
// ...
}});
var chart = $('#container').highcharts();
chart.pointer.cmd = chart.pointer.onContainerMouseDown;
chart.pointer.onContainerMouseDown = function (a){
//in my case, I need only X zooming, so I enable it if shift is pressed
this.zoomX=this.zoomHor=this.hasZoom=a.shiftKey;
this.cmd(a);
};
seems to work ok, so hope it help you
here is a JSFiddle working example: http://jsfiddle.net/73bc23zq/