Mapbox gl js url parameter - javascript

We have configured mapbox gl js successfully. We have a working map with locations / stores that are clickable which show the mapbox map popup, giving the user some details e.g., contact information, opening hours etc...
We are wanting to have parameter within a URL to easily access a specific listing (store/location) for example:
https://example.com/store-locator?store=1, by accessing the "store locator" with the ID 1 in the URL we would like the map to focus in on that location and have the mapbox popup show - matching location e.g., 1. For this case, let's suppose the JSON property "LocationX" is to be given an ID which is 1
I tried with the below code, but was not successful
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const storeID = urlParams.get('branch')
console.log(storeID);
$(document).ready(function() {
if (storeID == "1") {
$("#link-0").click();
};
})
#Link-0 is the id for one of the locations/listings.
<div id="listing-0" class="item active">Broxburn<div>
Mapbox GL JS
/**
* Add the map to the page
*/
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
center: [-1.5466858011960802, 53.478230478528126],
zoom: 5,
scrollZoom: true
});
// Add geolocate control to the map.
map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
// When active the map will receive updates to the device's location as it changes.
trackUserLocation: true,
// Draw an arrow next to the location dot to indicate which direction the device is heading.
showUserHeading: true
})
);
const stores = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-3.4524379167753025, 55.942792181678804]
},
'properties': {
'refName': 'Broxburn',
'phoneFormatted': 'xxxxxxxxxxxxxxxxxx',
'phone': 'xxxxxxxxxxxxxxxxxx',
'phone2': 'xxxxxxxxxxxxxxxxxx',
'address': 'xxxxxxxxxxxxxxxxxx',
'city': 'xxxxxxxxxxxxxxxxxx',
'country': 'xxxxxxxxxxxxxxxxxx',
'postalCode': 'xxx xxx',
'email': 'xxxxxxxxxxxxxxxxxx',
'service1': 'xxxxxxx',
'service2': 'xxxxxxx',
'weekday': 'xxxxxxx - xxxxxxx',
'weekend': 'xxxxxxx - xxxxxxx',
'sunday': 'Closed'
}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-2.9544548591328614, 54.92245269446434]
},
'properties': {
'refName': 'Carlisle',
'phoneFormatted': 'xxxxxxxxxxxxxxxxxx',
'phone': 'xxxxxxxxxxxxxxxxxx',
'phone2': 'xxxxxxxxxxxxxxxxxx',
'address': 'xxxxxxxxxxxxxxxxxx',
'city': 'xxxxxxxxxxxxxxxxxx',
'country': 'xxxxxxxxxxxxxxxxxx',
'postalCode': 'xxx xxx',
'email': 'xxxxxxxxxxxxxxxxxx',
'service1': 'xxxxxxx',
'service2': 'xxxxxxx',
'weekday': 'xxxxxxx - xxxxxxx',
'weekend': 'xxxxxxx - xxxxxxx',
'sunday': 'Closed'
}
}
}
]
};
/**
* Assign a unique id to each store. You'll use this `id`
* later to associate each point on the map with a listing
* in the sidebar.
*/
stores.features.forEach((store, i) => {
store.properties.id = i;
});
/**
* Wait until the map loads to make changes to the map.
*/
map.on('load', () => {
/**
* This is where your '.addLayer()' used to be, instead
* add only the source without styling a layer
*/
map.addSource('places', {
'type': 'geojson',
'data': stores
});
/**
* Create a new MapboxGeocoder instance.
*/
const geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
marker: true,
});
/**
* Add all the things to the page:
* - The location listings on the side of the page
* - The search box (MapboxGeocoder) onto the map
* - The markers onto the map
*/
buildLocationList(stores);
map.addControl(geocoder, 'top-left');
addMarkers();
/**
* Listen for when a geocoder result is returned. When one is returned:
* - Calculate distances
* - Sort stores by distance
* - Rebuild the listings
* - Adjust the map camera
* - Open a popup for the closest store
* - Highlight the listing for the closest store.
*/
geocoder.on('result', (event) => {
/* Get the coordinate of the search result */
const searchResult = event.result.geometry;
/**
* Calculate distances:
* For each store, use turf.disance to calculate the distance
* in miles between the searchResult and the store. Assign the
* calculated value to a property called `distance`.
*/
const options = { units: 'miles' };
for (const store of stores.features) {
store.properties.distance = turf.distance(
searchResult,
store.geometry,
options
);
}
/**
* Sort stores by distance from closest to the `searchResult`
* to furthest.
*/
stores.features.sort((a, b) => {
if (a.properties.distance > b.properties.distance) {
return 1;
}
if (a.properties.distance < b.properties.distance) {
return -1;
}
return 0; // a must be equal to b
});
/**
* Rebuild the listings:
* Remove the existing listings and build the location
* list again using the newly sorted stores.
*/
const listings = document.getElementById('listings');
while (listings.firstChild) {
listings.removeChild(listings.firstChild);
}
buildLocationList(stores);
/* Open a popup for the closest store. */
createPopUp(stores.features[0]);
/** Highlight the listing for the closest store. */
const activeListing = document.getElementById(
`listing-${stores.features[0].properties.id}`
);
activeListing.classList.add('active');
/**
* Adjust the map camera:
* Get a bbox that contains both the geocoder result and
* the closest store. Fit the bounds to that bbox.
*/
const bbox = getBbox(stores, 0, searchResult);
map.fitBounds(bbox, {
padding: 100
});
});
});
/**
* Using the coordinates (lng, lat) for
* (1) the search result and
* (2) the closest store
* construct a bbox that will contain both points
*/
function getBbox(sortedStores, storeIdentifier, searchResult) {
const lats = [
sortedStores.features[storeIdentifier].geometry.coordinates[1],
searchResult.coordinates[1]
];
const lons = [
sortedStores.features[storeIdentifier].geometry.coordinates[0],
searchResult.coordinates[0]
];
const sortedLons = lons.sort((a, b) => {
if (a > b) {
return 1;
}
if (a.distance < b.distance) {
return -1;
}
return 0;
});
const sortedLats = lats.sort((a, b) => {
if (a > b) {
return 1;
}
if (a.distance < b.distance) {
return -1;
}
return 0;
});
return [
[sortedLons[0], sortedLats[0]],
[sortedLons[1], sortedLats[1]]
];
}
/**
* Add a marker to the map for every store listing.
**/
function addMarkers() {
/* For each feature in the GeoJSON object above: */
for (const marker of stores.features) {
/* Create a div element for the marker. */
const el = document.createElement('div');
/* Assign a unique `id` to the marker. */
el.id = `marker-${marker.properties.id}`;
/* Assign the `marker` class to each marker for styling. */
el.className = 'marker';
/**
* Create a marker using the div element
* defined above and add it to the map.
**/
new mapboxgl.Marker(el, { offset: [0, -23] })
.setLngLat(marker.geometry.coordinates)
.addTo(map);
/**
* Listen to the element and when it is clicked, do three things:
* 1. Fly to the point
* 2. Close all other popups and display popup for clicked store
* 3. Highlight listing in sidebar (and remove highlight for all other listings)
**/
el.addEventListener('click', (e) => {
flyToStore(marker);
createPopUp(marker);
const activeItem = document.getElementsByClassName('active');
e.stopPropagation();
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
const listing = document.getElementById(
`listing-${marker.properties.id}`
);
listing.classList.add('active');
});
}
}
/**
* Add a listing for each store to the sidebar.
**/
function buildLocationList(stores) {
for (const store of stores.features) {
/* Add a new listing section to the sidebar. */
const listings = document.getElementById('listings');
const listing = listings.appendChild(document.createElement('div'));
/* Assign a unique `id` to the listing. */
listing.id = `listing-${store.properties.id}`;
/* Assign the `item` class to each listing for styling. */
listing.className = 'item';
/* Add the link to the individual listing created above. */
const link = listing.appendChild(document.createElement('a'));
link.href = '#/';
link.className = 'title';
link.id = `link-${store.properties.id}`;
link.innerHTML = `${store.properties.refName}`;
/* Add details to the individual listing. */
const details = listing.appendChild(document.createElement('div'));
details.innerHTML = details.innerHTML = `${store.properties.address}, ${store.properties.city}`;
if (store.properties.phone) {
details.innerHTML += ` · ${store.properties.phoneFormatted}`;
}
if (store.properties.service1) {
details.innerHTML += `<br><i class="fa-solid fa-truck-front"></i>`;
if (store.properties.service2) { details.innerHTML +=`<i data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tooltip on bottom" class="fa-solid fa-spray-can" style="padding-left: 15px;"></i>`;
if (store.properties.service3) { details.innerHTML +=`<i class="fa-solid fa-helmet-safety" style="padding-left: 15px;"></i>`;
}
}
}
/**
* Listen to the element and when it is clicked, do four things:
* 1. Update the `currentFeature` to the store associated with the clicked link
* 2. Fly to the point
* 3. Close all other popups and display popup for clicked store
* 4. Highlight listing in sidebar (and remove highlight for all other listings)
**/
link.addEventListener('click', function () {
for (const feature of stores.features) {
if (this.id === `link-${feature.properties.id}`) {
flyToStore(feature);
createPopUp(feature);
}
}
const activeItem = document.getElementsByClassName('active');
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
this.parentNode.classList.add('active');
});
}
}
/**
* Use Mapbox GL JS's `flyTo` to move the camera smoothly
* a given center point.
**/
function flyToStore(currentFeature) {
map.flyTo({
center: currentFeature.geometry.coordinates,
zoom: 15
});
}
/**
* Create a Mapbox GL JS `Popup`.
**/
function createPopUp(currentFeature) {
const popUps = document.getElementsByClassName('mapboxgl-popup');
if (popUps[0]) popUps[0].remove();
const popup = new mapboxgl.Popup({ closeOnClick: false })
.setLngLat(currentFeature.geometry.coordinates)
.setHTML(
`<h3>Company Name - ${currentFeature.properties.refName}</h3>
<h4>${currentFeature.properties.address}, ${currentFeature.properties.city}, ${currentFeature.properties.postalCode}</h4>
<h4><i style="margin-right:5px" class="fa-solid fa-clock"></i>Mon-Fri:<span style="margin-right:19px"></span> ${currentFeature.properties.weekday}<br><i style="margin-right:17px" class=""></i>Saturday: <span style="margin-right:10px"></span> ${currentFeature.properties.weekend}<br><i style="margin-right:17px" class=""></i>Sunday: <span style="margin-right:20px"></span> ${currentFeature.properties.sunday}</h4>
<h4><i style="margin-right:5px" class="fa-solid fa-phone"></i>${currentFeature.properties.phone} <br></h4>
<div style="padding:0;" id="alt-phone2" class="alt-phone2"> <h4 style="overflow-wrap: break-word;"><i style="margin-right:5px" class="fa-solid fa-phone"></i>${currentFeature.properties.phone2}</h4></div>
<div style="padding:0;" id="alt-phone2" class="alt-phone3"> <h4 style="overflow-wrap: break-word;"><i style="margin-right:5px" class="fa-solid fa-phone"></i>${currentFeature.properties.phone3}</h4></div>
<h4 style="overflow-wrap: break-word;"><i style="margin-right:5px" class="fa-solid fa-envelope"></i>${currentFeature.properties.email}</h4>`
)
.addTo(map);
if (currentFeature.properties.phone2 === undefined) {
document.getElementsByClassName("alt-phone2")[0].style.display = "none";
}
if (currentFeature.properties.phone3 === undefined) {
document.getElementsByClassName("alt-phone3")[0].style.display = "none";
}
}

