Google Maps Searchbox Positioning (library angular-google-maps) - javascript

I try to position the Google Maps searchbox variable. A list shows all markers and under those markers there should be the searchbox. As the list grows the searchbox moves down. I use this library: Angular Google Maps
There is a directive called <ui-gmap-search-box>. But it must be inside <div id="map_canvas"> </div> and the list is outside of that div.

I think you should use the custom control functions provided by the Google Maps API.
You can position your controls on the top left corner of your maps, and create click event listeners for your control and do your work from there.
Refer to the documentation for more information on Custom Controls.
Also, I made some quick changes to this sample, and made this example here. Hope it helps.
var map;
//var chicago = new google.maps.LatLng(41.85, -87.65);
/**
* The CenterControl adds a control to the map that recenters the map on Chicago.
* This constructor takes the control DIV as an argument.
* #constructor
*/
controlUIs = [];
function CenterControl(controlDiv, map) {
locations = [new google.maps.LatLng(37.7833, -122.4167),
new google.maps.LatLng(37.3382, -121.8863),
new google.maps.LatLng(37.4223662, -122.0839445),
new google.maps.LatLng(37.8694772, -122.2577238),
new google.maps.LatLng(37.7919615, -122.2287941),
new google.maps.LatLng(37.6256441, -122.0413544)
];
for (var i = 0; i < locations.length; i++) {
// Set CSS for the control border
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = '#fff';
controlUI.style.border = '2px solid #fff';
controlUI.style.borderRadius = '3px';
controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';
controlUI.style.cursor = 'pointer';
controlUI.style.marginBottom = '22px';
controlUI.style.textAlign = 'center';
controlUI.title = 'Click to recenter the map';
controlUIs[i] = controlUI;
controlDiv.appendChild(controlUIs[i]);
// Set CSS for the control interior
var controlText = document.createElement('div');
controlText.style.color = 'rgb(25,25,25)';
controlText.style.fontFamily = 'Roboto,Arial,sans-serif';
controlText.style.fontSize = '16px';
controlText.style.lineHeight = '38px';
controlText.style.paddingLeft = '5px';
controlText.style.paddingRight = '5px';
controlText.innerHTML = 'Location ' + i;
controlText.location = locations[i];
controlUIs[i].appendChild(controlText);
// Setup the click event listeners: simply set the map to
// Chicago
google.maps.event.addDomListener(controlUIs[i], 'click', function(click) {
map.setCenter(click.target.location)
});
}
}
function initialize() {
var mapDiv = document.getElementById('map-canvas');
var mapOptions = {
zoom: 10,
center: new google.maps.LatLng(37.6326196, -122.1568744)
}
map = new google.maps.Map(mapDiv, mapOptions);
// Create the DIV to hold the control and
// call the CenterControl() constructor passing
// in this DIV.
var centerControlDiv = document.createElement('div');
var centerControl = new CenterControl(centerControlDiv, map);
centerControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_LEFT].push(centerControlDiv);
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0;
padding: 0;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script>
<div id="map-canvas"></div>

I used the Google Maps API Search box instead of the library's search box.
main.js:
var searchBox = function() {
var input = document.getElementById('autocomplete');
var searchBox = new google.maps.places.SearchBox(input);
google.maps.event.addListener(searchBox, 'places_changed', function() {
});
}; // end searchBox
The function searchBox() is executed in $scope.init().
index.html:
<input id="autocomplete" ng-model="newPlace" type="text">

Related

DomMarkers and DomIcons not working inside a ShadowRoot

