draw polylines between multiple predefined markers using direction api - flutter

This is my url
https://maps.googleapis.com/maps/api/directions/json?key={My api key}&units=metric&origin=27.671690422260465,84.40326005320367&destination=27.6764151316667,84.41106864336271&mode=driving&waypoints=27.671690422260465,84.403260053203670|27.677023212852635,84.406927312726400|27.676814185326755,84.409158910582240|27.677004210366814,84.410972083840110|27.676415131666700,84.411068643362710
This is my code to draw polylines
void drawPolyLines() async {
// getAddressFromLatLng();
String origin = "";
String url = "";
http.Response? response;
var ltLn = latLag
.toString()
.replaceAll(",", "|")
.replaceAll(":", ",")
.replaceAll("[", "")
.replaceAll("]", "")
.replaceAll(" ", "");
List<Placemark> placemarks = [];
for (int i = 0; i < latLen.length; i++) {
placemarks = await placemarkFromCoordinates(
latLen[i].latitude, latLen[i].longitude);
}
log("second for vhitra");
url =
"https://maps.googleapis.com/maps/api/directions/json?key=${Keys.googleApiKey}&units=metric&origin=${latLen.first.latitude},${latLen.first.longitude}&destination=${latLen.last.latitude},${latLen.last.longitude}&mode=driving&waypoints=$ltLn}";
response = await http.post(Uri.parse(url));
pResponse = pRes.polylineResponseFromJson(response.body);
log("This is url>>>>>>>>>>>>>>>>>>>>>>>>>> $url");
log("THis is response ${response.body}");
try {
//PolylinePoints polylinePoints = PolylinePoints();
for (int i = 0; i < pResponse.routes![0].legs![0].steps!.length; i++) {
polylin.add(Polyline(
polylineId: PolylineId(
pResponse.routes![0].legs![0].steps![i].polyline!.points!),
points: [
LatLng(
pResponse.routes![0].legs![0].steps![i].startLocation!.lat!,
pResponse.routes![0].legs![0].steps![i].startLocation!.lng!),
LatLng(pResponse.routes![0].legs![0].steps![i].endLocation!.lat!,
pResponse.routes![0].legs![0].steps![i].endLocation!.lng!),
],
width: 3,
color: Colors.red));
}
} catch (e) {
rethrow;
}
//}
//log("This is map response ${response.body}");
}
in my api call when i use wayPoints then a polyline is drawn between start and end point leaving other markers like this
but i want to connect the polylines which is shown in google map in the same order which markers are shown but i am unable to do so need some help in here.

Do it like this i found the solution i am posting it so that it might may come in handy to others.
void drawPolyLines() async {
http.Response? response;
var ltLn = latLag
.toString()
.replaceAll(",", "|")
.replaceAll(":", ",")
.replaceAll("[", "")
.replaceAll("]", "")
.replaceAll(" ", "");
String origin = "${latLen.first.latitude},${latLen.first.longitude}";
String destination = "${latLen.last.latitude},${latLen.last.longitude}";
String url =
"https://maps.googleapis.com/maps/api/directions/json?key=${Keys.googleApiKey}&origin=$origin&destination=$destination&mode=driving&waypoints=$ltLn";
response = await http.post(Uri.parse(url));
pResponse = pRes.polylineResponseFromJson(response.body);
try {
PolylineId id = PolylineId(DateTime.now().microsecond.toString());
for (int i = 0; i < (pResponse.routes![0].legs ?? []).length; i++) {
for (int j = 0; j < pResponse.routes![0].legs![i].steps!.length; j++) {
final Polyline polyline = Polyline(
polylineId: PolylineId(
pResponse.routes![0].legs![i].steps![j].polyline!.points!),
width: 2,
color: Colors.blue,
startCap: Cap.roundCap,
endCap: Cap.buttCap,
points: [
LatLng(
pResponse.routes?[0].legs?[i].steps?[j].startLocation?.lat ??
0.0,
pResponse.routes?[0].legs?[i].steps?[j].startLocation?.lng ??
0.0),
LatLng(
pResponse.routes?[0].legs?[i].steps?[j].endLocation?.lat ??
0.0,
pResponse.routes?[0].legs?[i].steps?[j].endLocation?.lng ??
0.0),
],
);
polylin.add(polyline);
polyLines[id] = polyline;
update();
}
update();
}
} catch (e) {
rethrow;
}
}

