HERE maps: show both clustered and not clustered points - here-api

My goal is to display a group of clustered data points and one data point of different nature that never goes to a cluster in the same layer, so they all can received hover mouse events.
Is it possible to tell H.clustering.Provider to always exclude some points from clusters, or create a custom H.map.provider.ObjectProvider that can do it?
P. S.
I tried creating two layers and setting pointer-events: none for them in CSS to catch hover events by all points, it worked but made the map too slow to use.
Update
Here is a demo code, the goal is to get a hover rectangle for both markers with a condition that the first market should never be included to a cluster
<html>
<head>
<script src="http://js.api.here.com/v3/3.0/mapsjs-core.js" type="text/javascript" charset="utf-8"></script>
<script src="http://js.api.here.com/v3/3.0/mapsjs-service.js" type="text/javascript" charset="utf-8"></script>
<script src="http://js.api.here.com/v3/3.0/mapsjs-clustering.js" type="text/javascript" charset="utf-8"></script>
<style>
svg:hover {
border: 2px solid red;
}
</style>
</head>
<body>
<div id="mapContainer"/>
<script>
var platform = new H.service.Platform({
'app_id': 'my id',
'app_code': 'my code'
});
var defaultLayers = platform.createDefaultLayers();
var map = new H.Map(
document.getElementById('mapContainer'),
defaultLayers.normal.map,
{
zoom: 10,
center: { lat: 51.5, lng: 13.4 }
});
//this marker should not go to clusters
var marker = new H.map.DomMarker({ lat: 51.5, lng: 13.4 });
map.addObject(marker);
//this marker should go to clusters if there is more data points
var dataPoints = [];
dataPoints.push(new H.clustering.DataPoint(51.5, 13.45));
var theme =
{
getClusterPresentation: function(cluster){
return new H.map.DomMarker(cluster.getPosition(), {});
},
getNoisePresentation: function(point){
return new H.map.DomMarker(point.getPosition(), {});
}
}
var clusteredDataProvider = new H.clustering.Provider(dataPoints, {
theme: theme,
});
var layer = new H.map.layer.ObjectLayer(clusteredDataProvider);
map.addLayer(layer);
</script>
</body>
</html>

The following example shows a cluster provider initialized with the parameters eps and minWeight. eps holds the value of the radius within which data points are considered for clustering, while minWeight holds the cumulative weight that points lying close to another must reach or exceed to be clustered. The value of minWeight is 3 in the example, which means that three points, each with the weight of one or two data points with the weight of 2 and 1, respectively, form a cluster. This will reduce the time of rendering the page. Also please refer the new documentation :
https://developer.here.com/documentation/examples/maps-js/clustering/marker-clustering
var clusteredDataProvider = new H.clustering.Provider(dataPoints, {
min: 4,
max: 10,
clusteringOptions: {
eps: 32,
minWeight: 3
}
});

Related

Find attached child objects of a-frame/ a-marker