I think that your code looks good, but there is likely a race condition between the $(document).ready(...) and the map.on('load', ...) events. The first one fires before the second one. That means, your JavaScript that "clicks" on a link tries to click on a link that doesn't yet exist in the DOM. If this is the case, the solution is to move the "clicking" code after the code that creates the links.
i.e. create this function:
function clickSelectedStore() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const storeID = urlParams.get('branch')
console.log(storeID);
if (storeID) {
$('#link-' + storeID).click();
}
}
and call it at the end of the map.on('load', ...) event (after the buildLocationList(...) function has already been called.
If that doesn't help, you should create a Minimal Reproducible Example so that others can see your code in action.

Related

`Uncaught Error: Map container is being reused by another instance` from second manual search

I am currently trying to make an IP address checker which checks user's ip on load and on the user's manual search using Leaflet and other apis like ipgeolocation and currencyconverer. Currently, the map loads perfectly on load and on the first manual search after load. But when I try to do the second manual IP search I get this -
Map.js:745 Uncaught Error: Map container is being reused by another instance
at i.remove (Map.js:745:10)
at HTMLButtonElement.mapOff (index.js:136:25)
and then the result shows up like the first search.
Why is it appearing and how do I solve it?
Github Repository Link - https://github.com/MustakAbsarKhan/ip-address-tracker
Code-
//loading map and it's features
mapload ();
function mapload (){
count++;
if(count===1){
//map initiation
var map = L.map('map').setView([latitude, longitude], 13);
}else if(count === 2){
var map = L.map('map').setView([latitude, longitude], 13);
count --;
}
//maptile setup
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=Kiarb32YtKIgXk1i9lL1',{
tileSize: 512,
zoomOffset: -1,
minZoom: 1,
attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
crossOrigin: true
}).addTo(map);
//map icon
var blackIcon = L.icon({
iconUrl: 'images/icon-location.svg',
iconSize: [30, 40]
});
//marker & popup on marker
L.marker([latitude, longitude],{icon: blackIcon}).addTo(map)
.bindPopup('Your IP Shows You Here')
.openPopup();
//popup on map click
var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(map);
}
map.on('click', onMapClick);
//leaflet-locatecontrol plugin
var lc = L.control.locate({
position: 'topleft',
tap: false,
strings: {
title: "Click here, to get your device's current location"
},
locateOptions: {
enableHighAccuracy: true
}
}).addTo(map);
count--;
function mapOff(){
map.off();
map.remove();
};
button.addEventListener('click',mapOff);
};
The issue is solved by separating the marker, making the code only reposition the marker if the map and layer are already defined.
The thing that did cause the problem was- The map and Its Layer Container were getting initialized over and over following the button click.
Hope someone in the future will find this solution useful.
The Code-
let count = 0;
ipgeolocationapiCALL(ipgeolocationAPI);
//if user clicks on the button
button.addEventListener("click", function () {
if (searchbox.value !== "") {
ipgeolocationAPI =
`https://api.ipgeolocation.io/ipgeo?${params}&ip=` + searchbox.value;
count++;
ipgeolocationapiCALL(ipgeolocationAPI);
};
});
//initialization of map on load cause the count value stays 0 at the beginning and when the search icon is pressed for the first time
function initializeMap(latitude, longitude) {
map = L.map("map").setView([latitude, longitude], 13);
L.tileLayer(
"https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=Kiarb32YtKIgXk1i9lL1",
{
tileSize: 512,
zoomOffset: -1,
minZoom: 1,
attribution:
'\u003ca href="https://www.maptiler.com/copyright/" target="_blank"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href="https://www.openstreetmap.org/copyright" target="_blank"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e',
crossOrigin: true,
}
).addTo(map);
var blackIcon = L.icon({
iconUrl: "images/icon-location.svg",
iconSize: [30, 40],
});
L.marker([latitude, longitude], { icon: blackIcon })
.addTo(map)
.bindPopup("Your IP Shows You Here")
.openPopup();
L.control
.locate({
position: "topleft",
tap: false,
strings: {
title: "Click here, to get your device's current location",
},
locateOptions: {
enableHighAccuracy: true,
},
})
.addTo(map);
}
function ipgeolocationapiCALL(api) {
//returns "ip": "103.145.74.149","continent_code": "AS","continent_name": "Asia","country_code2": "BD","country_code3": "BGD","country_name": "Bangladesh","country_capital": "Dhaka","state_prov": "Dhaka Division","district": "Savar Upazila","city": "Savar Union","zipcode": "","latitude": "23.86170","longitude": "90.25649","is_eu": false,"calling_code": "+880","country_tld": ".bd","languages": "bn-BD,en","country_flag": "https://ipgeolocation.io/static/flags/bd_64.png","geoname_id": "1200292","isp": "Master Net","connection_type": "","organization": "Master Net","currency": {"code": "BDT","name": "Bangladeshi Taka","symbol": "৳"},"time_zone": {"name": "Asia/Dhaka","offset": 6,"current_time": "2022-08-28 15:24:16.540+0600","current_time_unix": 1661678656.54,"is_dst": false,"dst_savings": 0
fetch(api)
.then((response) => response.json()) //collects data as json
.then((data) => {
//declaring contents of api as objects
const ip = data.ip; //103.145.74.149
const { city, country_name, isp, country_flag, latitude, longitude } =
data; //Dhaka, Bangladesh,Master Net
const { current_time, name } = data.time_zone; //"2022-08-27 23:25:49.527+0600";
const { code, symbol } = data.currency; //BDT,TAKA SYMBOL
let timezone = current_time.slice(current_time.length - 5); //+0600
let date = current_time.slice(0, current_time.search(" ")); // 2022-08-27
let time = current_time.slice(date.length + 1, date.length + 9); //23:01:28
let exactTimezone =
"UTC " +
timezone.slice(0, 3) +
":" +
timezone.slice(timezone.length - 2, timezone.length); //UTC +06:00
//assigning api values to html elements
ipAddress.textContent = ip;
cityData.textContent = city + ",";
countryData.textContent = country_name;
timezoneData.textContent = exactTimezone + ",";
timeData.textContent = time + ",";
dateData.textContent = date;
ispData.textContent = isp;
currencyData.textContent = code + ` (${symbol})`;
flagIcon.src = country_flag;
let currencyCODE = code; //assigining fetched value to this variable for being able to reassign value to following conditions
if (currencyCODE === "USD") {
currencyCODE = "EUR";
let xchangeRateAPI = `https://api.exchangerate.host/convert?from=USD&to=${currencyCODE}`;
xchangeRateAPICALL(xchangeRateAPI);
} else {
let xchangeRateAPI = `https://api.exchangerate.host/convert?from=USD&to=${currencyCODE}`;
xchangeRateAPICALL(xchangeRateAPI);
}
//calling exchange rate api. This one Converts USD to User's Currency and For users who lives in United States it would convert 1 USD to Euro.
function xchangeRateAPICALL(api) {
fetch(api)
.then((response) => response.json())
.then((data) => {
const { to } = data.query;
const { result } = data;
const convertedAmount = result.toFixed(2);
currencyconvertData.textContent =
"$ 1 = " + `${to} ${convertedAmount}`;
});
}
//default value of count is 0 which gets incremented in the previous if function(which checks if the input field has any value)
if (count === 0) {//initializing the map and the layout on load
initializeMap(latitude, longitude);
} else {//resetting the marker position as the map and layout is already initialized
var blackIcon = L.icon({
iconUrl: "images/icon-location.svg",
iconSize: [30, 40],
});
L.marker([latitude, longitude], { icon: blackIcon })
.addTo(map)
.bindPopup("Your IP Shows You Here")
.openPopup();
}
})
.catch((error) => {
console.log("Error is "+ error);
alert("Wrong IP. Please Try Again.");
searchbox.value = "";
});

Bing Maps v8 API - Zoom Level to show route and pushpin location

I am using the Bing Maps v8 API. I have a map that shows a driving route, and a pushpin of another location. I need to get the map to zoom out to show both the waypoint locations and the pushpin location. Right now, I can get the map to zoom to the waypoints of the pushpin location.
I am not sure how to get both to show on the map zoom. I know that I need to use the LocationRect class.
var searchManager;
var startingPoint = document.getElementById('startPoint').value;
var address = $("#addressLine").val();
var loc;
var patAddLoc;
var waypointLoc;
var pinsLocs = [];
// GET ROUTE BASED ON DIRECTION
function GetMap() {
var map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
//BING API KEY VIA AZURE
credentials: 'X',
zoom: 10,
});
// geocode patient address
geocodeQuery(address);
// look for patient address
function geocodeQuery(query) {
//If search manager is not defined, load the search module.
if (!searchManager) {
//Create an instance of the search manager and call the geocodeQuery function again.
Microsoft.Maps.loadModule('Microsoft.Maps.Search', function () {
searchManager = new Microsoft.Maps.Search.SearchManager(map);
geocodeQuery(query);
});
} else {
var searchRequest = {
where: query,
callback: function (r) {
//Add the first result to the map and zoom into it.
if (r && r.results && r.results.length > 0) {
var pin = new Microsoft.Maps.Pushpin(r.results[0].location);
// get patient address location
patAddLoc = r.results[0].location;
map.entities.push(pin);
// add patient location to pushpin array
pinsLocs.push(patAddLoc);
// view is set with route location
//map.setView({ bounds: r.results[0].bestView });
}
// directions manager
// addWaypoint
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function addWaypoint() {
var directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
// if less than 2 point on the map
if (directionsManager.getAllWaypoints().length < 2) {
directionsManager.clearAll();
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('startPoint').value });
directionsManager.addWaypoint(startWaypoint);
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('endPoint').value });
directionsManager.addWaypoint(endWaypoint);
}
// Insert a waypoint
if (document.getElementById('wayPoints').value !== null) {
var addressList = JSON.parse(document.getElementById('wayPoints').value);
var arrayLength = addressList.length;
// insert waypoints from schedule
for (var i = 0; i < arrayLength; i++) {
//alert(addressList[i]);
var hvaddress = addressList[i];
var newWP = new Microsoft.Maps.Directions.Waypoint({ address: hvaddress });
directionsManager.addWaypoint(newWP, 1);
}
}
// Set the element in which the itinerary will be rendered - set autoupdatemapview to false to override autozoom to route
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('printoutPanel'), autoUpdateMapView: false });
directionsManager.calculateDirections();
var allWaypoints = directionsManager.getAllWaypoints();
// add way point to pinsLocs array
for (var i = 0; i < allWaypoints.length; i++) {
// returns nulls
alert(allWaypoints);
loc = allWaypoints[i].getLocation();
var showMeLoc = loc;
// showMeLoc = undefined.....?
alert(showMeLoc);
pinsLocs.push(loc);
}
// only the address search location is added to the array, waypoint locations are null
alert(pinsLocs);
//Create a LocationRect from array of locations and set the map view.
map.setView({
bounds: Microsoft.Maps.LocationRect.fromLocations(pinsLocs),
padding: 100 //Add a padding to buffer map to account for pushpin pixel dimensions
});
});
},
errorCallback: function (e) {
//If there is an error, alert the user about it.
alert("No results found.");
}
};
//Make the geocode request.
searchManager.geocode(searchRequest);
}
}
}
UPDATE - HERE is the working code for those who have the same question!
var searchManager;
var startingPoint = document.getElementById('startPoint').value;
var address = $("#addressLine").val();
var patAddLoc;
// GET ROUTE BASED ON DIRECTION
function GetMap() {
var map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
//BING API KEY VIA AZURE
credentials: 'XXXXX',
zoom: 10,
});
// geocode patient address
geocodeQuery(address);
// look for patient address
function geocodeQuery(query) {
//If search manager is not defined, load the search module.
if (!searchManager) {
//Create an instance of the search manager and call the geocodeQuery function again.
Microsoft.Maps.loadModule('Microsoft.Maps.Search', function () {
searchManager = new Microsoft.Maps.Search.SearchManager(map);
geocodeQuery(query);
});
} else {
var searchRequest = {
where: query,
callback: function (r) {
//Add the first result to the map and zoom into it.
if (r && r.results && r.results.length > 0) {
locs = [];
var pin = new Microsoft.Maps.Pushpin(r.results[0].location);
// get patient address location
patAddLoc = r.results[0].location;
map.entities.push(pin);
// add patient location to pushpin array
locs.push(r.results[0].location);
// view is set with route location
//map.setView({ bounds: r.results[0].bestView });
}
// directions manager
// addWaypoint
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function addWaypoint() {
var directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
// if less than 2 point on the map
if (directionsManager.getAllWaypoints().length < 2) {
directionsManager.clearAll();
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('startPoint').value });
directionsManager.addWaypoint(startWaypoint);
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: document.getElementById('endPoint').value });
directionsManager.addWaypoint(endWaypoint);
}
// Insert a waypoint
if (document.getElementById('wayPoints').value !== null) {
var addressList = JSON.parse(document.getElementById('wayPoints').value);
var arrayLength = addressList.length;
// insert waypoints from schedule
for (var i = 0; i < arrayLength; i++) {
//alert(addressList[i]);
var hvaddress = addressList[i];
var newWP = new Microsoft.Maps.Directions.Waypoint({ address: hvaddress });
directionsManager.addWaypoint(newWP, 1);
}
}
// Set the element in which the itinerary will be rendered - set autoupdatemapview to false to override autozoom to route
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('printoutPanel'), autoUpdateMapView: false });
//Add event handlers to directions manager.
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', directionsError);
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', directionsUpdated);
// Calculate directions, which displays a route on the map
directionsManager.calculateDirections();
// get route boundaries
function directionsUpdated(e) {
//Get the current route index.
var routeIdx = directionsManager.getRequestOptions().routeIndex;
// get northeast bounding box corner
var bBoxNE = e.routeSummary[routeIdx].northEast;
locs.push(bBoxNE);
// get southwest bounding box corner
var bBoxSW = e.routeSummary[routeIdx].southWest;
locs.push(bBoxSW);
//SET MAP VIEW
//Create a LocationRect from array of locations and set the map view.
map.setView({
bounds: Microsoft.Maps.LocationRect.fromLocations(locs),
padding: 50 //Add a padding to buffer map to account for pushpin pixel dimensions
});
}
function directionsError(e) {
alert('Error: ' + e.message + '\r\nResponse Code: ' + e.responseCode)
}
});
},
errorCallback: function (e) {
//If there is an error, alert the user about it.
alert("No results found.");
}
};
//Make the geocode request.
searchManager.geocode(searchRequest);
}
}
}
If I understand correctly, you want a view that the entirety of the route and the extra location are visible?
How about using directionsManager.getCurrentRoute().routePath to get all the locations on the route, and then using LocationRect.fromLocations(), which can take in an array of locations - in your case all locations of above plus the additional one.
Note that calculateDirections and geocode and asynchronous, so you may want to handle the dependency on patAddLoc (e.g. move the directions code into the geocode callback).
Reference:
https://msdn.microsoft.com/en-us/library/mt750375.aspx
https://msdn.microsoft.com/en-us/library/mt750645.aspx
https://msdn.microsoft.com/en-us/library/mt712644.aspx