Related

How to get nodes in OpenStreetMap using Leaflet strictly contained in my current view?

I'm able to correctly query data from the OSM api.
I can also show highways and trunks correctly on the map.
However, the query gives me back always results for a fixed zoom even if my current zoom is higher.
this is how i do my call:
var opl = new L.OverPassLayer({
minZoom: 14,
query: '(way({{bbox}})["highway"~"^(' + query + ')$"];);(._;>;);out geom;',
onSuccess: function (data) {
console.log(data);
urlxml = data.urlxml;
data = data.result;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
//document.getElementById("demo").innerHTML = xhttp.responseText;
$("#fileData").text(xhttp.responseText);
console.log(xhttp.responseText);
}
};
xhttp.open("GET", urlxml, true);
console.log(urlxml);
xhttp.send();
console.log(urlxml);
for (let i = 0; i < data.elements.length; i++) {
let pos;
let marker;
const e = data.elements[i];
if (e.id in this._ids) {
continue;
}
this._ids[e.id] = true;
if (e.type === "way") {
let posWay = [];
for (let j = 0; j < e.geometry.length; j++) {
pos = L.latLng(e.geometry[j].lat, e.geometry[j].lon);
posWay.push(pos);
}
var polyline = L.polyline(posWay, { color: "blue" }).addTo(map);
}
console.log("DATA: " + JSON.stringify(data.elements));
}
},
});
How can i get results from the current view only?
Thank you.

Leaflet: Moving the map doesn't move the icons with it, instead the icons stay fixed to the same position on the page

