I'm trying to toggle the display of a CartoDb layer on a Leaflet map. I've been able to load the layer using this code:
var layerUrl = 'http://ronh-aagis.cartodb.com/api/v1/viz/rotaryclubs_geo2/viz.json';
var clubPts = cartodb.createLayer(map, layerUrl, {
// The ST_AsGeoJSON(ST_Simplify(the_geom,.01)) as geometry will store a simplified GeoJSON representation of each polygon as an attribute we can pick up on hover
query: 'select *, ST_AsGeoJSON(the_geom) as geometry from {{table_name}}',
interactivity: 'cartodb_id, geometry'
})
.on('done', function(layer) {
map.addLayer(layer);
layer.on('featureOver', function(e, pos, latlng, data) {
$('.leaflet-container').css('cursor','pointer');
if (data.cartodb_id != point.cartodb_id) {
drawHoverPoint(data);
}
cartodb.log.log(pos, data);
});
layer.on('featureOut', function(e, pos, latlng, data) {
$('.leaflet-container').css('cursor','default')
removePoint();
});
layer.on('error', function(err) {
cartodb.log.log('error: ' + err);
});
}).on('error', function() {
cartodb.log.log("some error occurred");
});
Yet when I try to add this layer to a Layer Control:
var clubs = new L.LayerGroup();
clubs.addLayer(clubPts);
I get an "Uncaught TypeError: Object # has no method 'onAdd'" error.
Any thoughts? Thanks!
A great way to reduce complexity and get up to speed quickly here would be using an already-built Leaflet plugin, like Vector Layers, that has built-in CartoDB support already. Take a look at the demo here. http://jasonsanford.github.io/leaflet-vector-layers/demos/cartodb/
Related
Im trying to find a way to change the instance of a Leaflet geoJson Feature after it is added to the map.
This is what I want to achieve:
Importing data with L.GeoJson and I am using pointToLayer to change the marker to L.CircleMarker
Now I want
layer.on('click', function (e) {
e.target //Do something here to change it from L.CircleMarker to L.Marker
});
Any idea how to achieve this?
var group = L.geoJSON(); // Your geojson group on importing
layer.on('click', function (e) {
var circlemarker = e.target //Do something here to change it from L.CircleMarker to L.Marker
var marker = L.marker(circlemarker.getLatLng()).addTo(group);
marker.feature = circlemarker.feature
circlemarker.removeFrom(group)
// Then add the same events to the layer as in pointToLayer
});
Using leaflet is there any way I can get the bounds (NorthEast, SouthWest) of a loaded tile? I want to request the server to load the markers only for a particular tile which is loaded, so that when user is panning/dragging the map he can easily see the new markers on new area.
What you really want to do is a subclass of L.GridLayer. This will allow fine control over loaded/unloaded tiles, and is the best way to use the private L.GridLayer._tileCoordsToBounds() method.
With some basic handling of loaded markers, it should look like:
L.GridLayer.MarkerLoader = L.GridLayer.extend({
onAdd: function(map){
// Add a LayerGroup to the map, to hold the markers
this._markerGroup = L.layerGroup().addTo(map);
L.GridLayer.prototype.onAdd.call(this, map);
// Create a tilekey index of markers
this._markerIndex = {};
},
onRemove: function(map){
this._markergroup.removeFrom(map);
L.GridLayer.prototype.onRemove.call(this, map);
};
createTile: function(coords, done) {
var tileBounds = this._tileCoordsToBounds(coords);
var tileKey = this._tileCoordsToKey(coords);
var url = ...; // Compute right url using tileBounds & coords.z
fetch(url).then(function(res){
if (!key in this._markerIndex) { this._markerIndex[key] = []; }
// unpack marker data from result, instantiate markers
// Loop as appropiate
this._markerGroup.addLayer(marker);
this._markerIndex[key] = marker;
done(); // Signal that the tile has been loaded successfully
});
},
_removeTile: function (key) {
for (var i in this._markerIndex[key]) {
this._markerGroup.remove(this._markerIndex[key][i]);
}
L.GridLayer.prototype._removeTile.call(this, key);
}
});
Please note that zooming might be a source of bugs and graphical glitches (markers being removed because a tile unloads, before the markers at the new zoom level are loaded). Beware of that.
When a draw:editvertex event fires, how can I get information about the polygon which triggered it?
this.map.on('draw:editvertex', function (e) { debugger;
var layers = e.layers;
// I want to get current polygon latLng here
}.bind(this));
This approach works for me (but doesn't feel like best practice) –
In my draw:editvertex handler I loop through the target._layers and look for the edited property:
map.on('draw:editvertex', function(e) {
for (thisLayer in e.target._layers) {
if (e.target._layers.hasOwnProperty(thisLayer)) {
if (e.target._layers[thisLayer].hasOwnProperty("edited")) {
console.log("we think we found the polygon?");
console.log(e.target._layers[thisLayer]);
// the updated Polygon array points are here:
newPolyLatLngArray = e.target._layers[thisLayer].editing.latlngs[0];
}
}
};
});
...like I said, this doesn't feel Awesome, but it is working for me so far.
There are not only layers in e, but also the target layer poly can be approached easily.
map.on('draw:editvertex', function (e) {
var poly = e.poly;
var latlngs = poly.getLatLngs(); // here the polygon latlngs
});
I have a map which loads a GeoJSON containing two features (lines). I would like to use Leaflet Elevation plugin to display an elevation profile for each of those lines. The problem with my code is that when I click a feature, there is no data added to the elevation profile.
var map = L.map('map').setView([44.635, 22.653], 11);
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
function addData(e) {
var el = L.control.elevation();
el.addData(e);
map.addControl(el);
}
function onEachFeature(feature, layer) {
layer.on({
click: addData
});
}
var trails = new L.GeoJSON.AJAX('https://googledrive.com/host/0B55_4P6vMjhITEU4Ym9iVG8yZUU/map.geojson', {
onEachFeature: onEachFeature
}).addTo(map);
Here's a JSFiddle of my work: http://jsfiddle.net/pufanalexandru/eaok0Lnz/3/
To anyone who might be interested, I think I found a way to achieve this:
var trails = new L.GeoJSON.AJAX('https://googledrive.com/host/0B55_4P6vMjhITEU4Ym9iVG8yZUU/map.geojson', {
onEachFeature: function onEachFeature(feature, layer) {
layer.on({
click: function () {
el.clear();
el.addData(feature);
}
});
}
}).addTo(map);
I am looking for solution to add filter (not checkbox) to my site. I have this code loading blank map from Mapbox and added Markers from JSON file. I was trying to add setFilter function, but probably I am using it wrong. I would like to filter items by category property from my JSON file.
<script>
L.mapbox.accessToken = '*************';
var baseLayer = L.mapbox.tileLayer('test****');
var markers = L.markerClusterGroup();
// CALL THE GEOJSON HERE
jQuery.getJSON("locations.geojson", function(data) {
var geojson = L.geoJson(data, {
onEachFeature: function (feature, layer) {
// USE A CUSTOM MARKER
layer.setIcon(L.mapbox.marker.icon({'marker-symbol': 'circle-stroked', 'marker-color': '004E90'}));
// ADD A POPUP
layer.bindPopup("<h1>" + feature.properties.title + "</h1><p>" + feature.properties.description + "</p><p><a href=' + feature.properties.website + '>" + feature.properties.website + "</a></p>");
layer.on('mouseover', function (e) {
this.openPopup();
});
layer.on('mouseout', function (e) {
this.closePopup();
});
}
});
markers.addLayer(geojson);
// CONSTRUCT THE MAP
var map = L.map('map', {
searchControl: {layer: markers},
zoom: 6,
center: [51.505, -0.09],
maxZoom: 13
})
.setView([62.965, 19.929], 5)
.fitBounds(markers.getBounds());
baseLayer.addTo(map);
markers.addTo(map);
L.control.fullscreen().addTo(map);
});
</script>
Could you please help me add filter buttons (something like here: https://www.mapbox.com/mapbox.js/example/v1.0.0/filtering-markers)
PS: I think I tried all examples from Mapbox website, yet seems my skills are very limited here.
Thank you
I was trying to add setFilter function, but probably I am using it wrong. I would like to filter items by category property from my JSON file.
This code example is using L.geoJson to load the markers into your map. Like the Mapbox example, you'll need to use L.mapbox.featureLayer instead, since it includes the setFilter function and L.geoJson does not.
tmcw's answer is correct, L.mapbox.featureLayer is confusing
this tutorial helped me!
https://www.mapbox.com/mapbox.js/example/v1.0.0/custom-marker-tooltip/