I have a small A-frame based program to render text on a marker. When user click on the marker, I would like to scale the text, so it will be more visible. I can capture the click-event on the marker but how can I get it's child entities to scale?
My code can be found in https://codepen.io/asatrash/pen/rNLMgpa
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar.js"></script>
</head>
<body>
<script>
//Multi Markers WebAR-AR.js and Aframe - Playing the Archive - Connected Environment CASA-UCL
//Global Variable
var markersURLArray=[];
var markersNameArray=[];
var allow_clicks = false;
AFRAME.registerComponent('markers_start',{
init:function(){
console.log('Add markers to the scene');
var sceneEl = document.querySelector('a-scene');
//list of the markers
for(var i=1; i<6; i++)`enter code here`
{
var url="https://raw.githubusercontent.com/asatrash/ARInWeb/main/resources/markers/pattern-Individual_Blocks-3.patt";
markersURLArray.push(url);
markersNameArray.push('Marker_'+i);
//console.log(url);
}
for(var k=0; k<5; k++)
{
var markerEl = document.createElement('a-marker');
markerEl.setAttribute('type','pattern');
markerEl.setAttribute('url',markersURLArray[k]);
markerEl.setAttribute('id',markersNameArray[k]);
markerEl.setAttribute('registerevents','');
sceneEl.appendChild(markerEl);
var boxEl = document.createElement('a-box');
boxEl.setAttribute('id','box');
boxEl.setAttribute('depth','0.001');
boxEl.setAttribute('width','6');
boxEl.setAttribute('height','4');
boxEl.setAttribute('opacity','0.25');
boxEl.setAttribute('position','0 -2 -4');
boxEl.setAttribute('rotation','0 0 0');
boxEl.setAttribute('material', {color: '#000000'});
markerEl.appendChild(boxEl);
var textEl = document.createElement('a-text');
textEl.setAttribute('id','text');
textEl.setAttribute('text',{color: '#ffff00', align: 'left', value:'This is a very log text /b \n line which might or might not wrap', width: '2' });
//textEl.setAttribute('position', '-1.4 1.5 0');
textEl.setAttribute('position', '-2.5 1.5 0')
textEl.setAttribute('scale', '2 2 0');
boxEl.appendChild(textEl);
}
}
});
//Detect marker found and lost
AFRAME.registerComponent('registerevents', {
init: function () {
const marker = this.el;
marker.addEventListener("markerFound", ()=> {
var markerId = marker.id;
console.log('Marker Found: ', markerId);
allow_clicks = true;
});
marker.addEventListener("markerLost",() =>{
var markerId = marker.id;
console.log('Marker Lost: ', markerId);
allow_clicks = false;
});
marker.addEventListener('click', (evt) => {
if (allow_clicks){
console.log("CLICKED!!!" + marker.id);
//I want to scale the box and the text attached to the marker jere
}
});
},
});
</script>
<a-scene markers_start vr-mode-ui="enabled: false" color-space="sRGB" renderer="gammaOutput: true"
embedded arjs='debugUIEnabled: false; sourceType: webcam; patternRatio: 0.85; trackingMethod: best;'>
<a-entity id='userCamera' camera look-controls >
<a-cursor> </a-cursor>
</a-entity>
</a-scene>
</body>
</html>
Did bit more testing and found out the following.
The 'click' event doesn't work as I expected on the marker. It is registered to the whole scene and it get invoked irrespective of the place I click. Which is not what I want. I am looking at using intersection Points to get it working.
However the getting access to the child can be easily done if you put unique ids. We can use the normal document.getElementById("boxelementId"); and change the attributes using the setAttribute method.
Ex: To change the text
var markerTextEl = document.getElementById(markerTextxId);
markerTextEl.setAttribute("value", "Current Temperature is: " + data);
I used above inside the 'markerFound' event to show different/current value when user point to a particular marker.

How to make an info window clickable?

