I am trying to work around the issue where a map is just part of the page, and on a mobile if you scroll down to the map, it fills the screen and you can't scroll the page anymore - you scroll the map instead.
so I changed the draggable option to have two finger map scrolls. This works.
var mymap = L.map('mapid', {
center: [latitude,longitude],
zoom: 17,
layers: [streetmap], //default layer
dragging: !L.Browser.mobile, tap: !L.Browser.mobile //twofinger map controls, one finger page scrolling
});
But I want to still have the map auto-follow the player, unless they have deliberately dragged the map away (and then a button to snap back to automove). The code of relevance for that stuff is here:
var panbtn = L.easyButton({
states: [{
stateName: 'pauseAutoMove',
icon: 'fa-sign-in fa-lg',
title: 'Centre display at current Player', //Tooltip
onClick: function(btn, map) { //if you click the button whilst it is in pauseAutoMove, recentre map and unpause
currentAutoMove = true; //Set flag, that currently map is being moved to recentre
mymap.panTo([latitude,longitude]);
currentAutoMove = false; //Remove flag again
pauseAutoMove = false; //set flag to stop Auto moving map
panbtn.state('AutoMove');
}
},{
stateName: 'AutoMove', //clicking the button once it is doing AutoMove does nothing
icon: 'fa-crosshairs fa-lg',
}]
}).addTo(mymap);
mymap.on("zoomstart", function (e) { currentAutoMove = true }); //Set flag, that currently map is moved by a zoom command
mymap.on("zoomend", function (e) { currentAutoMove = false }); //Remove flag again
mymap.on('movestart',(e)=>{ //Check if map is being moved
if(!currentAutoMove){ //ignore if it was a natural PlayerLoc or programmatic update
pauseAutoMove = true; //set flag to stop Auto moving map
panbtn.state('pauseAutoMove'); //change button style to remove crosshairs and have a arrow-in icon
}
});
and elsewhere
function updatemap() { // Update the current player location on map
playerLoc.setLatLng([latitude,longitude]); //update current player marker instead of creating new ones
//other stuff goes here to update too
if(!pauseAutoMove){ //pan the map to follow the player unless it is on pause
currentAutoMove = true; //Set flag, that currently map is moved by a normal PlayerLoc Auto update
mymap.panTo([latitude,longitude]);
currentAutoMove = false; //Remove flag again
};
mymap.invalidateSize(); //reset map view
}; // end updatemap
Now that I have two-finger map-dragging, on the mobile, it does NOT register the change of state to panbtn. The map snaps back again and I can't stop it now. (Still works as intended on a PC screen).
So, my question: It seems mymap.on('movestart',(e)=>{... is NOT being triggered by a two-finger drag? Is there a way to re-enable that?
Leaflet events for touch interaction, including touch zoom (which is what happens when you use 2 fingers, even just for panning) are "touchstart", "touchmove" and "touchend".
However, these events will likely fire even with 1 finger touch, so you may need to add a check similar to Leaflet TouchZoom hamdler: https://github.com/Leaflet/Leaflet/blob/v1.7.1/src/map/handler/Map.TouchZoom.js#L68
So you could combine with what you have with something like:
function mayDisableAutomove() { //Check if map is being moved
if(!currentAutoMove){ //ignore if it was a natural PlayerLoc or programmatic update
pauseAutoMove = true; //set flag to stop Auto moving map
panbtn.state('pauseAutoMove'); //change button style to remove crosshairs and have a arrow-in icon
}
});
mymap.on('touchmove', (e) => {
if (!e.touches || e.touches.length !== 2) { return; }
mayDisableAutomove();
});
mymap.on('movestart', mayDisableAutomove);
Related
This is the site https://www.space-intelligence.com/scotland-landcover/#
When you click on the regional statistics it open a dropdown and then when you click select region it open a pop up and here you select the city and after that you click search button. But it is doing nothing. When you click on search, it should zoom into the area selected. The area is highlighted on the map and zooms in when you click search.
This is the function:
function areasearch(modalid) {
var fid = $("#areasearch" + modalid).val();
$("#exampleModal" + modalid).modal('toggle');
map.data.forEach(function(feature) {
if (fid != 0) {
if (feature.i.ID != fid) {
map.data.overrideStyle(feature, {
visible: false
});
feature.setProperty('visible', 'false');
} else {
var bounds = new google.maps.LatLngBounds();
feature.getGeometry().forEachLatLng(function(latlng) {
bounds.extend(latlng);
});
map.fitBounds(bounds);
map.data.overrideStyle(feature, {
visible: true
});
google.maps.event.trigger(map.data, 'click', feature.getId());
feature.setProperty('visible', 'true');
}
} else {
map.data.overrideStyle(feature, {
visible: true
});
feature.setProperty('visible', 'true');
}
$('#exampleModal').modal('hide');
});
}
use setZoom()
if you experiment some trouble with map.fitBounds(), try to use setZoom() method with your desire level of zoom (int is needed). Also you need to center the map where you want to have a focus with the method setCenter() (latLng object is needed).
Try insert the following lines with the value desired :
map.setCenter({lat:YOUR_LATITUDE, lng:YOUR_LONGITUDE});
map.setZoom(6);
you can also read the this section of the documentaion
Im working on an App which retrieves the Users Location via Geolocation-API.
When the user clicks on a button a "HERE-API" Map gets initialized and the user has the option to drag a marker to the exact postition if it isn't already.
When he clicks on the Abort-Button i want to "destroy" or remove the entire Map since i dont want it to be displayed on the screen all the time. Just when the user clicks the Button which retrieves the Location and displays the Map.
I did alot of research on StackOverflow and the Official Documentation but i haven't found any Information on how to approach this.
Can someone please help me.
$("#addLocation").on('click', function()
{
$("#mapContainer").fadeIn();
function addDraggableMarker(map, behavior)
{
var svgMarkup = `<svg width="40" height="40" xmlns="http://www.w3.org/2000/svg"><g><title>background</title><rect fill="none" id="canvas_background" height="42" width="42" y="-1" x="-1"/></g><g><title>Layer 1</title><path stroke="null" fill="#046f47" id="svg_1" d="m20,0.701143a15.19595,15.19595 0 0 0 -15.19595,15.19595c0,10.257267 13.296457,21.844179 13.96128,22.338047l1.234671,1.063717l1.234671,-1.063717c0.664823,-0.493868 13.96128,-12.080781 13.96128,-22.338047a15.19595,15.19595 0 0 0 -15.19595,-15.19595zm0,22.793926a7.597975,7.597975 0 1 1 7.597975,-7.597975a7.597975,7.597975 0 0 1 -7.597975,7.597975z"/><circle stroke="null" fill="#046f47" id="svg_2" r="3.938806" cy="16.03728" cx="19.999999"/></g></svg>`;
var icon = new H.map.Icon(svgMarkup);
var coords = {
lat: lat,
lng: lng
};
var marker = new H.map.Marker(
coords, {
icon: icon
}, {
volatility: true
}
);
// Ensure that the marker can receive drag events
marker.draggable = true;
map.addObject(marker);
// disable the default draggability of the underlying map and calculate the offset between mouse and target's position when starting to drag a marker object:
map.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
var targetPosition = map.geoToScreen(target.getGeometry());
target['offset'] = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}
}, false);
// re-enable the default draggability of the underlying map when dragging has completed
map.addEventListener('dragend', function(ev) {
var target = ev.target;
if (target instanceof H.map.Marker) {
behavior.enable();
}
}, false);
// Listen to the drag event and move the position of the marker as necessary
map.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
target.setGeometry(map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));
}
}, false);
}
//Step 1: initialize communication with the platform
var platform = new H.service.Platform({
'apikey': 'MY-API-KEY'
});
var defaultLayers = platform.createDefaultLayers();
//Step 2: initialize a map
var map = new H.Map(document.getElementById('map'),
defaultLayers.vector.normal.map, {
center: {
lat: lat,
lng: lng
},
zoom: 16,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive - MapEvents enables the event system - Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Step 4: Create the default UI:
var ui = H.ui.UI.createDefault(map, defaultLayers, "de-DE");
// Add the click event listener.
addDraggableMarker(map, behavior);
});
$('#mapButtonAbort').on('click', function() {
// Something like map.destroy()
});
Summary:
On the beginning of the page is was a "mapInit" variable defined which is set to false. Now when the user closes the map by either clicking "Save Position" or "Abort" it simply fadeOut the Map and set the "mapInit" variable to true. As a workaround: when the 'addLocation' Button is clicked it simply check if the "mapInit" Variable is set to false. If so a new map gets initialized. Otherwise i simply fadeIn the map again.
Another possibility is to remove the DOM element when the user click on the "Hide" button and vice-versa, onAttach, Detach callbacks can also be created, please reference for that.. developer.here.com/documentation/maps/topics/best-practices.html
I'm extending Leaflet's GridLayer to show canvas tiles on which I draw some data points - the problem is that after zooming in and out the other zoom layers are still visible, or are partially chopped off in random ways.
E.g. on the left is zoom level 13, on the right is after zooming out to 11 and back to 13 -
How can I show only the current zoom level, and prevent the canvas tiles from getting chopped off?
This is how I ended up fixing it, though there might be better ways...
Here's my GridCanvas class -
L.GridLayer.GridCanvas = L.GridLayer.extend({
onAdd: function (map) {
L.GridLayer.prototype.onAdd.call(this, map);
map.on('zoomend', e => this.onZoomEnd(e.target._zoom));
},
// on zoom end, want to hide all the tiles that are not on this zoom level,
// and show all the ones that are
onZoomEnd: function (zoom) {
Object.values(this._levels).forEach(level => {
level.el.style.display = (level.zoom === zoom) ? 'block' : 'none';
});
},
createTile,
});
The visibility of the tiles also gets set in seemingly random ways - this seemed to fix the problem - adding a class to the canvas elements and setting them to always be visible -
function createTile(coords, done) {
const canvas = L.DomUtil.create('canvas', 'grid-canvas-tile');
...
}
with styles.css:
.grid-canvas-tile {
visibility: visible !important;
}
To create polygons in my map, I am using jQuery.getJSON() to load geojson files containing polygons and multipolygons. Then I analyse the geojson with a github plugin (loadgeojson) and finally the polygons are created on the map.
I put a <div> with a loading gif that overlays the map that appears just before the jQuery.getJSON() is being called.
The problem is the timing to remove it. I make the loading animation disappears when all the polygons visible property is set to True.
I want the <div> to disappears when the polygons appears on the map. But for the moment, it disappear a little before this. So on slower browser there is a relatively big delay between the <div> disappearing and the polygons appearing.
I tried to put a listener on an event but I couldn't find an event that corresponded to what I want.
How can I remove the loading animation right on time when the polygons appears on my map?
Here's my code:
function readJSON(id){
showLoadingAnimation();
// If .json hasn't been read
if(stockArray[id].length == 0) {
$.getJSON(id + ".json", function(data){
showFeature(data, id)
})
}
}
function showFeature(geojson, elemtype){
currentFeature_or_Features = new GeoJSON(geojson, elemtype, options);
if (currentFeature_or_Features.type && currentFeature_or_Features.type == "Error"){
return;
}
// Display object
if (currentFeature_or_Features.length){
for (var i = 0; i < currentFeature_or_Features.length; i++){
if(currentFeature_or_Features[i].length){
for(var j = 0; j < currentFeature_or_Features[i].length; j++){
// Display multipolygon
currentFeature_or_Features[i][j].setMap(map);
// Mouse events for multipolygons
mouseEventsMulti(i,j,elemtype);
}
}
else{
// Display polygons, polylines and points
currentFeature_or_Features[i].setMap(map);
// Mouse events for polygons, polylines and points
mouseEventsSimple(i,elemtype)
}
}
} else {
currentFeature_or_Features.setMap(map)
}
// Stop loading animation
dontShowLoadingAnimation();
}
Finally, I modified my code to pan the map a tiny little bit after the polygons are created. Then it activate the idle listener that stops the loading animation.
It might not be the prettiest bit of code, but it works.
This is what I added to the showFeature function
center = map.getCenter();
latLngCenter = new google.maps.LatLng(center.lat() + 0.0000001,center.lng() + 0.0000001);
map.panTo(latLngCenter);
And this is the Listener
google.maps.event.addListener(map, 'idle', function() {
// Stop loading animation
dontShowLoadingAnimation();
});
I have a set view to start on when loading the Google Earth API from my website, but it starts from space and then zooms in rather than starting on this zoomed-in view. This is wonky for the viewer particularly because my view is from the north looking south, so the Earth does a whirl on the way in:
http://www.colorado.edu/geography/cartpro/cartography2/fall2011/bartel/projects/project3_tungurahua/tungurahua_hazards.html
The map loads into an iframe. I'd like to toggle between various kmls without changing the zoomed view, as well, but I'll post that question separately. I've looked around for answers but haven't found anything specific to this--if I missed a post about this, I'm happy to check it out if someone can point me in the right direction.
Here's the code:
var ge;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
// set navigation controls
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
// to fetch a KML file and show it
function finished(object) {
if (!object) {
// wrap alerts in API callbacks and event handlers
// in a setTimeout to prevent deadlock in some browsers
setTimeout(function() {
alert('Bad or null KML.');
}, 0);
return;
}
ge.getFeatures().appendChild(object);
var la = ge.createLookAt('');
la.set(-1.251336, -78.443817, 7000, ge.ALTITUDE_RELATIVE_TO_GROUND,
177, 65, 500);
ge.getView().setAbstractView(la);
}
//var marker = new GMarker(new GLatLng(-1.402002,-78.409471)); // latitude, longitude
// map.addOverlay(marker);
function failureCB(errorCode) {
}
google.setOnLoadCallback(init);
Thanks!!
You can set the fly to speed to SPEED_TELEPORT before loading the abstract view.
This setting will make globe instantaneously fly-to the desired location rather than 'swooping in'. If regular movement should be restored then after you have your initial view you can set the speed back to the default setting.
For example the following function can be used to instantaneously fly-to the desired location.
The method accepts any KmlAbstractView, i.e. a KmlCamera or KmlLookAt as its single parameter.
// fly-to a view using SPEED_TELEPORT
function teleport(abstractView) {
var oldSpeed = ge.getOptions().getFlyToSpeed(); .
ge.getOptions().setFlyToSpeed(ge.SPEED_TELEPORT);
ge.getView().setAbstractView(abstractView); // Wooosh!
ge.getOptions().setFlyToSpeed(oldSpeed);
}
Further to this to make sure that the transition is not shown at all for an initial position you can make the teleport move before setting the GEWindow visibility to True. For example.
function initCB(instance) {
ge = instance;
var la = ge.createLookAt('');
la.set(-1.251336, -78.443817, 7000, ge.ALTITUDE_RELATIVE_TO_GROUND, 177, 65, 500);
teleport(la); // set the position
ge.getWindow().setVisibility(true); // now display the window
//etc..