Google Maps custom marker - google-maps-api-3

I need to create a custom marker that would be similar to the look of the ClusterMarker.
I want to display the number of markers each County has.
That mark will display in the centre of the County showing the number of markers.
How would I create the marker to display the number in the middle of it.
This number would be queried from the database.
They don't need to be clickable.
Thanks

var count = markers[i].getAttribute("count");
if (count == '') {
var image = new google.maps.MarkerImage('modules/mod_boutiques_map/images/mm_20_blue.png', iconSize, null, iconAnchor);
} else if (count < 10) {
var image = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_spin&chld=0.4|0|FFFF00|9|_|"+count, null, new google.maps.Point(0, 0), new google.maps.Point(10, 34));
} else if (count < 99) {
var image = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_spin&chld=0.46|0|FFFF00|10|_|"+count, null, new google.maps.Point(0, 0), new google.maps.Point(10, 34));
} else {
var image = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_spin&chld=0.54|0|FFFF00|10|_|"+count, null, new google.maps.Point(0, 0), new google.maps.Point(10, 34));
}

Can be mad to calculate center of each country each time and, I bet, countries limits won't change so often to generate a tedious maintenance, so, as long as you will retrieve the data of the number of markers for each country, I think your best option will be to store the countries' centers custom marker's position in database, in a file or in a constant class... depends of how you develop your map.
To customize markers with special icons, hide the close button, change color, and put detailed info inside follow steps described here.
After creating a custom marker layout, and fetching data of the markers, you just have to create an array of markers and insert there all customized markers.

Related

Here Map JS cluster marker remove option

On map using cluster layer to display the marker , on API call loading the data on reload i need to clear clustered marker in the map please help on this issue,normal marker to clear using current method (map.removeObjects(map.getObjects()) it working as excepted but i need remove default cluster marker
Please find the below code :
startClustering(map, data) {
// First we need to create an array of DataPoint objects,
// for the ClusterProvider
// tslint:disable-next-line:ter-prefer-arrow-callback
const dataPoints = data.map(function (item) {
console.log('item>>>>', item);
return new H.clustering.DataPoint(item.y, item.x);
});
const clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
// Maximum radius of the neighbourhood
eps: 1,
// minimum weight of points required to form a cluster
minWeight: 2,
},
});
// Create a layer tha will consume objects from our clustering provider
const clusteringLayer = new H.map.layer.ObjectLayer(clusteredDataProvider);
// To make objects from clustering provder visible,
// we need to add our layer to the map
map.addLayer(clusteringLayer);
}
i need to remove this cluster marker before call this funcation
The easiest approach will be to keep a reference to the cluster layer you wish to remove and then remove it by:
Given a reference called clusteringLayer:
map.removeLayer(clusteringLayer);
The other alternative of using map.getLayers() to retrieve all map layers and removing each layer via map.removerLayer(<layerRef>) might remove layers you do not wish to remove.

openlayers 5 vector source does not clear, after calling clear function

In my openlayers 5 (based on a angular 6 app), I am implementing a functionality where you search for something, query the db, the db brings back some geoJSON and I render this geoJSON data in a ol vector layer.
There are two different ways to search, so there are two different forms that bring back geoJSOn to the same ol vector.
Of course, before rendering the data, I have to clear out the layer.
This is my code
ngOnInit() {//initialize some params and the ol map
//bring results-as you type - pure angular
this.results = this.myForm.valueChanges.pipe(
switchMap( formdata => this.mapcmsService.searchName(formdata.name, formdata.cepDrop))
);//pipe
this.tilesource = new OlXYZ({
url:'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
});
this.tilelayer = new OlTileLayer({
source: this.tilesource
});
this.vectorsource = new VectorSource({});
this.vectorlayer = new VectorLayer({
source: this.vectorsource
});
this.view = new OlView({
center: OlProj.fromLonLat([6.661594, 50.433237]),
zoom: 2,
});
this.olmap = new OlMap({
target: 'map',
layers: [this.tilelayer,this.vectorlayer],
view: this.view,
projection: 'EPSG:3857'
});
const selectClick = new Select({
condition: click,
layers:[this.vectorlayer]
});
this.olmap.addInteraction(selectClick);
selectClick.on(
'select', ()=>{
const values = selectClick.getFeatures().item(0).values_;
this.getDetails(values.id);
}
);
} //closes ngOnInit
Outside the ngOnInit, after the initialization,there are the two different functions that bring geoJSON to the same ol vector layer. They basically do the same thing.
searchById(id){
this.map_loading = true;
this.myService.getById(id).subscribe((data) =>{
this.vectorsource.refresh();
this.vectorsource.clear();
const fff = (new GeoJSON()).readFeatures(data.data);
this.vectorsource.addFeatures(fff);
this.map_loading = false;
})
}//searchById
and
searchCategories(){
this.map_loading = true;
this.myService.categoriesSearch(this.categoriesForm.value).subscribe((data) =>{
this.vectorsource.refresh();
this.vectorsource.clear();
const fff = (new GeoJSON()).readFeatures(data.data);
this.vectorsource.addFeatures(fff);
this.map_loading = false;
})
}//searchCategories
The problem is that the ol vector source is not always cleared before new features are added. I search for something, features are rendered. I search again , and sometimes, the old features remain on the map, along with the new ones.
I did a silly move to add refresh with clean and nothing is fixed. This is not standard, eg every other search. This randomly happen and I dont have a clue how to debug it. Please advice
Thanks
Is there an unique id for each feature?
I had the same problem that features were loaded constantly. I used the bbox-strategy and every time I moved the map, it loaded all the features in the extent, even if they were already there.
I had to set an unique id in the data for my features, so OpenLayers can refer to the existing ones if you load new ones. This randomness maybe comes through the generated ids for the features, that are sometimes equal to the new ones and sometimes not.
Dont know if that faces your problem, it just flew into my brain while I read that.