I have the below code, based on one of the API samples. A click on the map creates a marker. A click on the marker opens up an info window. Now I want a click on the info window to do something. E.g. a click anywhere might close it, as opposed to the little cross in the corner. Or a click on it might open a new URL. Etc.
Unfortunately it seems there is no "click" event for info windows.
The closest I've got is shown as a commented out line below: I wrap my info window content in a div, and give that an onClick. This works, but there is a big border around it. I really want to be able to click anywhere in the info window box.
Is there a way?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Click Test</title>
<script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script>
google.maps.visualRefresh = true; //New look visuals.
function initialize() {
var useragent = navigator.userAgent;
var mapdiv = document.getElementById("map-canvas");
if (useragent.indexOf('iPhone') != -1 || useragent.indexOf('Android') != -1 ) {
mapdiv.style.width = '100%';
mapdiv.style.height = '100%';
} else {
mapdiv.style.width = '400px';
mapdiv.style.height = '600px';
}
var mapOptions = {
zoom:3,
center: new google.maps.LatLng(37.09024, -95.712891),
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
google.maps.event.addListener(map, 'click', function(event) {
placeMarker(event.latLng);
});
function placeMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map
});
var infowindow = new google.maps.InfoWindow({
//content: "<div onClick='test1()'>(lat,lng):<br/>"+location.lat()+","+location.lng()+"</div>"
content: "(lat,lng):<br/>"+location.lat()+","+location.lng()
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(marker.get('map'), marker);
infowindow.addListener('click',test1); //Does nothing
});
}
}
google.maps.event.addDomListener(window, 'load', initialize);
function test1(){alert("test1");}
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
UPDATE:
This image shows the problem when I use a clickable div inside the content (background set to red to show the extent of the region I can make clickable, and also that I can style; if I set a negative margin I just get scrollbars, not a bigger region!). It is the whole white area I want to be clickable, not just that red rectangle.
I decided to use InfoBox found in the Google Maps Utility Library. So in the header add a link to the library. Then replace the new google.maps.InfoWindow() line with this one:
var infowindow = new InfoBox({
closeBoxURL:"",
content: '<div onClick="test1();return false;" style="background:white;opacity:0.8;padding:8px">(lat,lng):<br/>'+
location.lat()+","+location.lng()+"</div>"
});
By setting closeBoxUrl to a blank string I get no close option. I added a large padding just so you can see that clicking right to the edge does indeed work.
You can also do it this way. I also use the boxClass option so the formatting is done in CSS:
var infoContent=document.createElement('div');
infoContent.innerHTML="(lat,lng):<br/>"+location.lat()+","+location.lng();
infoContent.onclick=test1;
var infowindow = new InfoBox({
closeBoxURL:"",
boxClass:"marker_popup",
content: infoContent,
});
(Aside, if doing it this way, on just some browsers it creates a marker below the InfoBox! Simplest fix is to change test1 so it looks like: function test1(event){alert("test1");event.preventDefault();return false;} )
P.S. I chose InfoBox over InfoBubble, as the latter has no documentation, and it had no obvious advantages to compensate for that major flaw! InfoBox has documentation and a reference. (links are for version 1.1.9)

Google Maps: how to efficiently change marker when mouseover