Moving the map doesn't move the icons with it, instead the icons stay fixed to the same position on the page.
My icons get added to the correct latitude and longitude on my map. However, when I drag the map, the icons stay fixed on the same position on the page and are no longer being displayed at the correct latitude and longitude.
let sMap;
let ciLayer;
let neutralMarkers = [];
let gVesselIcons = {};
let numOfVessels = 0;
let ROI;
let nwLat;
let nwLon;
let seLat;
let seLon;
window.indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB;
//prefixes of window.IDB objects
window.IDBTransaction =
window.IDBTransaction ||
window.webkitittIDBTransaction ||
window.msIDBTransaction;
window.IDBKeyRange =
window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
let db;
const [dbPromise, dbResolve, dbReject] = (() => {
let resolve, reject;
return [
new Promise((res, rej) => {
resolve = res;
reject = rej;
}),
resolve,
reject
];
})();
let dbGSTSStore = window.indexedDB.open('GSTSStore', 1);
let dbVessels;
let dbTransactions;
let dbMessages;
dbGSTSStore.onerror = function(event) {
dbReject();
console.log('error: ');
};
dbGSTSStore.onsuccess = function(event) {
dbResolve();
db = dbGSTSStore.result;
};
dbGSTSStore.onupgradeneeded = function(event) {
const db = event.target.result;
dbVessels = db.createObjectStore('vessels', {
keyPath: 'mmsi'
});
dbMessages = db.createObjectStore('messages', {
keyPath: 'id'
});
dbTransactions = db.createObjectStore('transactions', {
keyPath: 'id'
});
};
async function InitializeSimple(
pBuildNumber,
pSysPersonId,
pSysOrganizationId
){
await GetOrganizationPrefs(pSysOrganizationId);
await GetPersonPrefs(pSysPersonId);
SetLabelText('lblBuildNumber', `Build: ${pBuildNumber}`);
dragElement(document.getElementById("vessel-info"));
nwLat = gOrganizationPrefs.roinwse.nwlat || gPersonPrefs.aoi.nwlat;
nwLon = gOrganizationPrefs.roinwse.nwlon || gPersonPrefs.aoi.nwlon;
seLat = gOrganizationPrefs.roinwse.selat || gPersonPrefs.aoi.selat;
seLon = gOrganizationPrefs.roinwse.selon || gPersonPrefs.aoi.selon;
try {
sMap = L.map('map-content', {
fullscreenControl: false,
zoomControl: false,
zoom: 6,
attributionControl: false,
preferCanvas: true
}).setView([19, 55]);
ciLayer = L.canvasIconLayer({}).addTo(sMap);
L.tileLayer(MapUrl[0], {
attribution: MapAttribution[0],
zoom: 5,
minZoom: 4,
maxNativeZoom: 13,
maxZoom: 20
}).addTo(sMap);
}
catch (error) {
console.log("error initializing map\n");
}
// SetVesselUpdate();
if(gOrganizationPrefs) await SetROI(gOrganizationPrefs.roinwse);
else await SetROI(gPersonPrefs.aoi);
await CreateNeutralLayer();
}
function SetLabelText(pLabel, pText) {
const lLabel = document.getElementById(pLabel);
if (lLabel !== undefined) lLabel.textContent = pText;
}
function CreateNeutralLayer(){
return new Promise((resolve, reject) => {
try {
const lTransaction = db.transaction(['vessels'], 'readonly');
let vessels = lTransaction.objectStore('vessels');
const countRequest = vessels.count();
countRequest.onsuccess = function() {
numOfVessels = countRequest.result;
}
vessels.openCursor().onsuccess = function(e) {
let cursor = e.target.result;
if (cursor !== null) {
let value = cursor.value;
let latitude = value.lat;
let longitude = value.lon;
let canInclude = checkROIBoundaries(latitude, longitude);
if (canInclude && cursor.value !== undefined) {
AddToLayers(cursor.value);
}
cursor.continue();
}
}
resolve('OK');
}
catch (err) {
console.log("error is: ", err, "\n");
reject({ error: err, function: 'CreateNeutralLayer()'});
}
});
}
function AddToLayers(vessel) {
let vesselRotationDegree = vessel.headingdegree.toString().padStart(2, '0');
if (vesselRotationDegree == '32') vesselRotationDegree = '00';
let vesselIconType = 'type-3';
let gBaseRiskIconURL = `./public/img/vessel/${vesselIconType}/vessel-`;
let gBaseRiskNeutralUrl = `${gBaseRiskIconURL}neutral-`;
var vIcon = L.icon({
iconUrl: `${gBaseRiskNeutralUrl}${vesselRotationDegree}.svg`,
iconSize: [24, 24],
iconAnchor: [24, 24]
});
const marker = L.marker([vessel.lat, vessel.lon], { icon: vIcon});
marker.properties = {
vesselname: vessel.shipname,
mmsi: vessel.mmsi,
imo: vessel.imo,
lat: vessel.lat,
lon: vessel.lon,
datetime: vessel.received_time,
heading: vessel.hdg,
sog: vessel.sog,
shiptype_descr: vessel.shiptype_descr,
last_positional_update: vessel.last_updated
};
marker.bindPopup(popupNeutralMarker, {
maxWidth: 392,
className: `map-info`
});
neutralMarkers.push(marker);
if (neutralMarkers.length >= numOfVessels) {
ciLayer.addLayers(neutralMarkers);
const vesselsInROI = document.getElementById('vessels-in-roi');
vesselsInROI.innerHTML = numOfVessels;
}
}
function checkROIBoundaries(latitude, longitude) {
let canInclude = false;
const lLatOK =
latitude >= Math.min(nwLat, seLat) &&
latitude <= Math.max(nwLat, seLat);
const lLonOK =
longitude >= Math.min(nwLon, seLon) &&
longitude <= Math.max(nwLon, seLon);
if (lLatOK && lLonOK) canInclude = true;
else numOfVessels--;
return canInclude;
}
function SetROI(pROI) {
return new Promise((resolve, reject) => {
try {
if (pROI.nwlat + pROI.nwlon + pROI.selat + pROI.selon === 0) return;
const defaultBoundaryStyle = {
color: 'blue',
fillColor: 'lightblue',
fillOpacity: 0.2
}
ROI = new L.rectangle(
[
[pROI.selat, pROI.selon],
[pROI.nwlat, pROI.selon],
[pROI.selat, pROI.selon],
[pROI.selat, pROI.nwlon]
],
defaultBoundaryStyle
)
sMap.addLayer(ROI, true);
// Center ROI
sMap.fitBounds([
[gOrganizationPrefs.roinwse.nwlat, gOrganizationPrefs.roinwse.nwlon],
[gOrganizationPrefs.roinwse.selat, gOrganizationPrefs.roinwse.selon]
]);
resolve('OK');
}
catch (err) {
console.log("error is: ", err, "\n");
reject({ error: err, function: 'SetROI'});
}
})
}