Filter Google Map markers with multiple [and intersecting] check boxes

I can't make my multiple-check-box filtering system to work. I'll explain the problem, the research I've done here on stackoverflow, and why I still need help after that.
My problem is that my check boxes can't bring back the markers when I gradually unselect them. These said filters work well when I click them, because they incrementally fade away the markers associated with them. However, after just unselecting a couple of these checkboxes, all the markers are back on screen, and the last boxes don't do anything when they are finally unclicked.
This is the temporary URL of the project: http://www.lcc.gatech.edu/~amartell6/php/main12.php
This is the code where I'm getting stuck:
//this getJson function exists within an init funciton where a map
//has already been called
$.getJSON(theUrl,function(result){
$.each(result, function(i, item){
//get Longitude
var latCoord = item.coordinate;
var parenthCoord = latCoord.indexOf(",");
var partiaLat = latCoord.substr(1,parenthCoord-1);
var lat = parseFloat(partiaLat);
//alert(lat);
//get Latitude
var lngCoord = item.coordinate;
var commaCoord = lngCoord.indexOf(",");
var partiaLng = lngCoord.substr(commaCoord+1);
var lng = parseFloat(partiaLng);
//alert(lng);
// display ALL the story markers
var storyMarker;
storyMarker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),// ----- > whithin the mutidimentional array,
map: map
});
//display the stories by clicking on the markers
google.maps.event.addListener(storyMarker, 'click', function() {
var from = "From ";
if(item.end_date != ""){
item.end_date = " to " + item.end_date;
}
else{
from = "";
}
$('#output').html(
'<p><span class="selected">Type of Entry: </span>' +
item.entry_type + ' <br/><br/>'+
'<span class="selected">Title: </span>'+ item.entry_title + '<br/><br/>' +
'<span class="selected">Date(s):</span><br/>'+ from +item.start_date+
//' to '+item.end_date+'<br/><br/>'+
item.end_date+'<br/><br/>'+
'<span class="selected">Content:</span><br/><br/> '+ item.entry
+'</p>'
);
});// end of story displays
//call filters from filter funciton
filter('#evacuation-filter',item.evacuation,"Yes");
filter('#evacuation-order-filter',item.evacuation_order,"Yes");
filter('#w-nearby-filter',item.w_nearby,"Yes");
filter('#hurricane-reached-filter',item.hurricane_reached,"Yes");
filter('#outdoors-filter',item.in_out_doors,"Outdoors Most of the Time");
filter('#indoors-filter',item.in_out_doors,"Indoors Most of the Time");
filter('#food-filter',item.food,"Yes");
filter('#windows-filter',item.windows,"Yes");
filter('#power-filter',item.power,"Yes");
filter('#wounded-filter',item.wounded,"Yes");
filter('#looting-filter',item.looting,"Yes");
filter('#blackouts-filter',item.blackouts,"Yes");
filter('#trees-filter',item.trees,"Yes");
filter('#powerlines-filter',item.powerlines,"Yes");
filter('#light-filter',item.light,"Yes");
filter('#sidewalks-filter',item.sidewalks,"Yes");
filter('#buildings-filter',item.buildings,"Yes");
filter('#flooding-filter',item.flooding,"Yes");
//FILTER FUNCTION
//first parameter is the checkbox id, the second is the filter criteria
//(the filter function has to be called within the $.each loop to be within scope)
var otherFilter = false;
function filter(id, criterion1, value){
var activeFilters = [];
$(id).change(function() {
//evalute if the checkbox has been "checked" or "unchecked"
var checkBoxVal = $(id).attr("checked");
//if it's been checked:
if(checkBoxVal=="checked"){
//1 - Get markers that don't talk about the filter
if(criterion1!=value && storyMarker.getVisible()==true){
//2 - fade them away, and leave only those meet the criteria
storyMarker.setVisible(false);
otherFilter = true;
activeFilters.push(criterion1);
//document.getElementById("text3").innerHTML=activeFilters+"<br/>";
//alert(activeFilters.push(criterion1) +","+criterion1.length);
}
}
//if it's been unchecked:
else if(checkBoxVal==undefined){
//1 - Get markers that don't talk about the filter
if(criterion1!=value && storyMarker.getVisible()==false){
//2 - Show them again
storyMarker.setVisible(true);
otherFilter = false;
activeFilters.pop(criterion1);
//alert(activeFilters.pop(criterion1) +","+criterion1.length);
} //end of if to cancel filter and bring markers and stories back
}
}); // end of change event
} // end of filter function
//var otherDropDown = false;
filter2("#media-filter",item.media);
filter2("#authorities-filter",item.authorities);
//---------------
function filter2(id2,criterion2){
$(id2).change(function() {
//get the value of the drowpdown menu based on its id
var dropDownVal = $(id2).attr("value");
var all="All";
//if the value isn't "All", other filters have not been applied, and marker is on screen
if(dropDownVal!=all && otherFilter==false){
//1 - check if the marker doesn't comply with filter
if(criterion2!=dropDownVal){
//2 - fade them away if not, and leave only those meet the criteria
storyMarker.setVisible(false);
//3 - If the marker does comply with it
}else if(criterion2==dropDownVal){
//4 - keep it there
storyMarker.setVisible(true);
}//end of filter applier
//else if if the value IS "All", filters have not been applied, and marker is faded
}else if(dropDownVal==all && otherFilter==false){
//select all the possible values for the cirterion
if(criterion2!=undefined){
//and show all those markers
storyMarker.setVisible(true);
}
}
});
} //end of function filter2
}); // end of $.each
}); // end of $.getJSON
I found one related blog post. This one suggests adding a category to the markers. However, when I do that, the filters keep working the same way. I think this happens because each filter is programmed to hide every single marker that meets their selecting criteria, but each marker has more than one property they can be filtered with.
Do you know if there is a way to make the script detect how many filters point towards the same marker, and only show it back if no filters are pointing at it? This is my guess on how to solve it, even though I don't know how to make it happen in code.
Finally, if you know of alternate ways to make the filters work, let me know.
I created an application with similar logic several years ago http://www.ioos.gov/catalog/ But it was for GMap 2.0 but I think the logic would be the same.
My approach was to extend the Google maps Marker object (already bloated) with features I wanted to filter them on.
These would be all the properties you're storing in your 'click' listener and perhaps more: e.g. item.title, item_start_date, etc. whatever you eventually want to filter your marker by.
var all_markers = [];
storyMarker.end_date = item.end_date;
storMarker.title = item.title;
...
all_markers.push(storyMarker);
Then when you want to filter loop thru all the markers, check the marker value against the filter condition and setVisible(true) or false as need.
Erik already provided a solution to my problem. However, I think the community may benefit from reading other options, and I want to share the solution I came up with. Even if it may not be the most effective, it works.
In the code I just mentioned, I declared all the storyMarkers at once when the map initializes:
// display ALL the story markers
var storyMarker;
storyMarker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),// ----- > whithin the mutidimentional array,
map: map
});
Now, I added a new argument to the markers, but instead of creating a variable as in the example I had found in other post, this argument was an empty array:
storyMarker.pointer = [];
The previous filter function had three levels. The first level detected a change in the check box. The second one verified whether the check box had been checked or unchecked. The third level ran the filter on e-v-e-r-y marker, either to show it or hide it.
This is where my solution began. Within the most inner if statement of the filter function, I added a discretionary element within the pointer array:
storyMarker.pointer.push("element");
Right after this, I nested a new if statement to check if the array is not empty. If it indeed isn't empty, the program hides the marker that this array belongs to.
The program inverses the logic when a box is unchecked. It calls-off the filter, subtracts one element from the array associated with that marker, and then checks if there are other markers associated with it. The system now only shows up markers whose arrays are empty.
//alert(storyMarker.pointer);
function filter(id,criterion,value){
$(id).change(function() {
var checkBoxVal = $(id).attr("checked");
if(checkBoxVal=="checked"){
if(criterion!=value){
storyMarker.pointer.push("element");
//alert("array length: "+storyMarker.pointer.length);
if(storyMarker.pointer.length>0){
storyMarker.setVisible(false);
}
}
}
else if(checkBoxVal!="checked"){
if(criterion!=value){
storyMarker.pointer.pop("element");
//alert("array length: "+storyMarker.pointer.length);
if(storyMarker.pointer.length<=0){
storyMarker.setVisible(true);
}
}
}
});
}
In summary, the script is still clicking a marker more multiple times if the user clicks on more than one marker. The system can now recognize how many times is one marker pointed out, and only show the one that has no pointers at all.

