When panning a map with the HERE maps API, the 'mapviewchangeend' event is triggered a short time after the animation completes. This means that is difficult to synchronise, say, a Leaflet overlay without the overlaid objects lagging behind.
var map = new H.Map(document.getElementById('mapContainer'),
defaultLayers.normal.map, ...
var lMap = L.map('mapContainer', {zoomControl: false});
...
function onMapViewChange() {
lMap.setView(map.getCenter(), map.getZoom(), {animation: false});
}
map.addEventListener('mapviewchange', function () {
onMapViewChange();
});
map.addEventListener('mapviewchangeend', function () {
onMapViewChange();
});
Is there a way to remove this delay? I have experimented with different kinetic settings for H.mapevents.Behavior but so far without success.
I think you can hook into the sync events being fired by the the view model and the viewport. I seem to recall that these events fire synchronously when the map renders...
After some digging, I found the example showing something very similar on github:
maps-api-for-javascript-examples/ground-overlay
Related
I am converting to HERE maps API 3.1 and haven't been able to find the same functionality in HERE that exists in both Google and Bing to return an event.
Bing: return Microsoft.Maps.Events.addThrottledHandler (_map, 'viewchangeend', callBack, 100);
Google: return google.maps.event.addListener(_map, 'bounds_changed', callBack);
What is the equivalent in HERE?
If you are looking for mapviewchange or mapviewchangeend Events below is the information:
Mapviewchange is called on each animation step in the process of changing a state of the viewport. In many cases, this operation is excessive. For example, updating a UI element with the current zoom level multiple times each time the user double-clicks on the map is inefficient.
// Displays current zoom level to the end user:
function displayZoomLevel() {...}
// A listener updates the map zoom level on each map view change
// -- this occurs more than 20 times on a double-click on the map,
// inefficient and to be avoided:
map.addEventListener('mapviewchange', function () {
var zoom = map.getZoom();
// This function is called more than 20 times on a double-click on the map!
displayZoomLevel(zoom);
});
mapviewchangeend, on the other hand, is called only once, when the viewport change is complete, therefore, we recommend using this event to update the map viewport:
/
*
Displays current zoom level to the end user
*/
function displayZoomLevel() {...}
// A listener updates the map zoom level -- it is called once when the map
// view change is complete.
map.addEventListener('mapviewchangeend', function () {
var zoom = map.getZoom();
// The function that displays the zoom level is called only once,
// after zoom level changed
displayZoomLevel(zoom);
});
The mapviewchangeend event is a 'debounced' version of mapviewchange, so, as a rule, it is more efficient to use mapviewchangeend
I've read the leaflet documentation fairly in depth and I can't find a simple answer to my question.
First some context:
I've created a new map and centred it at the current location and added a listener for location found.
var map = L.map('map', {zoomControl: false}).fitWorld();
L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/outdoors-v9/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoiZG9ucZhc3o3ODMifQ.3-x6nnTgePEK0ERPllV7oQ', {
maxZoom: 20
}).addTo(map);
map.locate({setView: true, watch: true, maxZoom: 17});
map.on('locationfound', onLocationFound);
I now want to create a marker at the current location e.g.
marker = L.marker(map.getLatLong);
marker.addTo(map);
This is to be done outwith the onLocationFound() function as I want to create it only once and then use the locationfound event to have the marker move using marker.setLatLng().
How am I able to use leaflet to get the current LatLong? Does it have a simple alternative to the HTML5 Geolocation API?
I've tried map.getCenter but it returns (0,0)
This is to be done out with the onLocationFound() function as I want to create it only once
In that case, use map.once() instead of map.on(). As you can read in the documentation, once() is the same as on() but only runs on the first event of that kind.
and then use the locationfound event to have the marker move using marker.setLatLng().
In that case, then check if the marker is created, create if it's not, or move it if it is. Something like...
var marker;
map.on('locationfound', function(ev){
if (!marker) {
marker = L.marker(ev.latlng);
} else {
marker.setLatLng(ev.latlng);
}
})
I'd also appreciate if anyone knows of a tidy way of doing it without events
In that case, do have a look at the HTML5 geolocation API. There are no events, but there are asynchronous callbacks anyway. You can use those callbacks directly, you can wrap them in event handlers (as Leaflet does), you can wrap them in Promises, but one way or the other you'll have to deal with not-totally-trivial asynchronicity issues.
I'm trying to create custom zoom in/out buttons and I've got it working except for the most important part, the zooming..
I've created a map chart like this:
$scope.chart = new Highcharts.Map(config);
Then I have two functions which run whenever you click on zoom in or out:
highcharts.zoomIn = function() {
$scope.chart.mapZoom(0.5);
};
highcharts.zoomOut = function() {
$scope.chart.mapZoom(2);
};
Setting the mapZoom of the chart doesn't give me an error nor does it do anything. I tried calling $scope.chart.redraw() afterwards but it didn't help either. Also saw that it already calls the redraw function in the source code of the mapZoom function.
I can't find any information on how to do this so what exactly am I doing wrong here?
I am building the functionality that allows mapbox markers to be edited from within a CMS. The functionality should open up and populate a form when a map marker is clicked, and then allow the map marker to be dragged. When the form is saved, the content is submitted via ajax and then the map is reloaded with the featureLayer.loadURL("my_geojson_endpoint").
I have added comments throughout my code below to outline how I am getting to the error.
N.B. I define a property db_id in the geojson to identify each point because when you apply a filter, _leaflet_id changes. I also have jquery included in the code.
Code:
// loop through each marker, adding a click handler
$.each(points._layers, function (item) {
var point = points._layers[item];
attachClickHandler(point);
});
function attachClickHandler(point) {
// open the edit state for the marker on click
$(point._icon).on("click", function () {
openEditState(point);
})
}
function openEditState (point) {
disableEditOthers(point);
displayContent(point);
point.dragging.enable(); // this line causes the error
$(point._icon).off("click");
}
function disableEditOthers (point) {
// hide the other markers from the map (using db_id as mentioned above)
points.setFilter(function (f) {
return f.db_id === point.feature.db_id;
})
// this functions as a callback to display the popup
// since applying the filter on click, does not show the popup
setTimeout(function () {
for (key in points._layers) {
points._layers[key].openPopup();
}
}, 0)
}
In the map creation step I have been able to call this dragging.enable() method on each of the markers and provide "draggability" to all of them, however this is undesirable from a usability point of view. I want the user to clear swap in and out of an edit state.
I discovered this issue on github, solved by the solution to this. However after swapping my mapbox.js version out to the standalone and including the latest version of leaflet (0.7.3) the same error still occured.
Am I calling the function on the wrong property of the object? dumping out the "point" variable just before the line which errors does not show that the draggable property has the enable() function defined.
Any help is much appreciated.
Ok so as a slight workaround, but still not solving the original error.
$.each(points._layers, function (item) {
points._layers[item].dragging.enable()
})
Because I have filtered out the other points, enabling dragging on all points is working around the issue.
If you can provide a fix to my original fix (avoiding the loop) I am happy to accept it.
I have some simple code that I copied from one of the openlayers examples for drawing several different types of geometries on the map. The problem is, whenever the "point" geometry is selected, I lose the ability to double-click to zoom in. The only difference between the examples and my code is I'm registering the handlers to use MOD_SHIFT, because i want to retain the ability to pan/zoom. Here is a snipit of code:
point: new OpenLayers.Control.DrawFeature(this.geometryFilterLayer,
OpenLayers.Handler.Point,
{
'done': console.info("drew point")
},
{
keyMask: OpenLayers.Handler.MOD_SHIFT
}
),
polygon: new OpenLayers.Control.DrawFeature(this.geometryFilterLayer,
OpenLayers.Handler.Polygon,
{
'done': console.info("drew polygon")
},
{
keyMask: OpenLayers.Handler.MOD_SHIFT
}
),
The funny thing about the above code is, the 'done' event only gets fired when the control/handler is created, and the keyMask doesn't work at all -- I have to loop through this object and manually set the keyMask each time, but that's not the real problem at hand.
I've tried every way I can think of to register a dblclick event, but no matter what, I can't get it to zoom in when I double click. It works fine on all the other geometries (bbox, point/radius, and polygon).
Can anybody give me some advice?
I never solved this issue, but ended up doing away with using MOD_XXX altogether. Each different draw control had too much built-in functionality for what happens when you hold shift, ctrl, alt, etc. I ended up using custom Buttons and a toolbar, that way the user can explicitly select the drawing control themselves.
this.toolbar = new OpenLayers.Control.Panel({
displayClass: 'olControlEditingToolbar'
});
map.addControl(this.toolbar);
var navButton = new OpenLayers.Control.Button({
displayClass: "olControlNavigation",
title: "Navigation",
trigger: lang.hitch(this, function(data){
this.toggleDrawControl("navigation");
navButton.activate();
pointButton.deactivate();
bboxButton.deactivate();
pointRadiusButton.deactivate();
polygonButton.deactivate();
})
});
...
this.toolbar.addControls([navButton, pointButton, bboxButton, pointRadiusButton, polygonButton]);
and my function to toggle draw controls (can be called externally, so that's why I re-call the activate and deactivate functions:
toggleDrawControl: function(geometryType){
this.currentGeometryType = geometryType;
for(key in this.drawControls) {
var control = this.drawControls[key];
if(geometryType == key) {
control.activate();
this.drawingButtons[key].activate();
} else {
control.deactivate();
this.drawingButtons[key].deactivate();
}
}
}