Distance calculation Flutter background Location

I am trying to develop a Location service-based Distance calculation app. the problem is I need this to be run when the app is in the background as well. so I used the following plugin to do so.
https://pub.dev/packages/background_location
when this runs on AVD nothing happened but worked fine. but when run on some devices I got the wrong calculations. I have noticed that this happens when the app is in the background this is. following is a partial recreation of mine. I just want to know if my code get any error before posting this as an issue
Future<void> startLocationUpdate() async {
var permission = await Permission.locationAlways.isGranted;
if (!permission) {
var t = await Permission.locationAlways.request();
}
oldPosition2 = Location(
longitude: currentPosition.longitude, latitude: currentPosition.latitude);
isWaited = false;
waitButtonText = "WAIT";
BackgroundLocation.stopLocationService();
BackgroundLocation.setAndroidConfiguration(2000);
await BackgroundLocation.setAndroidNotification(
title: "XXXXXXXXXXXXXXXXX",
message: "XXXXXXXXXXXXXXXXXX",
icon: "XXXXXXXXXXXXXXXXXX",
);
//print('Inside startLocationUpdate');
await BackgroundLocation.startLocationService(distanceFilter: 20);
print('Inside startLocationUpdate 1');
BackgroundLocation.getLocationUpdates((location) {
try {
currentPosition = location;
LatLng pos = LatLng(location.latitude, location.longitude);
var rotation = MapKitHelper.getMarkerRotation(oldPosition2.latitude,
oldPosition2.longitude, pos.latitude, pos.longitude);
Marker movingMaker = Marker(
markerId: MarkerId('moving'),
position: pos,
icon: movingMarkerIcon,
rotation: rotation,
infoWindow: InfoWindow(title: 'Current Location'),
);
setState(() {
CameraPosition cp = new CameraPosition(target: pos, zoom: 17);
rideMapController.animateCamera(CameraUpdate.newCameraPosition(cp));
_markers.removeWhere((marker) => marker.markerId.value == 'moving');
_markers.add(movingMaker);
this.accuracy = location.accuracy.toStringAsFixed(0);
totalSpeed = location.speed;
totalDistance = totalDistance +
CalDistance(oldPosition2 != null ? oldPosition2 : location,
location, DistanceType.Kilometers);
var totalDistanceAdj = totalDistance != 0 ? totalDistance : 1;
//totalFare = 50 + (kmPrice * totalDistanceAdj);
print("distance $totalDistance");
});
oldPosition2 = location;
updateTripDetails(location);
Map locationMap = {
'latitude': location.latitude.toString(),
'longitude': location.longitude.toString(),
};
rideRef = FirebaseDatabase.instance
.reference()
.child("rideRequest/${widget.tripDetails.rideID}");
rideRef.child('driver_location').set(locationMap);
} catch (e) {
FirebaseService.logtoGPSData('Error in updates ${e}');
}
});
}
and the CalDistance method as follows
double CalDistance(Location pos1, Location pos2, DistanceType type) {
print("pos1 : ${pos1.latitude} pos2: ${pos2.latitude}");
double R = (type == DistanceType.Miles) ? 3960 : 6371;
double dLat = this.toRadian(pos2.latitude - pos1.latitude);
double dLon = this.toRadian(pos2.longitude - pos1.longitude);
double a = sin(dLat / 2) * sin(dLat / 2) +
cos(this.toRadian(pos1.latitude)) *
cos(this.toRadian(pos2.latitude)) *
sin(dLon / 2) *
sin(dLon / 2);
double c = 2 * asin(min(1, sqrt(a)));
double d = R * c;
//d = (d*80)/100;
return d;
}
double toRadian(double val) {
return (pi / 180) * val;
}
Any help or hint would be much appreciated