Automatically Finding Appropriate Zoom for Geocoding Result

I'm using Google Maps and Google Geocoding service for my location service application. I use Google Geocoding service for translating address to lat/lng position. My problem is how to automatically find an appropriate zoom for a certain address like the maps.google.com does.
For example, when I search a street in maps.google.com (e.g. Cisitu Baru, Bandung), it will show the street in smaller zoom. When I search a region (e.g. Bandung), it will show larger zoom. And a larger zoom for province (e.g. Jawa Barat / West Java), and so on.
I have tried both
var geocoder = new google.maps.Geocoder();
geocoder.geocode( {
'address': someAddress
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
console.dir(results);
//cut
map.panToBounds(results[0].geometry.bounds); //setting bound
//cut
}
});
and
//cut
map.panToBounds(results[0].geometry.viewports); //setting bound
//cut
(Honestly, I still don't know what's the difference between bounds and viewport and what are their uses from code.google.com/apis/maps/documentation/javascript/geocoding.html)
but both still don't display the map in appropriate zoom.
Right now, I use a small hack like this
var tabZoom = {
street_address: 15,
route: 15,
sublocality: 14,
locality: 13,
country: 10
};
//cut
map.setCenter(results[0].geometry.location);
if (tabZoom[results[0].types[0]] != undefined){
map.setZoom(tabZoom[results[0].types[0]]);
} else {
map.zetZoom(10);
}
//cut
Is there other solution? (Or anything from Google Map API that I don't know yet?)
Thanks!
use GLatLngBounds class
an example:
// map: an instance of GMap2
// latlng: an array of instances of GLatLng
var latlngbounds = new GLatLngBounds( );
for ( var i = 0; i < latlng.length; i++ )
{
latlngbounds.extend( latlng[ i ] );
}
map.setCenter( latlngbounds.getCenter( ), map.getBoundsZoomLevel( latlngbounds ) );
^
The trick is to add the list of all points that need to be visible on the map simultaneously into a GLatLngBounds object. The Google Maps API can do the rest of the maths.
or in v3 you can use LatLngBounds class (similar to GLatLngBounds in v2), link: http://code.google.com/apis/maps/documentation/javascript/reference.html#LatLngBounds
for an example
better check this out: http://unicornless.com/code/google-maps-v3-auto-zoom-and-auto-center
use viewport of the result geometry. if your search result does not have specific bounds, you will get an error with geometry.bounds
viewport gives you best view for the result.
map.fitBounds(results[0].geometry.viewport);

Removing an individual marker from Google Map - API v3

I want to remove an individual marker from Google map. I am using version 3 API. I know how I can remove all the markers by maintaining a markerArray and setting map null for all.
For removing one by one, I am thinking to make a key value pair combination. So that I give a key and remove the particular marker. I need help over this.
Following is the code, that I use to dram marker:
function geoCodeAddresses(data) {
var markerInfo = {addressKey: '', marker:''};
for (var i = 0; i < data.length; i++) {
myLocation = data[i];
geocoder.geocode({"address":myLocation}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({map:map, position:results[0].geometry.location});
// checkpoint A
alert(myLocation);
/*
markerInfo.addressKey = myLocation;
markerInfo.marker = marker;*/
//mArray.push(markerInfo);
}
});
}
}
I will search for addresskey and remove the marker from mArray. But I get last value every time in geocode callback method. And one object got pushed every time. the var myLocation always give me the address of the last index of my array. If I alert it at check point A.
My approach is right?
Your problem is this line:
mArray.push(markerInfo);
That doesn't push the values of markerInfo into your array. It pushes a reference to markerInfo into your array. Now, on your next iteration of the loop, when you change the value of markerInfo, it changes the value pointed at by the references in the array too. So your array ends up having elements that all have the same value.
Try this instead:
mArray.push({addressKey:myLocation,marker:marker});
If that doesn't work, then this:
mArray.push({addressKey:data[i],marker:marker});

Resources