Clickable location labels on Google Map API [duplicate]

This question already has an answer here:
Google Maps API V3: How to get region border coordinates (polyline) data? [duplicate]
(1 answer)
Closed 6 years ago.
Now on google.com/maps page when I click on the name/label of a country or city, this area are highlighted and opens left popup window with information.
Is it possible to realize the same thing with the Google Maps API?
To highlight label on mouse over, to highlight boundaries of country, state or city on click and to get selected by user label/name in js.
I looked Google Maps API JavaScript documentation but similar functionality not found.
Thanks!
Sorry for imprecise question.
Is there any way to set clickable country / city names on map with API, like on google.com/maps page?
Recommend a 'barebones' GMap class. As it happens I am just re-visiting this myself so try this code (it might need some changes)
/**
* 'GMap'
* extends googlemaps to allow simpler coding in other apps, should be loaded after the main google maps
* a new instance of a google map is contructed calling this with identical arguments to the standard class and then returned
* the map name must be unique and reserved as a global by the client code, eg var pagemap outside of function, so the external callbacks
* can use this name to run a function against, eg pagemap.queryMove_do
*
*/
function GMap(mapId, options) {
this.name = null;
this.map = null;
this.bounds = null; //view point boundary
this.gui_reg;
this.mapoptions;
this.calledbackonload;
this.polygons = {};
this.lngoffset = {'direction': '', referenceelem: ''};
this.infowindows = {};
this.infowindowindex = 0;
GMap.prototype.__construct = function (mapId, options) {
var mapbuffer = new Data_buffer(); //this has to be vague as 3rd party api data is not always the same format, simply return data to the logged map interface objects
if (typeof window.MAP_INTERFACE_CTRL === 'undefined') {//if not created, global constant to co-ordinate ajax requests with map objects and 3rd party API, and allow funneling back to local objects
window.MAP_INTERFACE_CTRL = new Data_buffer(); //this has to be vague as 3rd party api data is not always the same format, simply return data to the logged map interface objects
}
options.panControlOptions = model.array_defaults(
options.ctrlcfg,
{
position: google.maps.ControlPosition.RIGHT_BOTTOM
}
);
options.zoomControlOptions = model.array_defaults(
options.ctrlcfg,
{
position: google.maps.ControlPosition.RIGHT_CENTER
}
);
this.mapoptions = model.array_defaults(
options,
{
center: new google.maps.LatLng(54.5, -7),
zoom: 6,
minzoom: 15,
maxzoom: 21
}
);
this.gui_reg = {location: {address: new Array()}};
this.name = mapId;
this.map = new google.maps.Map(document.getElementById(mapId), this.mapoptions);
var selfobj = this;
google.maps.event.addListener(//processes client registration for registered events
this.map,
'dragend', //center changed causes too many requests
function () {
selfobj.update_client_go("location");
}
);
//create invisible scratchpad
if ($('#map_pool').length == 0) {
$('body').append("<div id='map_pool'></div>");
$('#map_pool').hide();
}
/*
callback_obj = this;
google.maps.event.addListener(this.map, 'tilesloaded', function(evt) {
callback_obj.map.setZoom(9);
});*/
}
/*****************************************************************/
/* METHODS FOR BOTH GMAP AND CLIENT */
/*****************************************************************/
/*
* defines offset of mapcentre away from an element such as custom controls
* which overlay a large amount of map
* positive or negative according to offset direction where the element might be on the
* left or the right
*/
GMap.prototype.set_lng_offset = function (elemid, dir) {
var direction = 'right';
if (dir == 'left') {
direction = dir;
}
this.lngoffset = {direction: direction, referenceelem: elemid};
}
/*
* returns lng offset according to definitions and current map situation
*/
GMap.prototype.calc_lng_offset = function () {
//get lng width of map
var eastlng = this.map.getBounds().getNorthEast().lng();
var westlng = this.map.getBounds().getSouthWest().lng();
var lngspan;
if (westlng <= 0 && eastlng >= 0) {
lngspan = Math.abs(westlng) + eastlng;
} else if (westlng >= 0 && eastlng <= 0) {
lngspan = (180 - westlng) + (180 - Math.abs(eastlng));
} else if (westlng < 0 && eastlng < 0) {
lngspan = Math.abs(eastlng) + westlng;
} else {
lngspan = eastlng - westlng;
}
//get px width of map and referenced element
var mapwidth = $("#" + this.name).width();
var offsetpx = $("#" + this.lngoffset.referenceelem).width();
//convert this px to lng offset for map by multiplying by lngpx
var lngperpx = lngspan / mapwidth; //calc lng/px as lngpx
//calc the offset lng
var offsetlng = offsetpx * lngperpx;
if (this.lngoffset.direction == 'left') {
var offsetlng = 0 - offsetlng;
}
return offsetlng;
}
/*
* returns an object with north south east west and centre coordinates of the current view
* args.precision states number of figures after decimal returned - if not give a full result is returned.
* #returns {float north,float east,float south,float west,float lat,float lng}
*/
GMap.prototype.get_viewport_coords = function (args) {
if (args == undefined) {
args = {};
}
var coords = {};
coords.north = this.map.getBounds().getNorthEast().lat();
coords.east = this.map.getBounds().getNorthEast().lng();
coords.south = this.map.getBounds().getSouthWest().lat();
coords.west = this.map.getBounds().getSouthWest().lng();
coords.lat = this.map.getCenter().lat();
coords.lng = this.map.getCenter().lng();
if (args.precision != undefined) {
coords.north = coords.north.toFixed(args.precision);
coords.east = coords.east.toFixed(args.precision);
coords.south = coords.south.toFixed(args.precision);
coords.west = coords.west.toFixed(args.precision);
}
return coords;
}
/*
* 'map_query'
* takes a text query and queries to google for info
*
* required due to APIs not being the same, a uuid is registered globally and a global process used to redirect
* because of this the global process must identify a map object by UUID and only expect a single argument as an object literal (JSON)
* this is then passed back to the object that initiated the ajax or UUID request
*
* #param OBJECT query_cfg to send to gmap geocode
* #param string query_cfg.type states what type of query and what action to take, allowing multiple use for this method
* #param string query_cfg.query_data a string containing address data such as '<postcode>, <street>, <property>'
* #param string query_cfg.callback to return the data to
*/
GMap.prototype.geo_query = function (query_cfg) {
//package pre query data and set defaults if not set
query_cfg = model.array_defaults(
query_cfg,
{
clientid: this.name,
callback: 'update_client_do'//client code can set its own callback,else set callback to this
}
);
var geo_queryid = MAP_INTERFACE_CTRL.callback_push(query_cfg);
switch (query_cfg.type) {
case "location"://returns location data at given lat lng coords
var gcoder = new google.maps.Geocoder();
gcoder.geocode({'location': {lat: query_cfg.lat, lng: query_cfg.lng}}, function (results, status) {
var server_response = {results: results, status: status};
eval("MAP_INTERFACE_CTRL.callback_pop('" + geo_queryid + "',server_response)");
});
break;
case "address_latlng":
var gcoder = new google.maps.Geocoder();
gcoder.geocode({'address': query_cfg.query_data}, function (results, status) {
var server_response = {results: results, status: status};
eval("MAP_INTERFACE_CTRL.callback_pop('" + geo_queryid + "',server_response)");
});
break;
case "sv_pano_latlng"://gets streetview pano for given lat lng
var sv_service = new google.maps.StreetViewService();
sv_service.getPanoramaByLocation(query_cfg.latlng, query_cfg.radius, function (results, status) {
var server_response = {results: results, status: status};
eval("MAP_INTERFACE_CTRL.callback_pop('" + geo_queryid + "',server_response)");
});
break;
case "viewport_range"://returns lat lng for viewport and centre to callback
var gcoder = new google.maps.Geocoder();
var bounds = this.bounds;
var center = this.map.getCenter();
gcoder.geocode({address: change_request}, function (results, status) {
callback_obj.viewport_range_do(results, status)
});
break;
}
}
/*
* 'formatted_geo_result'
* interprets geocoded results to a standard uniform independent of map api
* #param OBJECT geo_result data returned (in this map interface from google)
*/
GMap.prototype.formatted_geo_result = function (geodata) {
var formatted = {};
var itemdefaults = {
address: '',
lat: null,
lng: null
}
for (var i in geodata.results) {
var item = {
address: geodata.results[i].formatted_address,
lat: geodata.results[i].geometry.location.lat(),
lng: geodata.results[i].geometry.location.lng(),
}
formatted[i] = model.array_defaults(item, itemdefaults);
}
return formatted;
}
/*
* 'map_change'
* takes a request and processes and changes map accordingly
*
* callerobj is optional, if not given then callback will be back to this map object
* if a callerobj is given this must be to an object which can accept it
* (if callerobj is a top level function it needs to pass the object as keyword window - not 'window')
* The callback method is named as query type with _do appended eg address_move_do
* Some query types require the caller object to handle the query and DO NOT have a method defined in the map object
* If this map object DOES have the callback but a callback_obj is given then it will override this map object
*
* #param string change_request free text to send to gmap object
* #param string change_type states what type of query and what action to take, allowing multiple use for this method
* #param string callback function to run on change completion.
*/
GMap.prototype.map_change = function (change_type, change_data, callback) {
switch (change_type) {
case "lat_lng":
this.map.panTo({lat: change_data.latlng.lat, lng: change_data.latlng.lng + this.calc_lng_offset()});
break;
case "address"://to address_latlng as translation for this map object
this.geo_query({type: "address_latlng", clientid: this.name, callback: "map_change_do", change_type: change_type, query_data: change_data});
break;
}
if (callback != undefined) {
this.loadedCallback(callback);
}
}
/*
* 'map_change_do'
* processes any ajax return required by map_change
*
* #param string change_request free text to send to gmap object
* #param string change_type states what type of query and what action to take, allowing multiple use for this method
*/
GMap.prototype.map_change_do = function (pre_data, callback_data) {
switch (pre_data.change_type) {
case "address":
this.map_change("lat_lng", {latlng: {lat: callback_data.results[0].geometry.location.lat(), lng: callback_data.results[0].geometry.location.lng()}}); //callback_data.results[0].geometry.location.lat()
break;
}
}
/*
* permanently deletes all objects such as map markers (pins) etc
*/
GMap.prototype.clearmapobjects = function () {
this.map.clearMarkers();
}
GMap.prototype.panotestA = function () {
var locquery = "framlingham tech centre";
this.map_change("address", locquery);
this.map.setZoom(20);
this.geo_query("location", locquery)
this.geo_query({type: "address_latlng", clientid: this.name, callback: "panotestB", query_data: locquery});
}
GMap.prototype.panotestB = function (pre_data, callback_data) {
var pin = this.add_pin(callback_data.results[0].geometry.location.lat(), callback_data.results[0].geometry.location.lng(), {infopop: {content: 'hello', streetview: true}});
}
/*
* 'add_pin'
* adds a pin to a map
*
* #param float lat is latitude position
* #param float lng is longitude position
* #param object info_args other pin constructs such as the info displayed while clicking it
* #return object marker
*/
GMap.prototype.add_pin = function (lat, lng, info_args) {
info_args = model.array_defaults(
info_args,
{
width: 16,
height: 16,
animation: google.maps.Animation.DROP,
icon: {
url: "http://" + ROOTUC + "//css/images/icons/ROYOdot_a.gif"
},
infopop: null
}
);
/*
var icon = {
url: info_args.icon.url,
size: new google.maps.Size(20, 20),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(0, 0)
};
*/
var iconImage = new google.maps.MarkerImage(
info_args.icon.url, // url to image inc http://
null, // desired size
null, // offset within the scaled sprite
null, // anchor point is half of the desired size
new google.maps.Size(info_args.width, info_args.height) // required size
);
var pin = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
map: this.map,
title: info_args.label,
icon: iconImage,
optimized: false, //to allow for animations
animation: info_args.animation,
});
if (info_args.infopop != null) {
/*content is forced into div with black font as google default
* is white text on white background ?!?!?!
*/
info_args.infopop = model.array_defaults(
info_args.infopop,
{
fontcolor: '#000000',
infowidth: '40em',
streetview: false
});
//standard google defs
var infowindow = new google.maps.InfoWindow();
//extra seperate data ref for client apps
infowindow.metadata = {
parent: this,
parentid: this.infowindowindex,
};
this.infowindows[this.infowindowindex] = {
infowidth: info_args.infopop.infowidth,
content: info_args.infopop.content,
fontcolor: info_args.infopop.fontcolor,
latlng: {lat: lat, lng: lng},
streetview: info_args.infopop.streetview
};
this.infowindowindex++;
//build for pin click
google.maps.event.addListener(pin, 'click', function () {
var infodata = infowindow.metadata.parent.infowindows[infowindow.metadata.parentid];
//build content
var infocontent = "<div id='" + infowindow.metadata.parent.name + "infowindow" + (infowindow.metadata.parentid) + "' style='color:" + infodata.fontcolor + ";width:" + infodata.infowidth + "'>";
infocontent += infodata.content;
if (infodata.streetview) {
infocontent += "<div id='" + infowindow.metadata.parent.name + "infowindowsvframe" + (infowindow.metadata.parentid) + "' class='infostreetviewframe' >";
infocontent += ". . . loading view</div>";
}
infocontent += "</div>";
infowindow.setContent(infocontent);
infowindow.open(this.map, pin);
if (infodata.streetview) {
var service = new google.maps.StreetViewService();
infowindow.metadata.parent.geo_query({type: "sv_pano_latlng", latlng: infodata.latlng, radius: 50, clientid: infowindow.metadata.parent.name, streetviewframe: infowindow.metadata.parent.name + "infowindowsvframe" + (infowindow.metadata.parentid), callback: "add_streetview_do"});
}
});
}
}
/*
* 'add_streetview'
* for flexibility addition of a streetview into a named dom element id
*
* #param object args
* #param.args string elemid the element to put the streetview into
*
*/
GMap.prototype.add_streetview_do = function (predata, callbackdata) {
var svelement = document.getElementById(predata.streetviewframe);
if (callbackdata.status == google.maps.StreetViewStatus.OK) {
var targetPOVlocation = predata.latlng
var svLatLng = {lat: callbackdata.results.location.latLng.lat(), lng: callbackdata.results.location.latLng.lng()};
// var svLatLng = new google.maps.LatLng(callbackdata.results.location.latLng.lat(), callbackdata.results.location.latLng.lng());
//var svLatLng = callbackdata.results.location.latLng;
var povyaw = this.getBearing(svLatLng, targetPOVlocation);
var sv = new google.maps.StreetViewPanorama(svelement);
var svoptions = {
position: svLatLng,
addressControl: false,
linksControl: false,
panControl: false,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
},
pov: {
heading: povyaw,
pitch: 10,
zoom: 1
},
enableCloseButton: false,
visible: true
};
sv.setOptions(svoptions);
} else {
svelement.innerHTML = "no streetview available";
}
}
/*
* 'getBearing'
* calcs bearing from two latlngs
*
*/
GMap.prototype.getBearing = function (fromLatLng, targetLatLng) {
var DEGREE_PER_RADIAN = 57.2957795;
var RADIAN_PER_DEGREE = 0.017453;
var dlat = targetLatLng.lat - fromLatLng.lat;
var dlng = targetLatLng.lng - fromLatLng.lng;
// We multiply dlng with cos(endLat), since the two points are very closeby,
// so we assume their cos values are approximately equal.
var bearing = Math.atan2(dlng * Math.cos(fromLatLng.lat * RADIAN_PER_DEGREE), dlat)
* DEGREE_PER_RADIAN;
if (bearing >= 360) {
bearing -= 360;
} else if (bearing < 0) {
bearing += 360;
}
return bearing;
}
/*
* 'add_polygon'
* adds a polygon to a map using an array of lat lng coords
* these are pushed in the order they appear in the locationarray
*
* #param array locationarray - which event/change type triggers update of this element
*
*/
GMap.prototype.add_polygon = function (args) {
//construct and store polygon
var polyobj = model.array_defaults(args, {name: "polygon", polygon: null, infohtml: null, box: null, focuson: false});
//remove any same named polygon
if (this.polygons[args.name] != undefined) {
this.polygons[args.name].polygon.setMap(null);
this.polygons[args.name] = null;
}
var newpolygon = new Array();
polyobj.box = new google.maps.LatLngBounds();
for (var l in args.polygon) {
var point = new google.maps.LatLng(args.polygon[l].lat, args.polygon[l].lng);
newpolygon.push(point);
polyobj.box.extend(point);
}
polyobj.polygon = new google.maps.Polygon(
{
map: this.map,
paths: newpolygon,
strokeColor: '#00ff00',
strokeOpacity: 0.75,
strokeWeight: 2,
fillColor: '#00ff00',
fillOpacity: 0.15
}
);
this.polygons[args.name] = polyobj;
//set required changes to map
if (args.infohtml != null) {
// content is forced into div with black font as google default is white text on white background ?!?!?!
polyobj.info = new google.maps.InfoWindow(
{
content: "<div style='color:#000000'>" + args.infohtml + "</div>"
});
var selfobj = this;
google.maps.event.addListener(this.polygons[args.name].polygon, 'click', function (event) {
var point = event.latLng;
selfobj.polygons[args.name].info.setPosition(point);
selfobj.polygons[args.name].info.open(selfobj.map);
});
}
if (polyobj.focuson) {
this.map.fitBounds(polyobj.box);
}
}
/*****************************************************************/
/* methods for CLIENT --> GMAP change */
/*********************************************************S ********/
/*
* allows gui to register elements so when changes / events occur in the map gui, its
* parent gui can be updated.
* #param string change_type - which event/change type triggers update of this element
* #param string change_return - data required to be returned eg latlng or address etc
* #param string callback - the page element identifier to update
*/
GMap.prototype.register_elem = function (change_type, event_return_cfg) {
switch (change_type) {
case "location":
switch (event_return_cfg.return_type) {
case "address":
this.gui_reg.location.address.push(event_return_cfg);
break;
}
break;
}
}
/*****************************************************************/
/* methods for GMAP --> CLIENT change */
/*****************************************************************/
/*
* checks registered change type to send back to client
* #param string change_type - which event/change type triggers update of this element
* #param string data_request - data required to be returned
* #param string regelem - the parent gui identifier to update5
* #param object attr - which attribute to update eg for input, its value, for div its html
*/
GMap.prototype.update_client_go = function (change_type, data_request) {
switch (change_type) {
case "location":
var loc = this.get_viewport_coords();
this.geo_query({type: "location", lat: loc.lat, lng: loc.lng});
}
}
/*
* actions client_update
* #param string change_type - which event/change type triggers update of this element
* #param string data_request - data required to be returned
* #param string regelem - the parent gui identifier to update5
* #param object attr - which attribute to update eg for input, its value, for div its html
*/
GMap.prototype.update_client_do = function (pre_data, callback_data) {
if (callback_data.status != "ZERO_RESULTS") {
switch (pre_data.type) {
case "location":
var location_data_registrars = this.gui_reg.location;
for (var loc_type_list in location_data_registrars) {
switch (loc_type_list) {
case "address":
var address = callback_data.results[0].formatted_address;
for (var r in location_data_registrars[loc_type_list]) {
var event_return = location_data_registrars[loc_type_list][r];
if (event_return != undefined) {
event_return.address = this.address_parse("postcode", address);
if (event_return.callback != undefined) {
eval(event_return.callback + "(event_return)");
}
}
}
break;
}
}
break;
}
}
}
/*****************************************************************/
/* PRIVATE METHODS */
/*****************************************************************/
GMap.prototype.address_parse = function (required_part, address) {
var result = "";
address = address.split(", ");
var country = address[address.length - 1];
switch (country) {
case "UK":
switch (required_part) {
case "postcode":
result = address[address.length - 2];
result = result.substr(result.indexOf(" ") + 1);
break;
}
break;
}
return result;
}
GMap.prototype.loadedCallback = function (callback) {
this.calledbackonload = false;
google.maps.event.addListenerOnce(this.map, 'tilesloaded', function () {
google.maps.event.clearListeners(this.map, 'idle');
eval(callback + '()');
});
google.maps.event.addListenerOnce(this.map, 'idle', function () {
eval(callback + '()'); //add idle as a catch all
});
/*
google.maps.event.addListenerOnce(this.map, 'idle', function() {
eval(callback + '()')
});
*/
}
/*
* zooms map to next level from current depending on dir being '+' or '-'
*/
GMap.prototype.incrementZoom = function (dir, callback) {
var newZoom = this.map.getZoom();
if (dir == '+') {
newZoom++;
}
if (dir == '-') {
newZoom--;
}
this.map.setZoom(newZoom);
if (callback != undefined) {
this.loadedCallback(callback);
}
}
/*
* zooms map to fully zoomed in
*/
GMap.prototype.zoomMax = function (callback) {
this.map.setZoom(this.mapoptions.maxzoom);
if (callback != undefined) {
this.loadedCallback(callback);
}
}
/*
* zooms map to fully zoomed out
*/
GMap.prototype.zoomMin = function (callback) {
this.map.setZoom(this.mapoptions.minzoom);
if (callback != undefined) {
this.loadedCallback(callback);
}
}
/*
* zooms map to contain the given box as per gmaps southwest / northeast corner specs
*/
GMap.prototype.boxZoom = function (latfrom, latto, lngfrom, lngto) {
var bottomleft = {lat: latfrom, lng: lngfrom};
var topright = {lat: latto, lng: lngto};
var box = new google.maps.LatLngBounds(bottomleft, topright);
this.map.fitBounds(box);
}
/*
* forces zoom in to min max params and returns true if it has been constrained
* additional callback if required for when zoom to constraints has finished
*/
GMap.prototype.constrainzoom = function (callback) {
if (this.map.getZoom() > this.mapoptions.maxzoom) {
this.map.setZoom(this.mapoptions.maxzoom);
} else if (this.map.getZoom() < this.mapoptions.minzoom) {
this.map.setZoom(this.mapoptions.minzoom);
} else {
return false;
}
if (callback != undefined) {
this.loadedCallback(callback);
}
return true;
}
/*add extras to generic map object*/
google.maps.Map.prototype.clearMarkers = function () {
for (var i = 0; i < this.markers.length; i++) {
this.markers[i].setMap(null);
}
this.markers = new Array();
};
/*
* places an existing div by id as a map control
*/
GMap.prototype.addcontrol = function (divid, posn) {
if (posn == undefined) {
posn = google.maps.ControlPosition.TOP_LEFT;
}
this.map.controls[posn].push(document.getElementById(divid));
}
/* translate normal functions to internal map object */
/* trigger setup */
this.__construct(mapId, options);
}

