Improve Api calls to Openweathermap for tiles on Leaflet - javascript

I am trying to add to my leaflet map a layer with current weather. For that I am using this leaflet plugin https://github.com/buche/leaflet-openweathermap that is using this call:
https://tile.openweathermap.org/map/{layer}/{z}/{x}/{y}.png?appid={API key}
The free version of OWM is offering 60 calls per minute, the problem is that every time that I zoom or drag the map 12 petitions to the API are being requested. I thought the free version with the 60c/m should be more than enough for my app, but as soon I zoom few times the API key gets blocked. Is there a better way to work around this?

The more tiles your map requests, the sooner you reach the limit. In order to reduce the amount of tiles requested (with a cost to user experience), consider limiting zoom/drag options.
// change options according to your needs
let mapOptions = {
zoomControl: false,
scrollWheelZoom: false,
boxZoom: false,
dragging: false
}
let map = L.map('map', mapOptions);

Related

Performance limitations with OpenLayers 4.6.5 using several layers

I am currently working on a GIS holding a large amount of layers (up to 20 / 30).
The map is rendering tiles in a really slow way.
It was previously written with OpenLayers 2.x, and we didn't face this performance bottleneck.
Our layers are using WMS sources & tiles, which are declared as follow
function createTileLayer(options){
let source = new ol.source.TileWMS({
url: serverURL, // Our GeoServer instance
params: {
'LAYERS': options.id
'BGCOLOR': options.backgroundColor,
'TRANSPARENT': options.transparent,
'VERSION': options.version,
'FORMAT': 'image/png'
},
serverType: 'geoserver',
projection: 'EPSG:2100', // Managed by Proj4J
transition: 0
});
let layerTile = new ol.layer.Tile({
source: source,
visible: options.visible,
});
return layerTile;
}
The map declaration in itself is quite simple:
let map = new ol.Map({
target: document.getElementById('app'),
layers: Layers, // All the layers we created before
view: new ol.View({
center: ol.proj.fromLonLat([5.497853028599662, 34.82203273834541]),
zoom: 18,
projection: 'EPSG:2100'
}),
loadTilesWhileAnimating: true,
loadTilesWhileInteracting: true,
renderer: 'canvas'
});
}
Problem with this approach is that the browser seems to spend far too much time in drawing every layer. Here is the profile of some tests on Chrome:
Results are an almost unusable map.
I am aware that the amount of layers is high, but the issue was not in OpenLayers 2.x (or at least, performances were better).
One possible workaround is using only one TileWMS source and pass it the list of all our layers in its 'LAYERS' param. This dramatically improve the speed because GeoServer does all the rendering work, but we lose some possibilities such as managing each layer transparency.
I might be doing something wrong in querying / rendering tiles this way, that I am not aware of. Thanks for any help.
The most likely issue is that you are not hitting the tile boundaries that GeoWebCache (which is what GeoServer) uses to render the tiles. See this page in the manual which lists the criteria that must be met for this to work.
A better way to do this is to use a WMTS request (where the tile grids etc are agreed on between the client and server rather than guessed at). You can even get OpenLayers to do the negotiation for you by asking for the getCapabilities document.

Bing Maps in Ionic v1 Framework is not working

I am trying to use Bing maps API in ionic v1 framework app which builds on android,iOS and windows platforms.
I am facing problem in Bing maps which is plotting properly but zoom in,zoom out,changing the map type from aerial to road & fetching current location these buttons are not functional.I have proper API key to access maps. I even tried it doing ionic serve on browser but nothing helped me.
I have followed code from the below link:
https://github.com/eppineda/ionic.bing-map-demo
I have also changed JS src file of bing maps in index.html page from:
src='http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0'
To
src='http://www.bing.com/api/maps/mapcontrol'
The src file i have changed referring to Microsoft document pages as below:
http://www.bing.com/api/maps/sdkrelease/mapcontrol/isdk#loadMapAsync+HTML
Issue can be seen in the link -
http://plnkr.co/edit/NO5eLxogOyPHsiXzzpaQ?p=preview
$scope.init = function () {
console.log('Map init');
var mapOptions = {
credentials: '',
mapTypeId: Microsoft.Maps.MapTypeId.road,
center: new Microsoft.Maps.Location(51.5033640, -0.1276250),
zoom: 15,
// showLocateMeButton: false,
// // NavigationBarMode: "default",
// // NavigationBarOrientation: "vertical",
// showZoomButtons: false,
// ShowNavigationBar: false
showDashboard: true
// // showMapTypeSelector : true
// // showMapTypeSelector: false
// navigationBarMode: Microsoft.Maps.NavigationBarMode.compact
};
map = new Microsoft.Maps.Map(document.getElementById('divMap'), mapOptions);
console.log(map);
};
Please help me out to figure this out.It would be really helpful with the solution. Thanks in advance.
I suspect there is one of two issues. The first is that you have some other HTML element above the map and/or navigation bar/buttons. This would block you from being able to press those buttons. The second is that your code is actually loading the map twice somehow and as such you are ending with two maps on top of each other. When this happens the navigation bar for the bottom map ends up on top and using it actually changes the bottom hidden map. I've seen this occur once before in someone else's app who load the map twice to the same div.