Format string to phone number with (123) 456-6789 pattern using dart

Here is my code
void main() {
String phoneNumber = '123456789';
String formattedPhoneNumber = phoneNumber.replaceFirst("(\d{3})(\d{3})(\d+)", "(\$1) \$2-\$3");
print('Formatted number ${formattedPhoneNumber}');
}
Output:
Formatted number 123456789
I want output as Formatted number (123) 456-6789
Try this
print('1234567890'.replaceAllMapped(RegExp(r'(\d{3})(\d{3})(\d+)'), (Match m) => "(${m[1]}) ${m[2]}-${m[3]}"));
Create a custom Masked class
import 'package:flutter/material.dart';
class MaskedTextController extends TextEditingController {
MaskedTextController({String text, this.mask, Map<String, RegExp> translator})
: super(text: text) {
this.translator = translator ?? MaskedTextController.getDefaultTranslator();
this.addListener(() {
var previous = this._lastUpdatedText;
if (this.beforeChange(previous, this.text)) {
this.updateText(this.text);
this.afterChange(previous, this.text);
} else {
this.updateText(this._lastUpdatedText);
}
});
this.updateText(this.text);
}
String mask;
Map<String, RegExp> translator;
Function afterChange = (String previous, String next) {};
Function beforeChange = (String previous, String next) {
return true;
};
String _lastUpdatedText = '';
void updateText(String text) {
if(text != null){
this.text = this._applyMask(this.mask, text);
}
else {
this.text = '';
}
this._lastUpdatedText = this.text;
}
void updateMask(String mask, {bool moveCursorToEnd = true}) {
this.mask = mask;
this.updateText(this.text);
if (moveCursorToEnd) {
this.moveCursorToEnd();
}
}
void moveCursorToEnd() {
var text = this._lastUpdatedText;
this.selection = new TextSelection.fromPosition(
new TextPosition(offset: (text ?? '').length));
}
#override
void set text(String newText) {
if (super.text != newText) {
super.text = newText;
this.moveCursorToEnd();
}
}
static Map<String, RegExp> getDefaultTranslator() {
return {
'A': new RegExp(r'[A-Za-z]'),
'0': new RegExp(r'[0-9]'),
'#': new RegExp(r'[A-Za-z0-9]'),
'*': new RegExp(r'.*')
};
}
String _applyMask(String mask, String value) {
String result = '';
var maskCharIndex = 0;
var valueCharIndex = 0;
while (true) {
// if mask is ended, break.
if (maskCharIndex == mask.length) {
break;
}
// if value is ended, break.
if (valueCharIndex == value.length) {
break;
}
var maskChar = mask[maskCharIndex];
var valueChar = value[valueCharIndex];
// value equals mask, just set
if (maskChar == valueChar) {
result += maskChar;
valueCharIndex += 1;
maskCharIndex += 1;
continue;
}
// apply translator if match
if (this.translator.containsKey(maskChar)) {
if (this.translator[maskChar].hasMatch(valueChar)) {
result += valueChar;
maskCharIndex += 1;
}
valueCharIndex += 1;
continue;
}
// not masked value, fixed char on mask
result += maskChar;
maskCharIndex += 1;
continue;
}
return result;
}
}
Now call it in your main dart file
var maskedController = MaskedTextController(mask: '(000) 000-0000');
TextField(
controller: maskedController,
style: Styles.textNormalStyle,
maxLines: 1,
),
This solution work for your this specific Question and scenario.
you can achieve using following code.
String formattedPhoneNumber = "(" + phoneNumber.substring(0,3) + ") " +
phoneNumber.substring(3,6) + "-" +phoneNumber.substring(6,phoneNumber.length);
Ricardo pointed to a great library but his answer is half right. Besides the intl_phone_number_input you need to get libphonenumber_plugin installed as well.
intl_phone_number_input: ^0.7.0+2
libphonenumber_plugin:
The method getRegionInfoFromPhoneNumber "discovers" what country the number is from eg +55... it would interpret as it's from Brasil and proceed to format the phone number accordingly. You can also explicitly tell from where the phone number is from passing the country's acronym into the method eg. await PhoneNumber.getRegionInfoFromPhoneNumber(phone, "US"); It'll disregard a country code if it doesn't fit the number you're entering.
String phone = "+19795555555";
PhoneNumber number =
await PhoneNumber.getRegionInfoFromPhoneNumber(phone);
String formattedNumber = await PhoneNumberUtil.formatAsYouType(
number.phoneNumber!,
number.isoCode!,
);
print(formattedNumber); // -> prints: '+1 979-555-5555'
Also you can use: https://pub.dev/packages/intl_phone_number_input/example
String phoneNumber = '+234 500 500 5005';
PhoneNumber number = await PhoneNumber.getRegionInfoFromPhoneNumber(phoneNumber);
String parsableNumber = number.parseNumber();
`controller reference`.text = parsableNumber