get overlapping features informations on popup using WFS layer in Openlayers 3

I'm trying to get information from WFS layer that contain several overlapping features. i use this function to get information but i receive juste the information of the top feature.
Some one can help me ?
olMap.on('click', function(evt) {
var feature = olMap.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
return feature;
});
if (feature) {
var coordinate = evt.coordinate;
var viewResolution = /** #type {number} */ (view.getResolution());
var coord = feature.getGeometry().getCoordinates();
var props = feature.getProperties();
content.innerHTML = '<p><b>City</b>:'+props.nam+'<br> ZIP CODE:'+props.f_code+'</p>';
overlay.setPosition(coordinate);
}
else{
overlay.setPosition(undefined);
}
Dont return the feature from forEachFeatureAtPixel method instead move if code inside the that method only.
olMap.on('click', function(evt) {
var feature = olMap.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
var coordinate = evt.coordinate;
var viewResolution = /** #type {number} */ (view.getResolution());
var coord = feature.getGeometry().getCoordinates();
var props = feature.getProperties();
content.innerHTML = '<p><b>City</b>:'+props.nam+'<br> ZIP CODE:'+props.f_code+'</p>';
overlay.setPosition(coordinate);
});

OL3: GetFeature from Layers by Coordinate

I want to get the Feature of a Layer by coordinate.
Furthermore I want to open this feature in a popup, which I have solved so far by an onclick event. But I want to realize by giving the coordinates of a feature and opening the popup of the featue.
I have a layer with the map and a layer with the features:
if (trackMap != null) {
for (var i = 0; i < trackMap.length; i++) {
var trackInfo = trackMap[i];
lat = parseFloat(trackInfo.lat);
lon = parseFloat(trackInfo.lon);
var layergpx = new ol.layer.Vector({
source: new ol.source.Vector({
parser: new ol.parser.GPX(),
url: '${contextRoot}/gps/gpx2' + trackInfo.url
})
});
layers.push(layergpx);
}
}
I want to get the feature of this layer in another Javascript function.
How I open a pop up by clicking on the map:
/**
* The Click Event to show the data
*/
var element = document.getElementById('popup');
var popup = new ol.Overlay({
element: element,
positioning: ol.OverlayPositioning.BOTTOM_CENTER,
stopEvent: false
});
map.addOverlay(popup);
map.on('singleclick', function(evt) {
map.getFeatures({
pixel: evt.getPixel(),
layers: vectorLayers,
success: function(layerFeatures) {
var feature = layerFeatures[0][0];
if (feature) {
var geometry = feature.getGeometry();
var coord = geometry.getCoordinates();
popup.setPosition(coord);
$(element).popover({
'placement': 'top',
'html': true,
'content': feature.get('desc')
});
$(element).popover('show');
} else {
$(element).popover('destroy');
}
}
});
});
But I want this feature not to be opened by clicking on it on the map, but by entering a coordinate in a textfield and the map opens this pop up, like in the onclick event.
Take a look at this example to see if it helps you:
http://openlayers.org/en/latest/examples/kml.html
var displayFeatureInfo = function(pixel) {
map.getFeatures({
pixel: pixel,
layers: [vector],
success: function(featuresByLayer) {
var features = featuresByLayer[0];
var info = [];
for (var i = 0, ii = features.length; i < ii; ++i) {
info.push(features[i].get('name'));
}
document.getElementById('info').innerHTML = info.join(', ') || '&nbsp';
}
});
map.getFeatures() has this success callback where it delivers the features of the layers specified in layers: [vector]. Customize it at will to get what you need.
=== Update ===
In the OpenLayers 3's Map object you have a function: getPixelFromCoordinate
/**
* #param {ol.Coordinate} coordinate Coordinate.
* #return {ol.Pixel} Pixel.
*/
ol.Map.prototype.getPixelFromCoordinate = function(coordinate) {
var frameState = this.frameState_;
if (goog.isNull(frameState)) {
return null;
} else {
var vec2 = coordinate.slice(0, 2);
return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2);
}
};

Categories

Resources