I'm trying to use DomMakers and DomIcons inside a ShadowRoot. When the markers load, I get this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'getPropertyValue')
at rm.Ga (mapsjs-core.js:350:435)
at kn (mapsjs-core.js:376:338)
at S.Ga (mapsjs-core.js:376:52)
at T.de (mapsjs-core.js:408:437)
at $o (eval at <anonymous> (mapsjs-core.js:73:36), <anonymous>:5:219)
at Zo (eval at <anonymous> (mapsjs-core.js:73:36), <anonymous>:4:425)
at fp.g (eval at <anonymous> (mapsjs-core.js:73:36), <anonymous>:16:301)
This happens because mapsjs-core can't find the canvas element, since it's inside a ShadowRoot. Here is the code snippet where the error occurs:
var r = g.style;
f.push({
Aj: r.getPropertyValue(tm),
bo: r.getPropertyPriority(tm),
style: r
});
g is supposed to be the map canvas, but inside a ShadowRoot it's the document element
I'm using Here Maps API for Javascript v3.1.30.7 on a React app.
If I change to Markers and Icons the problem is gone, but I lose the interactivity I need.
It works only in this way:
https://jsfiddle.net/ba2oL057/2/
function drawCanvas() {
var canvas = document.createElement('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.fillRect(25, 25, 100, 100);
ctx.clearRect(45, 45, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
}
return canvas;
}
/**
* Create a marker that is capable of receiving DOM events and add it
* to the map.
*
* #param {H.Map} map A HERE Map instance within the application
*/
function addDomMarker(map) {
function setToShadow(outerElement){
var innerElement = document.createElement('div');
outerElement.attachShadow({mode: 'open'});
outerElement.shadowRoot.innerHTML = `
<div></div>
`;
let outerShElem = outerElement.shadowRoot.querySelectorAll('div')[0];
outerShElem.style.userSelect = 'none';
outerShElem.style.webkitUserSelect = 'none';
outerShElem.style.msUserSelect = 'none';
outerShElem.style.mozUserSelect = 'none';
outerShElem.style.cursor = 'default';
innerElement.style.color = 'red';
innerElement.style.backgroundColor = 'blue';
innerElement.style.border = '2px solid black';
innerElement.style.font = 'normal 12px arial';
innerElement.style.lineHeight = '12px'
innerElement.style.paddingTop = '2px';
innerElement.style.paddingLeft = '4px';
innerElement.style.width = '20px';
innerElement.style.height = '20px';
// add negative margin to inner element
// to move the anchor to center of the div
innerElement.style.marginTop = '-10px';
innerElement.style.marginLeft = '-10px';
outerShElem.appendChild(innerElement);
outerShElem.appendChild(drawCanvas());
// Add text to the DOM element
innerElement.innerHTML = 'C';
outerShElem.addEventListener('mouseover', changeOpacity);
outerShElem.addEventListener('mouseout', changeOpacityToOne);
}
var outerElement = document.createElement('div');
//document.body.appendChild(outerElement);
function changeOpacity(evt) {
evt.target.style.opacity = 0.6;
};
function changeOpacityToOne(evt) {
evt.target.style.opacity = 1;
};
//create dom icon and add/remove opacity listeners
var domIcon = new H.map.DomIcon(outerElement, {
// the function is called every time marker enters the viewport
onAttach: function(clonedElement, domIcon, domMarker) {
setToShadow(clonedElement);
},
// the function is called every time marker leaves the viewport
onDetach: function(clonedElement, domIcon, domMarker) {
let outerShElem = clonedElement.shadowRoot.querySelectorAll('div')[0];
outerShElem.removeEventListener('mouseover', changeOpacity);
outerShElem.removeEventListener('mouseout', changeOpacityToOne);
}
});
// Marker for Chicago Bears home
var bearsMarker = new H.map.DomMarker({lat: 41.8625, lng: -87.6166}, {
icon: domIcon
});
map.addObject(bearsMarker);
//setTimeout(()=>{map.removeObject(bearsMarker);}, 0);
}
/**
* Boilerplate map initialization code starts below:
*/
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
//Step 2: initialize a map - this map is centered over Chicago.
var map = new H.Map(document.getElementById('map'),
defaultLayers.vector.normal.map,{
center: {lat:41.881944, lng:-87.627778},
zoom: 11,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Now use the map as required...
addDomMarker(map);

Ionic 2: Google Map Custom Controls Not Working

I have a google map implementation in Ionic2. Map and geolocation works fine. The errors occured only after I tried to implement custom controls/button into the map. I followed this link:
https://developers.google.com/maps/documentation/javascript/examples/control-custom
This is my js code (Constructor):
constructor(navController, platform, app) {
this.navController = navController;
this.platform = platform;
this.app = app;
platform.ready().then(() => {
this.initializeMap();
});
}
Custom control:
CenterControl(controlDiv, map){
// Set CSS for the control border.
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = '#fff';
controlUI.style.border = '2px solid #fff';
controlUI.style.borderRadius = '3px';
controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';
controlUI.style.cursor = 'pointer';
controlUI.style.marginBottom = '22px';
controlUI.style.textAlign = 'center';
controlUI.title = 'Click to recenter the map';
controlDiv.appendChild(controlUI);
// Set CSS for the control interior.
var controlText = document.createElement('div');
controlText.style.color = 'rgb(25,25,25)';
controlText.style.fontFamily = 'Roboto,Arial,sans-serif';
controlText.style.fontSize = '16px';
controlText.style.lineHeight = '38px';
controlText.style.paddingLeft = '5px';
controlText.style.paddingRight = '5px';
controlText.innerHTML = 'Center Map';
controlUI.appendChild(controlText);
// Setup the click event listeners: simply set the map to Chicago.
controlUI.addEventListener('click', function() {
map.setCenter(chicago);
});
}
Map Initialization:
initializeMap() {
let locationOptions = {timeout: 10000, enableHighAccuracy: true};
navigator.geolocation.getCurrentPosition(
(position) => {
let options = {
// /new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
center: new google.maps.LatLng(position.coords.latitude, position.coords.longitude),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
this.map = new google.maps.Map(document.getElementById("map_canvas"), options);
var centerControlDiv = document.createElement('div');
var centerControl = new CenterControl(centerControlDiv, options);
centerControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_CENTER].push(centerControlDiv);
},
(error) => {
console.log(error);
}, locationOptions
);
}
My index.html:
<script src="http://maps.google.com/maps/api/js?key=<MY API KEY>"></script>
The error message given was this:
Where line 87 refers to:
var centerControl = new CenterControl(centerControlDiv, options);
I'm unable to set "CenterControl(){}" as "function CenterControl(){}" as I would encounter syntax error in that case.
I would define CenterControl like this:
export class CenterControl {
constructor(controlDiv, map){
(...)
}
}
instead of
CenterControl(controlDiv, map) {
(...)
}
and import then when you want to use it... Don't forget the export keyword.
Edit
If it's a method of your class, simply call it this way:
this.CenterControl(centerControlDiv, options);
centerControlDiv.index = 1;
this.map.controls[google.maps.ControlPosition.TOP_CENTER].push(centerControlDiv);

api bing maps - multi layer (line and pic) on one point

I can't create multiple layers (images and lines) on the same coordinates.
Does anyone know how you can handle it?
example code:
for (; index_array < array_trip.length; index_array++) {
latVal = array_trip[index_array].latitude;
longVal = Microsoft.Maps.Location.normalizeLongitude(array_trip[index_array].longitude);
map.setView({ center: new Microsoft.Maps.Location(latVal, longVal) });
var pushpinOptions = { icon: path + 'car.png', width: 50, height: 50 };
var pushpin = new Microsoft.Maps.Pushpin({ latitude: latVal, longitude: longVal }, pushpinOptions);
map.entities.push(pushpin);
}
First off, don't set the map view in an array. This will only cause issues. Secondly, ensure that the URL to the pushpin icon is correct. Perhaps try removing that option for now until you see the default pushpins displayed on the map, then try adding a custom icon.
If you want to separate your data into layers you should use EntityCollection's: https://msdn.microsoft.com/en-us/library/gg427616.aspx
Here is a good blog post on layering: https://rbrundritt.wordpress.com/2011/10/13/multiple-pushpins-and-infoboxes-in-bing-maps-v7/
Use could initialize EntityCollection object to add multiple entities to the map at one time.
Example
function GetMap() {
var locations = [
new Microsoft.Maps.Location(60.173783, 24.941068),
new Microsoft.Maps.Location(59.338575, 18.065823),
new Microsoft.Maps.Location(59.922602, 10.749411),
new Microsoft.Maps.Location(55.675817, 12.570452)
];
var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), { credentials: "Bing Maps Key" });
//1. Add pushpins
for (var i = 0; i < locations.length; i++) {
var pin = new Microsoft.Maps.Pushpin(locations[i]);
// Add the pushpin
map.entities.push(pin);
}
//2. Add a polyline
var line = new Microsoft.Maps.Polyline(locations);
map.entities.push(line);
//3. Add a polygon
var polygoncolor = new Microsoft.Maps.Color(100, 100, 0, 100);
var polygon = new Microsoft.Maps.Polygon(locations, { fillColor: polygoncolor, strokeColor: polygoncolor });
map.entities.push(polygon);
var bestview = Microsoft.Maps.LocationRect.fromLocations(locations);
map.setView({ bounds: bestview });
}
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<body onload="GetMap();">
<div id='mapDiv' style="position:relative; width:600px; height:600px;"></div>
</body>

Add Multiple Custom Control buttons on Google Maps API v3

I have 2 Google maps on the same page and I am looking to add the same button to a map that already has one.
This button is to close the overlay that Google maps launches in, basically an exit button.
The Button works fine on the first map but I cant get the second one to work D:!
I know I have to change the variables because that's what I had to do to get 2 maps on one page. Also if someone else is good in Google Maps API v3 can you tell me why I need the "map" variable in the function HomeControl(controlDiv, map) { line?
Here is my code:
function HomeControl(controlDiv, map) {
// Set CSS styles for the DIV containing the control
// Setting padding to 5 px will offset the control
// from the edge of the map.
controlDiv.style.padding = '5px';
// Set CSS for the control border.
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = 'white';
controlUI.style.borderStyle = 'solid';
controlUI.style.borderWidth = '2px';
controlUI.style.cursor = 'pointer';
controlUI.style.textAlign = 'center';
controlUI.title = 'Click to set the map to Home';
controlDiv.appendChild(controlUI);
// Set CSS for the control interior.
var controlText = document.createElement('div');
controlText.style.fontFamily = 'Arial,sans-serif';
controlText.style.fontSize = '12px';
controlText.style.paddingLeft = '4px';
controlText.style.paddingRight = '4px';
controlText.innerHTML = '<strong>Home</strong>';
controlUI.appendChild(controlText);
// Setup the click event listeners: simply set the map to Chicago.
google.maps.event.addDomListener(controlUI, 'click', function() {
document.getElementById('light').style.display='none';
document.getElementById('fade').style.display='none';
});
}
function detectBrowser() {
var useragent = navigator.userAgent;
var mapdivMap = document.getElementById("light");
if (useragent.indexOf('iPhone') != -1 || useragent.indexOf('Android') != -1 ) {
mapdivMap.style.width = '100%';
mapdivMap.style.height = '100%';
initialize();
} else {
mapdivMap.style.width = '600px';
mapdivMap.style.height = '100%';
initialize();
}
};
function initialize() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(43.464258,-80.52041),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('light'),
mapOptions);
var marker = new google.maps.Marker({
  position: map.getCenter(),
    map: map,
    title: 'Waterloo'
});
// Create the DIV to hold the control and call the HomeControl() constructor
// passing in this DIV.
var homeControlDiv = document.createElement('div');
var homeControl = new HomeControl(homeControlDiv, map);
homeControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv);
}
//*******************************************************
//************ Conestoga Map Page JavaScript ************
//*******************************************************
function Map2(Map2Div, map2) {
// Set CSS styles for the DIV containing the control
// Setting padding to 5 px will offset the control
// from the edge of the map.
Map2Div.style.padding = '5px';
// Set CSS for the control border.
var Map2UI = document.createElement('div');
Map2UI.style.backgroundColor = 'white';
Map2UI.style.borderStyle = 'solid';
Map2UI.style.borderWidth = '2px';
Map2lUI.style.cursor = 'pointer';
Map2UI.style.textAlign = 'center';
Map2UI.title = 'Click to set the map to Home';
Map2Div.appendChild(Map2UI);
// Set CSS for the control interior.
var Map2Text = document.createElement('div');
Map2Text.style.fontFamily = 'Arial,sans-serif';
Map2Text.style.fontSize = '12px';
Map2Text.style.paddingLeft = '4px';
Map2Text.style.paddingRight = '4px';
Map2Text.innerHTML = '<strong>Home</strong>';
Map2UI.appendChild(Map2Text);
// Setup the click event listeners: simply set the map to Chicago.
google.maps.event.addDomListener(MapUI2, 'click', function() {
document.getElementById('light').style.display='none';
document.getElementById('fade').style.display='none';
});
}
function detectBrowser2() {
var useragent2 = navigator.userAgent;
var mapdivMap2 = document.getElementById("light");
if (useragent2.indexOf('iPhone') != -1 || useragent2.indexOf('Android') != -1 ) {
mapdivMap2.style.width = '100%';
mapdivMap2.style.height = '100%';
initialize2();
} else {
mapdivMap2.style.width = '600px';
mapdivMap2.style.height = '100%';
initialize2();
}
};
function initialize2() {
var mapOptions2 = {
zoom: 8,
center: new google.maps.LatLng(43.464258,-80.52041),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map2 = new google.maps.Map(document.getElementById('light'),
mapOptions2);
var marker2 = new google.maps.Marker({
  position: map.getCenter(),
    map: map2,
    title: 'Waterloo'
});
// Create the DIV to hold the control and call the HomeControl() constructor
// passing in this DIV.
var Map2Div = document.createElement('div');
var Map2 = new Map2(Map2Div, map2);
Map2Div.index = 1;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(Map2Div);
}

Google maps v3: clustering with custom markers

I'm trying to use MarkerClusterer to clusterize the markers on my map.
The problem is that I'm not using default markers (google.maps.Marker), but instead a custom class which hinerits from google.maps.OverlayView.
Unfortunately it seems that the library has been developed assuming the use of basic markers, in fact I get errors because my class does not implement methods defined in google.maps.Marker.
Is it possible to use the MarkerClusterer by keeping my custom markers?
EDIT: it was a lot easier than I expected, I solved by implementing 2 methods in my custom class:
setVisible() and getPosition()
in order to help others the following is my complete interface (without full implementation):
BFPushpin = function(config)
{
this.setMap(config.map);
this.set("position", config.position);
// other settings...
};
// my class extends google.maps.OverlayView
BFPushpin.prototype = new google.maps.OverlayView();
BFPushpin.prototype.getBounds = function()
{
return new google.maps.LatLngBounds(this.position, this.position);
};
BFPushpin.prototype.getPoint = function()
{
var bounds = this.getBounds();
var projection = this.getProjection();
var sw = projection.fromLatLngToDivPixel(bounds.getSouthWest());
var ne = projection.fromLatLngToDivPixel(bounds.getNorthEast());
return new google.maps.Point(sw.x, ne.y);
};
BFPushpin.prototype.getSuperContainer = function()
{
var panes = this.getPanes();
return jQuery(panes ? panes.overlayImage : "");
};
BFPushpin.prototype.getContainer = function()
{
// return inner container
};
BFPushpin.prototype._generatePopupContent = function()
{
// return markup for the popupwindow
};
BFPushpin.prototype._addListeners = function()
{
// add handlers for the pushpin
};
BFPushpin.prototype.onAdd = function()
{
// customize content here
};
BFPushpin.prototype.onRemove = function()
{
// remove pin container here
};
BFPushpin.prototype.draw = function()
{
// set display style here
};
BFPushpin.prototype.setVisible = function(visible)
{
// set display block or hidden
};
BFPushpin.prototype.getPosition = function()
{
return this.position;
};
Or just define the functions that the MarkerClusterer expects on the marker. setMap and getPosition() and some other ones.
You should probably define your new marker class in such a way that it also inherits from google.maps.Marker (i.e. that it implements its interface). It is logical that MarkerClusterer uses this interface - it has to suppose the markers are markers in order to work with them :-)
Hopefully this will also help people trying to get this solution to work. Thanks #daveoncode for the example. I was able to modify it to get it working for me:
renderMap() {
const mapProperties = {
center: new google.maps.LatLng(34.0234, -84.6155),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.mapElement.nativeElement, mapProperties);
let markers = [];
for (let i=0; i<this._sitesList.length; i++) {
let bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(this._sitesList[i].lat, this._sitesList[i].lon)
);
let position = new google.maps.LatLng(this._sitesList[i].lat, this._sitesList[i].lon);
let html = this.makeHtmlForSitePanel(i, this._sitesList[i]); // I have a function to return html for my OverlayView panels here.
markers.push( this.generateSitePanel(bounds, html, this.map, position) );
}
var markerCluster = new MarkerClusterer(this.map, markers, {
imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
});
}
generateSitePanel(bounds, html, map, position) {
SitePanel.prototype = new google.maps.OverlayView();
function SitePanel (bounds, html, map, position) {
this.bounds_ = bounds;
this.set('position', position);
this.html_ = html;
this.map_ = map;
this.div_ = null;
this.setMap(map);
}
SitePanel.prototype.getBounds = function() {
return new google.maps.LatLngBounds(this.position, this.position);
};
SitePanel.prototype.getPoint = function() {
var bounds = this.getBounds();
var projection = this.getProjection();
var sw = projection.fromLatLngToDivPixel(bounds.getSouthWest());
var ne = projection.fromLatLngToDivPixel(bounds.getNorthEast());
return new google.maps.Point(sw.x, ne.y);
};
SitePanel.prototype.getSuperContainer = function(){
var panes = this.getPanes();
return $(panes ? panes.overlayImage : '');
};
SitePanel.prototype.getContainer = function()
{
// return inner container
// I don't have anything for this one
};
SitePanel.prototype.getPosition = function() {
return this.position;
};
SitePanel.prototype.onAdd = function() {
var div = document.createElement('div');
div.className = 'tooltip-container-';
div.innerHTML = this.html_;
div.style.position = 'absolute';
this.div_ = div;
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
};
SitePanel.prototype.draw = function() {
var overlayProjection = this.getProjection();
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 20 + 'px';
};
SitePanel.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
};
return new SitePanel(bounds, html, map, position);
}

Categories

Resources