Is there any way to create custom dynamic icons for the markers?
What I want to create is a list of points and put a number "n" within markers specifying it's the n-th element.
Yes. You can either use custom icons with Numeric Markers or the built-in numbering system on Google has for markers.
Assuming the last option (not using custom markers), your marker definition code would look like:
var NUMBER_SHOWN='34';
var ICON_COLOR = 'ff6600';
var ICON_TEXT_COLOR = '000000';
var marker = new google.maps.Marker({
position: [LatLong Obj],
map: [Map Obj],
icon: 'http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld='+NUMBER_SHOWN+'|'+ICON_COLOR+'|'+ICON_TEXT_COLOR
});
I believe this only works for two-digit number, though I'm not sure.
EDIT
Geocodezip has correctly pointed out that the second approach has now been deprecated, so it looks like you're stuck using the first approach (using google's custom numbered-icons). Have a look at Daniel Vassallo's answer here on how to use it. If none of the markers fit your needs (colors, look, etc) you can create your own custom markers for each of the numbers (if you know how, you can write a server-side script that you can pass GET vars to and have it build the icon for you using GD etc, but you can also just build all the icons by hand)
Related
My end goal is to show a map with several hundred markers, each containing some information in a popup. Those markers are fairly close and some are in the very same spot, so they should be clustered and must be separately clickable for the popup. I also want to be able to filter them by several properties, starting with two array properties (phases and tags).
I actually managed to set all of that up quite nicely by using the MarkerCluster and MarkerCluster-LayerSupport plugins. I have 19 different tags and 4 different phases with corresponding FeatureGroups, all the markers are added to the respective groups, and there are two controls with checkboxes on the map. You can check it out here if you like.
However, these controls act a little weirdly, or rather, not quite the way I'd like them to. All markers are on at least two layers, so when I uncheck "Tag #2", the FeatureGroup with all the markers with tag #2 is removed. That includes markers with tag #3 and tag #6, which are still checked and which therefore I'd like to keep on the map… so when you check and uncheck boxes in both controls, the results become quite unpredictable.
Is there a way to fix this, by somehow reevaluating all the checked layers? Or should I go a completely different route with the filtering? For example this seems to be a jQuery filter. I find it hard to gauge performance issues though – I'm importing all the data into a separate geoJSON file with PHP, and I expect to get several hundred markers at some point, possibly more. I'm fairly new to Leaflet and handling large amounts of data in JS.
I will of course post my code if you'd like to see it, but since it's all working as intended and it's quite a lot, I'm not sure it's useful at this point.
Any pointers, ideas and best practice tips are most appreciated!
I have worked a little with Leaflet. In my experience, you need to have in mind that you need to group the common markers in a single layer, but the geo-JSON files put all markers in a single layer, no matter with properties has.
I did something similar to you, but I preprocessed all added markers to group them by specific properties. It is good because it can give you more control and do whatever you need, but that needs more initial time to preprocess all the info (and more if you are planning to have thousands of markers).
To check and manage all possible points you can use the pointToLayer method in the geoJSON loading:
const tagCategories = {};
.
.
.
L.geoJSON(someGeojsonFeature, {
pointToLayer: function (feature, latlng) {
const tagName = feature.properties.tagName;
const marker = L.circleMarker(latlng, geojsonMarkerOptions);
if (!tagCategories[tagName]) {
tagCategories[tagName] = [];
}
tagCategories[tagName].push({marker, feature});
return marker;
}
}).addTo(map);
.
.
.
function myFilterFunction({feature}) {
return feature.properties.year === '1981';
}
document.querySelector('.tag1Btn').addEventListener('click', () => {
const places = tagCategories[tagName].filter(myFilterFunction);
// Do whatever you need with places.
})
My best advice is to try to use vanilla js to reduce the overhead of preprocessing because libraries like jQuery, lodash and underscore do the same and in some cases are fast, but generally, Vanilla JS is faster if is used properly.
Is it possible to have multiple data layers using Google Maps API? The only existing related question I could find was this.
Here's my problem.
I want to have a data layer for showcasing polygons on map that are being drawn by the user. At the same time I want to have another data layer that displays polygons that already exist in a database.
I figured I would do this by creating 2 data layers:
drawLayer = new google.maps.Data();
savedLayer = new google.maps.Data();
But when I initialize the drawing tools using drawLayer.setControls(['Polygon']), it doesn't work. If I replace the drawLayer with map.data, then the drawing tools works fine. Why is that?
JSFiddle: http://jsfiddle.net/pjaLdz6w/
In your fiddle you aren't declaring drawLayer as a google.maps.Data object. But even if you do, you still need to give it a map attribute:
drawLayer = new google.maps.Data({map:map});
JSFiddle: http://jsfiddle.net/jbyd815y/
I wan to use marker as end point while creating object on google map using drawingManager library.
Currently its working fine but it place simple dot as end point on google map but instead of that I want to use my custom marker.
Currently when I create an object then it display like this :
But instead of that simple end point i want to use marker like this :
I have used this code from google map library.
https://developers.google.com/maps/documentation/javascript/examples/drawing-tools
You can use BitmapDescriptorFactory; something like this :-
mMap.addMarker(new MarkerOptions().position(
new LatLng(latitude, longitude)).icon(
BitmapDescriptorFactory
.fromResource(R.drawable.end_icon))
);
You can use any custom image for that.
I have a student who is using MapBox.js (v1.6.0) to display some tiles that they made in TileMill. These tiles use the Tooltip functionality provided by TileMill (documentation) to add some interactivity. My student is also using a MapBox Streets layer to give some detailed views of roadways, etc. The problem is, when I use both of these layers together in the map, the interactivity from the tiles doesn't work.
Here is the code that doesn't work:
var map = L.mapbox.map("map");
var tilesOSM = L.mapbox.tileLayer("username.id1");
var tilesTileMill = L.mapbox.tileLayer("username.id2");
map
.addLayer(tilesOSM)
.addLayer(tilesTileMill)
.setView(L.latLng(61, -160.5), 4)
.setMaxBounds(L.latLngBounds(L.latLng(50,-180), L.latLng(72,-129)));
We have tried several iterations of this code, but the only way we can get it to work is by using the L.mapbox.map(3) method and then using the _ insertAtTheBottom_ parameter of the L.map.addLayer() function.
var map = L.mapbox.map("map", "username.id2", {});
map
.addLayer(L.mapbox.tileLayer("username.id1"), true)
.setView(L.latLng(61, -160.5), 4)
.setMaxBounds(L.latLngBounds(L.latLng(50,-180), L.latLng(72,-129)));
My question is three fold.
What is the difference between these two implementations?
Why is the tileLayer created using L.mapbox.tileLayer() different than the one created and automatically added using L.mapbox.map(3)?
Are there plans to address this discontinuity in future changes to the API or will support for interactive tiles be dropped in TileMill 2?
What is the difference between these two implementations?
If you check out what L.mapbox.map does internally, it adds a gridLayer and gridControl for the layer you specify. Basically the map constructor makes all of the safe assumptions it could make and does them automatically as a convenience.
Why is the tileLayer created using L.mapbox.tileLayer() different than the one created and automatically added using L.mapbox.map(3)?
It's the same - there's a gridLayer and gridControl in the mix when you use L.mapbox.map(3), and those are what make things interactive.
Are there plans to address this discontinuity in future changes to the API
It's not as much a discontinuity than an API design: we decided to keep tileLayers decoupled from gridLayers and gridControls so you can mix & match them - if you want to switch which layer interactive features come from, or disable interactivity without disabling the tile layer, you can.
will support for interactive tiles be dropped in TileMill 2?
No, you can use TileMill 2 and see how it supports interactivity. We aren't going to remove or phase this out, though vector tiles will have new methods of interaction.
For your second example, you would want something like:
var map = L.mapbox.map("map", "username.id2", {});
var gridLayer = L.mapbox.gridLayer("username.id1").addTo(map);
var gridControl = L.mapbox.gridControl(gridLayer).addTo(map);
map
.addLayer(L.mapbox.tileLayer("username.id1"), true)
.setView(L.latLng(61, -160.5), 4)
.setMaxBounds(L.latLngBounds(L.latLng(50,-180), L.latLng(72,-129)));
I am trying to learn how to use the Javascript library leaflet along with d3 to create various map visualisations.
I have been following this tutorial which creates a choropleth map of the United States with some interactivity. This provides some of what I need, but the main functionality I want is to have a list of lat/long coordinates classified according to which region they belong to.
This would mean, in the tutorial map for example, if I had a lat long value (55, -3) which fell within the state of Arizona's polygon, the program could classify this point as belonging to Arizona.
Is there a function in the leaflet (or d3) library which will allow me to enter a lat long coordinate as a parameter and return the name of the feature it belongs to? The tutorial above allows you to attach a function to every feature via the onEveryFeature property and can fire mouseover events when each feature is hovered over. Surely there is a way to extend this functionality to numerically entered data instead of mouse points?
Leaflet would need some tweaking if you wish to do this. It leaves the handling of mouseclicks to the browser and therefore does not need logic for determining if a point lies inside a polygon.
I am not very knowledgeable about d3 but it's not glaringly obvious to me how it'd do this out of the box. Looking at the polygon code, I do find a clipping algorithm and intersection of infinite lines.
If you add a third library, however, this should be rather simple.
The OpenLayers Geometry library can determine if a point lies inside a polygon.
EDIT: I got this to work, see also http://jsfiddle.net/VaY3E/4/
var parser = new OpenLayers.Format.GeoJSON();
var vectors = parser.read(statesData);
var lat = 36;
var lon = -96;
var point = new OpenLayers.Geometry.Point(lon, lat);
for( var i = 0; i< vectors.length; i++ ){
if(vectors[i].geometry.intersects(point)){
alert(vectors[i].attributes['name']);
}
}
Or you could use https://github.com/maxogden/geojson-js-utils , a bit more specific library. It looks like it knows how to read GeoJSON and it has a method gju.pointInPolygon. I've not tested it though.