Magnifying Tiles in OpenLayers 2 or Increasing MaxZoom Without Distorting Projection

I am using OpenLayers2 with Bing. My customer requires a deeper zoom level to interact with the maps. Currently, the max zoom level I can achieve is 19 which I tested with the getZoom() function. I have tried to set the "numZoomLevels" in the map constructor to a higher number, but Bing/OL just seems to ignore it. I was wondering if there is a way to force the tiles to a lower zoom level or if I could simply magnify the existing tiles so that I can see larger images even if the details are a bit blurry. It is crucial, however, that I don't modify the projection because having correct lat/lon values is paramount to the customer's function.
map = new OpenLayers.Map('map', {
allOverlays: false,
numZoomLevels: 20,
controls: [
new OpenLayers.Control.Navigation({
dragPanOptions: {
enableKinetic: true
}
}),
new OpenLayers.Control.LayerSwitcher(),
new OpenLayers.Control.Zoom({
zoomInId: "customZoomIn",
zoomOutId: "customZoomOut"
})
]});
var aerial = new OpenLayers.Layer.Bing({
name: "Aerial",
key: apiKey,
type: "Aerial"
});
I did stumble across an OL3 magnify example, but it is written for OL3 and a bit beyond what I can convert since I need the magnify option to be embedded as a zoom level, not just a context overlay. Also, I don't have a ton of experience with canvas. Any help is appreciated!
I figured it out, and it's actually quite simple. First, the numZoomLevels should have been on the layer level, not the map level. If you want to be able to zoom in beyond what Bing provides you, you must set fractionalZoom to true as shown below:
map = new OpenLayers.Map('map', {
allOverlays: false,
fractionalZoom: true,
controls: [
new OpenLayers.Control.Navigation({
dragPanOptions: {
enableKinetic: true
}
}),
new OpenLayers.Control.LayerSwitcher(),
new OpenLayers.Control.Zoom({
zoomInId: "customZoomIn",
zoomOutId: "customZoomOut"
})
]});
Then, on each layer, you need to set an array of resolutions. You will need to create a value for each zoom level you list under your numZoomLevels. I needed 22 zoom levels.
var aerial = new OpenLayers.Layer.Bing({
name: "Aerial",
key: apiKey,
type: "Aerial",
numZoomLevels: 22,
resolutions: bingResolutions,
serverResolutions: bingServerResolutions,
transitionEffect: 'resize'
});
In the source code for OpenLayers.Layer.Bing already had a resolution block defined which maps to their values at: https://msdn.microsoft.com/en-us/library/aa940990.aspx
var bingResolutions = [156543.03390625, 78271.516953125, 39135.7584765625,
19567.87923828125, 9783.939619140625, 4891.9698095703125,
2445.9849047851562, 1222.9924523925781, 611.4962261962891,
305.74811309814453, 152.87405654907226, 76.43702827453613,
38.218514137268066, 19.109257068634033, 9.554628534317017,
4.777314267158508, 2.388657133579254, 1.194328566789627,
0.5971642833948135, 0.29858214169740677, 0.14929107084870338,
0.07464553542435169];
var bingServerResolutions = [156543.03390625, 78271.516953125, 39135.7584765625,
19567.87923828125, 9783.939619140625, 4891.9698095703125,
2445.9849047851562, 1222.9924523925781, 611.4962261962891,
305.74811309814453, 152.87405654907226, 76.43702827453613,
38.218514137268066, 19.109257068634033, 9.554628534317017,
4.777314267158508, 2.388657133579254, 1.194328566789627,
0.5971642833948135];
The server resolutions are the tile resolutions from Bing itself. The additional resolutions (0.29858214169740677, 0.14929107084870338, 0.07464553542435169) are my fractional zoom levels that just zoom in on the layer 19 tile.
Here is the working example from OpenLayers for an OSM layer.
Hope this helps someone else!