I want to dynamically change the color/text of any google maps marker.
Run the code: http://jsbin.com/odimop/edit#javascript,html,live
As you can see the problem of using a variable (var styloo) is when properties change then all markers using that variable behave in the same way, in this case marker4 and marker5. This approach is cumbersome and tedious when the map has too many markers because each marker will need one styled variable
I'm looking for a solution that use something like: this.styleIcon.color = "00ff00";. But so far is not working.
Any idea? please!
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/styledmarker/src/StyledMarker.js"></script>
<script type="text/javascript">
var styleIcon;
function initialize() {
var myLatLng = new google.maps.LatLng(37.313477473067, -121.880502070713);
var myOptions = {
zoom: 10,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var marker2 = new StyledMarker({styleIcon:new StyledIcon(StyledIconTypes.BUBBLE,{color:"00ffff",text:"Hover Me, this doesn't work"}),position:new google.maps.LatLng(37.5, -121.880502070713),map:map});
var marker3 = new StyledMarker({styleIcon:new StyledIcon(StyledIconTypes.BUBBLE,{color:"ff0000",text:"Just a Marker"}),position:new google.maps.LatLng(37.4, -121.880502070713),map:map});
google.maps.event.addDomListener(marker2,"mouseover", function(o){
this.setAnimation(google.maps.Animation.BOUNCE);
this.styleIcon.color = "00ff00";
this.styleIcon.text = "it does not change :(";
});
styloo = new StyledIcon(StyledIconTypes.BUBBLE,{color:"#95AA7B",text:"click me!",fore:"#ffffff"});
var marker4 = new StyledMarker({styleIcon: styloo,position:new google.maps.LatLng(37.2, -121.88),map:map});
var marker5 = new StyledMarker({styleIcon: styloo,position:new google.maps.LatLng(37.1, -121.88),map:map});
google.maps.event.addDomListener(marker4,"click", function(o){
this.setAnimation(google.maps.Animation.BOUNCE);
styloo.set("fore","#ffffff");//test color
styloo.set("color","#C2554D");// background color
styloo.set("text","color changed");
});
}
</script>
</head>
<body style="margin:0px; padding:0px;" onload="initialize()">
<div id="map_canvas" style="width: 600px; height: 600px;"></div>
</body>
As per StyledMarker examples, you need to use the set(property, value) methods, like this:
styleIcon.set("text","Elevation: " + results[0].elevation + "m");
In your case, change the mouseover handler to this:
this.styleIcon.set('color', '00ff00');
this.styleIcon.set('text', 'it does not change :(');
As for the other problem, where both change at once, you'll need to create a StyledIcon for each StyledMarker. I'd just add a function that returns a new icon each time.
function createStyle() { return new StyledIcon(StyledIconTypes.BUBBLE,{color:"#95AA7B",text:"click me!",fore:"#ffffff"}); }
var marker4 = new StyledMarker({styleIcon: createStyle(),position:new google.maps.LatLng(37.2, -121.88),map:map});
var marker5 = new StyledMarker({styleIcon: createStyle(),position:new google.maps.LatLng(37.1, -121.88),map:map});
google.maps.event.addDomListener(marker4,"click", function(o){
this.setAnimation(google.maps.Animation.BOUNCE);
this.styleIcon.set("fore","#ffffff");//test color
this.styleIcon.set("color","#C2554D");// background color
this.styleIcon.set("text","color changed");
});

Google Maps api v3 - circle without fill or unclickable fill

.. and sorry for my english.
I'm trying to create circle without fill with google maps api v3. I know that I can set opacity (and fill disapired), but this no-visible fill is still clickable. I need to set fill unclickable, but stroke have to be clickable. Under my circle there are few points and lines, that have to be clickable and circle is upper, than lines, for example. My idea was move circle to different pane, but I didn't find way how to do it. Is there a solution for it?
Thanks!
Ajax
[EDIT]
Here is code sample. My problem is, that I'm not able to click on map or line inside blue circle.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>
<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?key=YOUR_GMAP+API_KEY&sensor=true">
</script>
<script type="text/javascript">
function initialize() {
var lat = 49;
var lon = 15;
var myOptions = {
center: new google.maps.LatLng(lat,lon),
zoom: 18,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, "click", function(clickEvt) {
alert('mapClicked');
});
var line = new google.maps.Polyline({
path: [new google.maps.LatLng(lat + 0.001, lon + 0.001),new google.maps.LatLng(lat - 0.001, lon - 0.001)],
strokeColor: '#00FF00',
map: map
});
google.maps.event.addListener(line, "click", function() {
alert('Line clicked');
});
var circle = new google.maps.Circle({
strokeColor: '#0000FF',
strokeWeight: 2,
fillOpacity: 0,
map: map,
center: new google.maps.LatLng(lat, lon),
radius: 100
});
google.maps.event.addListener(circle, 'click', function(event) {
alert('circle clicked');
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>
set 'clickable: false` in the circle option object to allow the click event be detected in the map layer.
var circle = new google.maps.Circle({
strokeColor: '#0000FF',
strokeWeight: 2,
fillOpacity: 0,
map: map,
center: new google.maps.LatLng(lat, lon),
radius: 100,
clickable: false
});
reference: Unclickable fill in Circle?
Try this: draw 2 circles, one for your outline (clickable) and one for your fill (not clickable). The fill circle should be slightly smaller, and set its z-index to sit on top of the other one, preventing you clicking on anything but the outline circle. The problem will be the other items you want to remain clickable underneath the circle.

How can I show label/title for marker permanently in Google Maps V3?

I want to display Markers on Google map with title displayed under them as shown in picture:
Now this I read was possible in v2 using ELabel but is deprecated in v3. Is there any possible way to show some text under icons of markers in Google Maps V3?
Since at least October 2016, the official API provides a way to add permanently visible labels that are longer than one letter. See this reply by a Google project member.
var m = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
label: 'Hello world',
});
By default, the result looks like:
Pretty unreadable. Fortunately the API also allows a MarkerLabel object instead of a plain string:
var m = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
label: {
color: 'white',
fontWeight: 'bold',
text: 'Hello world',
},
});
Snippet above yields the following result:
However, the original question asked if the label could be located below the marker. The MarkerLabel docs mention this is possible with a custom icon and labelOrigin property. If we want to use the default icon, one is available at GitHub. Let us add the icon object:
var m = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
label: {
color: 'white',
fontWeight: 'bold',
text: 'Hello world',
},
icon: {
labelOrigin: new google.maps.Point(11, 50),
url: 'default_marker.png',
size: new google.maps.Size(22, 40),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(11, 40),
},
});
This results:
Pretty good! However, this whole approach has a shortcoming that the box in the original question does not have: readability with each map type. If the map type is changed from the satellite to the default the resulting label is hard to read:
An easy but not perfect way to avoid the low contrast in the both types is to set color: 'gray':
However, the gray color fails near urban areas. A better option would be to apply text-shadow CSS property to draw black linings for the white text. However, I cannot find a way to apply the property to the labels because few DOM elements created by Google Maps define a class:
The best option I came up to is to detect changes in the map type and update label color for each marker:
map.addListener('maptypeid_changed', function () {
var typeToColor, type, color, k, label;
typeToColor = {
'terrain': 'black',
'roadmap': 'black',
'hybrid': 'white',
'satellite': 'white',
};
type = map.getMapTypeId();
color = typeToColor[type];
for (k in markers) {
if (markers.hasOwnProperty(k)) {
label = markers[k].getLabel();
label.color = color;
markers[k].setLabel(label);
}
}
});
However, even this would fail on snowy or cloudy satellite imagery. I think it is still good enough in most of the cases. Nevertheless, it is nice to have the ability to display visible labels with the official API, without any plugins :)
I found the solution in an other post which worked perfectly for me.
Add numbering label to google map marker
You can't! But there's another part of maps API you can use to have permanently displayed text attached to your markers (without requiring any third party component), it's called infoWindow. Have a look at this for sample code & see it in action: https://developers.google.com/maps/documentation/javascript/examples/event-closure
If you dare using third party code, then here's something that is closer from the look & feel you want: http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/examples.html
I use the following:
MarkerWithLabel.js
( the image is just a flag.png file)
Using javascript in my X.html document
it looks something like this....
<style type="text/css">
.labels {
color: black;
background-color: white;
font-family: "Lucida Grande", "Arial", sans-serif;
font-size: 0.8em;
font-weight: bold;
text-align: center;
width: 6em;
border: 1px solid black;
white-space: normal;
}
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3.9&sensor=true"></script>
<!--MarkerwithLabelClass - adjust the path!! -->
<script src="YourPathHere/markerwithlabel.js"></script>
<script type="text/javascript">
//insert standaard initializing of googlemaps here
//and other windows.onload function
window.onload = function Initialize() {
var myOptions = {
zoom: 8,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
function CreateMarker(lat, long, titel, label, image, anchorY, anchorX){
var latlng = new google.maps.LatLng(parseFloat(lat), parseFloat(long));//I use parseFloat cause my parameters are strings(coming from JSON-string)
var marker = new MarkerWithLabel({
zIndex: 1,
title: titel,
position: latlng,
draggable: false,
icon: image,
labelContent: label,
labelAnchor: new google.maps.Point(30, -2),
labelClass: "labels", // the CSS class for the label
labelStyle: { opacity: 0.80 }
});
return marker;
}
</script>
Read up on license info for google maps API here : https://www.google.com/intx/en_uk/work/mapsearth/products/mapsapi.html
You should be able to use the same principle as in this example. Instead of listening to the mouse events you should create a new custom control for each marker and then position it below the marker. Hope it works out.

Resources