One pushpin click opens them all

Need help troubleshooting. All of the pushpins open upon clicking a single one opens up every pushpin infobox. I want there to be one pushpin infobox that changes each time a pushpin is clicked, only allowing one infobox to be open at a time.
// BING MAP Java Script
var map = null;
var pinid = 0;
var arrPinInfobox = [];
//Bing V8 start
function GetMap() { //LocInfo, Lat, Long
var _MapElement = document.getElementById("myMap");
if (_MapElement === null || typeof _MapElement === "undefined")
return;
if(jQuery("#pagesitemap_4_noMap").length < 0)
return;
var arrLocInfoRec = [];
var arrLLAdder = [];
var MapCenterLat;
var MapCenterLong;
var ZoomFactor;
var ZipLLSource = jQuery("#hdnZipLL").val();
var LocInfo = jQuery("#hdnCompleteLocInfo").val();
var ZipLL = [];
var Lat = "";
var Long ="";
console.log("Long");
if(typeof LocInfo === "undefined")
{
console.log("locInfo Undefined");
return;
}
if (ZipLLSource.length > 0) {
ZipLL = (ZipLLSource).split("`");
}
if (LocInfo.length > 0) {
arrLocInfoRec = LocInfo.split("|")
}
if (Lat.length > 0 && Long.length > 0) {
MapCenterLat = parseFloat(Lat);
MapCenterLong = parseFloat(Long);
ZoomFactor = 11; //16
}
else if (ZipLL.length >= 2) {
MapCenterLat = parseFloat(ZipLL[0]);
MapCenterLong = parseFloat(ZipLL[1]);
ZoomFactor = 11;
}
var mapOptions = {
credentials: ' ',
center: new Microsoft.Maps.Location(MapCenterLat, MapCenterLong),
mapTypeId: Microsoft.Maps.MapTypeId.Automatic,
zoom: ZoomFactor,
showScalebar: true
}
map = new Microsoft.Maps.Map('#myMap', mapOptions);
var arrPins = [];
var arrPinCenter = [];
//Generating Pins for multiple locations with Lat,Long
for (var locNum = 0; locNum <= arrLocInfoRec.length - 1; locNum++) {
try {
arrLLAdder = arrLocInfoRec[locNum].split("`");
if (arrLLAdder.length >= 13) {
//var latlong = arrLLAdder[11].split(',');
arrPinCenter[locNum] = new Microsoft.Maps.Location(parseFloat(arrLLAdder[11]), parseFloat(arrLLAdder[12]));
arrPinCenter[locNum] = new Microsoft.Maps.Location(parseFloat(arrLLAdder[11]), parseFloat(arrLLAdder[12]));
arrPins[locNum] = new Microsoft.Maps.Pushpin(
arrPinCenter[locNum], {
text: arrLLAdder[8] ,
icon: 'https://www.bingmapsportal.com/Content/images/poi_custom.png',
anchor: new Microsoft.Maps.Point(12, 39)
}
);
var adder = arrLLAdder[2] + '\r\n' + arrLLAdder[4] + '\r\n' + arrLLAdder[6] + arrLLAdder[9] + "\r\n" + arrLLAdder[1]
// Create the infobox for the pushpin
arrPinInfobox[locNum] = new Microsoft.Maps.Infobox(arrPins[locNum].getLocation(),
{ width: 350,
height: 100,
title: arrLLAdder[5],
description: adder,
offset: new Microsoft.Maps.Point(-3,13),
visible: false
});
// Add handler for the pushpin click event.
Microsoft.Maps.Events.addHandler(arrPins[locNum], 'click', displayInfobox);
// Add the Push Pins and InfoBox to the map all at once
if(arrPins.length > 0) {
map.entities.push(arrPins); //[locNum]
}
}
else {
console.log("Invalid Data: arrLocInfoRec[" + locNum + "] = \"" + arrLocInfoRec[locNum] + "\"");
}
} catch (e) {
console.log(e.message + "\r\n" + arrLocInfoRec[locNum]);
}
}
}
function displayInfobox(e) {
//map.entities.push(arrPinInfobox);
console.log("DisplayBox");
for(var i in arrPinInfobox){
arrPinInfobox[i].setOptions({ visible: true });
arrPinInfobox[parseInt(e.target.getText()) - 1].setOptions({ visible: true });
var infobox = arrPinInfobox[i];
infobox.setMap(map);
}
}
Your code in the displayInfobox function loops through all your infoboxes and sets visible to true and adding them to the map. Your code is functioning how it was written.
What you want to do is filter out your infoboxes. Personally I hate the whole array of infobox idea, it is messy. I believe I've recommended before the idea of creating a single infobox and reusing it when a pushpin is clicked. That is the best approach if you only need one infobox to appear at a time. If you want to be able to show multiple infoboxes at a time, store the reference to the infobox in the pushpin some how. All shapes in Bing Maps has a metadata property reserved for your custom data. Also just noticed you add the array of pushpins to the map several times, this will cause issues. Here is a proposed change to your code, I've added a comment with // Ricky: to indicate the changes I made:
// BING MAP Java Script
var map = null;
var pinid = 0;
var arrPinInfobox = [];
//Bing V8 start
function GetMap() { //LocInfo, Lat, Long
var _MapElement = document.getElementById("myMap");
if (_MapElement === null || typeof _MapElement === "undefined")
return;
if(jQuery("#pagesitemap_4_noMap").length < 0)
return;
var arrLocInfoRec = [];
var arrLLAdder = [];
var MapCenterLat;
var MapCenterLong;
var ZoomFactor;
var ZipLLSource = jQuery("#hdnZipLL").val();
var LocInfo = jQuery("#hdnCompleteLocInfo").val();
var ZipLL = [];
var Lat = "";
var Long ="";
console.log("Long");
if(typeof LocInfo === "undefined")
{
console.log("locInfo Undefined");
return;
}
if (ZipLLSource.length > 0) {
ZipLL = (ZipLLSource).split("`");
}
if (LocInfo.length > 0) {
arrLocInfoRec = LocInfo.split("|")
}
if (Lat.length > 0 && Long.length > 0) {
MapCenterLat = parseFloat(Lat);
MapCenterLong = parseFloat(Long);
ZoomFactor = 11; //16
}
else if (ZipLL.length >= 2) {
MapCenterLat = parseFloat(ZipLL[0]);
MapCenterLong = parseFloat(ZipLL[1]);
ZoomFactor = 11;
}
var mapOptions = {
credentials: ' ',
center: new Microsoft.Maps.Location(MapCenterLat, MapCenterLong),
mapTypeId: Microsoft.Maps.MapTypeId.Automatic,
zoom: ZoomFactor,
showScalebar: true
}
map = new Microsoft.Maps.Map('#myMap', mapOptions);
var arrPins = [];
var arrPinCenter = [];
//Generating Pins for multiple locations with Lat,Long
for (var locNum = 0; locNum <= arrLocInfoRec.length - 1; locNum++) {
try {
arrLLAdder = arrLocInfoRec[locNum].split("`");
if (arrLLAdder.length >= 13) {
//var latlong = arrLLAdder[11].split(',');
arrPinCenter[locNum] = new Microsoft.Maps.Location(parseFloat(arrLLAdder[11]), parseFloat(arrLLAdder[12]));
arrPins[locNum] = new Microsoft.Maps.Pushpin(arrPinCenter[locNum], {
text: arrLLAdder[8] ,
icon: 'https://www.bingmapsportal.com/Content/images/poi_custom.png',
anchor: new Microsoft.Maps.Point(12, 39)
});
var adder = arrLLAdder[2] + '\r\n' + arrLLAdder[4] + '\r\n' + arrLLAdder[6] + arrLLAdder[9] + "\r\n" + arrLLAdder[1]
// Create the infobox for the pushpin
//Ricky: Add your infobox as a reference in your pushpin
arrPins[locNum]. metadata = new Microsoft.Maps.Infobox(arrPins[locNum].getLocation(),
{ width: 350,
height: 100,
title: arrLLAdder[5],
description: adder,
offset: new Microsoft.Maps.Point(-3,13),
visible: false
});
// Add handler for the pushpin click event.
Microsoft.Maps.Events.addHandler(arrPins[locNum], 'click', displayInfobox);
}
else {
console.log("Invalid Data: arrLocInfoRec[" + locNum + "] = \"" + arrLocInfoRec[locNum] + "\"");
}
} catch (e) {
console.log(e.message + "\r\n" + arrLocInfoRec[locNum]);
}
}
// Add the Push Pins and InfoBox to the map all at once
//Ricky: Moved this out of the array as you only need to add array of pushpins to the map once.
if(arrPins.length > 0) {
map.entities.push(arrPins); //[locNum]
}
}
function displayInfobox(e) {
//map.entities.push(arrPinInfobox);
console.log("DisplayBox");
//Get infobox from the pushpin, rather than looping through array.
var infobox = e.target.metadata;
infobox.setOptions({ visible: true });
//for(var i in arrPinInfobox){
//arrPinInfobox[i].setOptions({ visible: true });
//arrPinInfobox[parseInt(e.target.getText()) - 1].setOptions({ visible: true });
//var infobox = arrPinInfobox[i];
//infobox.setMap(map);
//}
}
If you want to clean up your code some more I recommend:
get rid of all the array's, there is no need for them.
Use a layer for your pushpins. Add a single click event on the layer rather than on each individual pushpin.