Switch from Terrain layer to Satellite layer using Mapbox

I'm using Mapbox for a dynamic map on a social website.
I added a satellite toggle button but I can't find any way in the API docs on how to switch from terrain view to satellite view like Google Maps does?
Is it hidden somewhere? I know I have to subscribe and I will but I need to know I can switch from terrain to satellite in realtime without losing my markers, etc.
Let's say I have a simple map:
var initialLocation = [40.97, 64.07];
var initialZoomLevel = 2;
var map = L.mapbox.map('map_container').setView(initialLocation, initialZoomLevel);
How could I switch from terrain to satellite?
Any suggestions?
Thanks!
Its pretty easy to add a satellite view - just not very well documented. A prerequisite though is you must have a paid account (UPDATE: you used to need a paid account - that no longer seems to be the case) and have setup your own map in your account over there with the satellite imagery selected.
var initialLocation = [40.97, 64.07];
var initialZoomLevel = 2;
var map = L.mapbox.map('map_container').setView(initialLocation, initialZoomLevel);
L.control.layers({
"Street": map.tileLayer,
"Satellite": L.mapbox.tileLayer("my satellite imagery map id")
}, null).addTo(map);
This adds a control in the upper right (by default) that allows you to select between the default map and your satellite map.
With MapBox there is no concept of "modes", just different maps each with their own Map ID. So create a map at http://tiles.mapbox.com/newmap based on terrain, then another based on satellite imagery. Switch between them with the second argument to L.mapbox.map (see http://www.mapbox.com/mapbox.js/api/#L.mapbox.map) using their respective IDs.

Real time GPS Tracker on JUST HTML / JS and Google Maps to be run on a handphone? Is it possible?

I have read up on GPS Real time tracking and found out several things about it, mostly requiring PHP, zope and a database to store the incoming data. Some other methods uses ajax with relations to PHP.
As regards to my question, is it possible to do so with just html and JS, using markers or anything else to populate the Google Map when you move anywhere in the city? Need some help on this, Thanks!
Yes, it is possible. Most browsers in the latest smartphones have implemented the W3C Geolocation API:
The Geolocation API defines a high-level interface to location information associated only with the device hosting the implementation, such as latitude and longitude. The API itself is agnostic of the underlying location information sources. Common sources of location information include Global Positioning System (GPS) and location inferred from network signals such as IP address, RFID, WiFi and Bluetooth MAC addresses, and GSM/CDMA cell IDs, as well as user input. No guarantee is given that the API returns the device's actual location.
The API is designed to enable both "one-shot" position requests and repeated position updates, as well as the ability to explicitly query the cached positions.
Using the Geolocation API to plot a point on Google Maps, will look something like this:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var point = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
// Initialize the Google Maps API v3
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 15,
center: point,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
// Place a marker
new google.maps.Marker({
position: point,
map: map
});
});
}
else {
alert('W3C Geolocation API is not available');
}
The above will only gather the position once, and will not auto update when you start moving. To handle that, you would need to keep a reference to your marker, periodically call the getCurrentPosition() method, and move the marker to the new coordinates. The code might look something like this:
// Initialize the Google Maps API v3
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = null;
function autoUpdate() {
navigator.geolocation.getCurrentPosition(function(position) {
var newPoint = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
if (marker) {
// Marker already created - Move it
marker.setPosition(newPoint);
}
else {
// Marker does not exist - Create it
marker = new google.maps.Marker({
position: newPoint,
map: map
});
}
// Center the map on the new position
map.setCenter(newPoint);
});
// Call the autoUpdate() function every 5 seconds
setTimeout(autoUpdate, 5000);
}
autoUpdate();
Now if by tracking you mean that you should also store this information on a server (so that someone else could see you moving from a remote location), then you'd have to send the points to a server-side script using AJAX.
In addition, make sure that the Google Maps API Terms of Use allow this usage, before you engage in such a project.
UPDATE: The W3C Geolocation API exposes a watchPosition() method that can be used instead of the setTimeout() mechanism we used in the above example.

Categories

Resources