I'm trying to create an custom stationary map using the Leaflet JavaScript library and keep running into a major issue where most of the map tiles for the coordinates do not render. I'm defining & showing the map like so
function initmap() {
map = new L.Map('map');
var osmUrl = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}.png';
var osm = new L.TileLayer(osmUrl);
map.addLayer(osm);
}
var lat = 40.120910;
var lng = -74.978602;
var startLatLng = new L.LatLng(lat, lng);
initmap();
map.setView(startLatLng, 16);
It seems like it should work, but the map div never shows the full map/all tiles. I know there is coverage for this particular area because I've been using another person's service that using this library and map to look at this location. This code is structured based off of their code.
This website is using the exact coordinates, map server, and the leaflet js script and is able to render all tiles fine.
Here's a JSFiddle to show the code (and issue) in action. Any idea why this is happening or how to fix it?
Missing Leaflet CSS: https://npmcdn.com/leaflet#1.0.0-rc.1/dist/leaflet.css
Updated JSFiddle: https://jsfiddle.net/t14rLknv/7/
(BTW you can upgrade to Leaflet 1.0.0-rc.3, new official CDN on unpkg.com, see http://leafletjs.com/download.html)
Related
I have a bokeh Google maps plot with several Lat/ Lng data points, and I would like to use the fitBounds() method of the Google Maps v3 API to set the zoom level.
I have a Google Maps plot up and running, displaying on my site and showing the data points, but I need to set the zoom manually.
import bokeh.io
import bokeh.models
import bokeh.plotting
import pandas as pd
data = {
'Latitude [deg]': [18.46, 25.7, 32.3],
'Longitude [deg]': [-66, -80.2, -64.8],
}
data_frame = pd.DataFrame.from_dict(data)
data_source = bokeh.models.ColumnDataSource(data_frame)
mean_lat = data_frame['Latitude [deg]'].mean()
mean_lng = data_frame['Longitude [deg]'].mean()
gmap_options = bokeh.models.GMapOptions(lat=mean_lat, lng=mean_lng, zoom=10, map_type='satellite')
xy_gmap = bokeh.plotting.gmap('SuPeRSeCrEtAPIkey', gmap_options)
xy_gmap.circle(x='Longitude [deg]', y='Latitude [deg]', source=data_source, color="red")
# A callback like this? Could make the call in JavaScript after the page is loaded, and update map zoom??
# xy_gmap.fitBounds(x='Longitude [deg]', y='Latitude [deg]', source=data_source)
bokeh.io.show(xy_gmap)
I would like the bounds of the map to enclose all points in my dataframe, at the lowest zoom possible (as is done in Javascript by fitBounds() ). Currently, the map can only zoom to the manually set level.
As of Bokeh 1.2, there is no built-in way to accomplish this. The only suggestion I can offer is to note that there is a global Bokeh.index on the JavaScript side, and in that there is GMapPlotView for the corresponding GmapPlot that you made. This view has an attribute .map that is the actual Google map object. You could call the fitBounds method on that from JavaScript code. Bokeh GMapPlot objects follow Google's lead wrt to plot bounds, so if they get updated, the axes, etc. should respond.
Otherwise, I can only suggest opening a GitHub issue to discuss adding this as a new feature.
Starting an answer for both methods described by bigreddot (using JS Bokeh.index and Python integration)
Bokeh.index
In the Javascript Console, you can use the following commands (should be self explanatory to get this into some JS code)
> var gmapPlotView;
> for (var property in Bokeh.index) { if (Bokeh.index[property].constructor.name == 'GMapPlotView') {gmapPlotView = Bokeh.index[property];} } // Get the correct object, in the case that you have multiple plots, but only one map plot
> var bounds = gmapPlotView.map.getBounds(); // To start from existing bounds
> var bounds = google.maps.LatLngBounds(); // To start with fresh bounds
> var place = new google.maps.LatLng(45.5983128 ,8.9172776); // Coordinates of place to put bounds, repeat for all points
> bounds.extend(place); // Add each place to the bounds object
> gmapPlotView.map.fitBounds(bounds); // Set the maps new bounds
Note that the Bokeh google maps implementation does not plot your data on the Google Maps data layer, but on a bokeh canvas above the map (that is why there is a lag when panning the map between map tiles and your graphs).
Python Integration
In process....
I'm trying to add Marker Clustering to my Google Map chart with no success. I have a function which puts markers on the map based on lat/long. My understanding Map chart will not display more than 400 or so markers, which i don't really want anyway but i'd rather have clustering in place. This way my user sees, for example, single marker for Los Angeles and San Francisco, which would be broken down into multiple when zoom in.
I've looked into https://developers.google.com/maps/documentation/javascript/marker-clustering
but still can't connect dots and implement it into my function
function drawMapChart() {
var array_map = []
var header_map=[]
header_map.push('latitude')
header_map.push('longitude')
header_map.push('name')
array_map.push(header_map)
array_map.push([{v:34.043736},{v:-118.464298},{v:"city A"}])
array_map.push([{v:34.043003},{v:-118.448385},{v:"city B"}])
var data = google.visualization.arrayToDataTable(array_map);
var chart = new google.visualization.ChartWrapper({
chartType:'Map',
containerId:'map_chart_div',
options:{
mapType: 'normal'
},
dataTable:data
});
chart.draw();
}
Help is much appreciated!
It looks like the problem was that my implementation was through map chart (google charts), which from my understanding uses google maps api so i thought it should work. However, i couldn't find the way on how to add MarkerClusterer to that and so as a solution i just rebuilt the page using google maps api (following the example in the link) skipping google chart altogether.
I had more than 600 kml files to load in a single google map.
Initially I tried with KmlLayer(), but it didn't work due to the amount of kml files, so I found GeoXML3, and it works really fine.
Now I need to retrieve the path's coords for every polygon created with GeoXML3. Here I found the method getPaths() that seems to be just what I'm looking for, but it doesn't work because now I don't create polygons using the class Polygon but using the class geoxml3
for (i=0; i < controlli.length; i++)
{
appo = kmlurl + controlli[i].id + ".kml";
appo = appo.replace(" ", '_');
area[controlli[i].id] = new geoXML3.parser({
map: map,
zoom: false,
});
area[controlli[i].id].parse(appo);
//here I would like to do something like: 'area[controlli[i].id].getPaths()'
}
How can I do this?
The google.maps.Polygon objects created by geoXml3 to represent the KML polygons can be accessed 2 ways:
area[controlli[0].id].docs[0].placemarks[0].polygon.getPath()
working jsfiddle
area[controlli[0].id].docs[0].gpolygons[0].getPath()
working jsfiddle
where geoXml is a reference to the parser object (your area[controlli[i].id])
and i is a sequential reference to the placemarks (or the polygons) in the KML).
If you are using it on a KML file loaded asynchronously, you need to wait for the parsed event, or use the data in the afterParse function.
I am using a simple Mapbox layer control calling MB data layers (below).
I need to add a few more marker layers to this, but not sure how to get a mapbox ID. How can I accomplish this?
L.mapbox.accessToken = 'pk.eyJ1IjoibWFwc3RlciIsImEiOiI3RmFfME5ZIn0.73sdzUFNqSsGQzjlsnimaA';
var map = L.map('map').setView([38.8922,-77.0348], 14);
var layers = document.getElementById('menu-ui');
addLayer(L.mapbox.tileLayer('examples.map-i87786ca'), 'Base Map', 1);
addLayer(L.mapbox.tileLayer('examples.bike-lanes'), 'Bike Lanes', 2);
addLayer(L.mapbox.tileLayer('examples.bike-locations'), 'Bike Stations', 3);
function addLayer(layer, name, zIndex) {
layer
.setZIndex(zIndex)
.addTo(map);
code is from Mapbox toggling layers template
At the moment you're using their example ID and maps. You're not supposed to do that. If you would have read at the bottom of the page you posted it says:
Use this example by copying its source into your own HTML page and replacing the Map ID with one of your own from your projects.
Where "your projects" is linked to https://www.mapbox.com/projects/. When you're not logged in you get a nice dialog which asks you to login or register. Once you've done that you'll get your very own ID and you are able to create projects. When creating a project you'll get a Map ID per project. It's all pretty selfexplanatory.
EDIT: If you want to insert a separate layer with features, you've got to create a project with only a markerlayer. Save it and copy the id. You can include that in another map by using L.mapbox.featureLayer:
var mapId = 'examples.map-zr0njcqy'; // use your feature mapid
var features = L.mapbox.featureLayer(mapId); // declare featureLayer
features.on('ready', function () { // Wait untill features are loaded
addLayer(features); // add it the same your tilelayers
}
You can also use this to load external geojson files by just using an URL instead of a mapid.
See the example: https://www.mapbox.com/mapbox.js/example/v1.0.0/features-from-another-map/
And the reference: https://www.mapbox.com/mapbox.js/api/v2.1.5/l-mapbox-featurelayer/
I am working on a somewhat complex google map and have run into an issue with fitbounds.
It works perfectly... most of the time, but occasionally ignores my bounds and loads the map in the middle of the ocean.
My markers still appear and had loaded correctly if i zoom out and search for them.
Any thoughts?
Markers from json string
Code (stripped out for simplicity):
**var mybounds = new google.maps.LatLngBounds();**
$.getJSON(callRoot + JSON.stringify(mapSearchParams), function(data) {
$.each(data.markers, function (i, marker) {
**var position = new google.maps.LatLng(marker.latitude, marker.longitude);**
addMarker(position, findIcon(marker.category, "marker"), marker.category, marker.title, marker.subtitle, marker.destNodeGUID, marker.documentURL, marker.primaryImageURL, marker.isFeatured);
**mybounds.extend(position);**
}); // end .each
**map.fitBounds(mybounds);**
Please also note: I don't get any js errors on the page.