I am using Leaflet library and stuck with following issue:
To generate Map i am calling map function on button click.
So on each generatemap function call, I want to clear pregenerated markers.
function generatefilterrecord(orgid,defservice,defavail,defowner,defhealthfacility) {
$("#content1").hide();
$("#map1").show();
$("#mapA1").hide();
$("#footer").hide();
jQuery('#sel').html('');
$(".w3-card-4").remove();
var addressjoin=[],ouid=[],availspecialitiesjoin,availspecialities=[],avaialabilityjoin,name=[],address=[],pincode=[],village=[],mobile=[],special=[],notspecial=[],hfacilities=[],nothfacilities=[],schemes=[],notschemes=[],contactpname=[],contactpnumber=[];
var toAdd,spec=[],email=[],specialjoin,notspecialjoin,notspec=[],owner=[],notowner=[],hfacilitiesjoin,nothfacilitiesjoin,schemesjoin,notschemesjoin,hfschemes=[],nothfschemes=[];
var healthfac="",ownership=[],availspecialiti=[];
var arrayMap = [];latitude=[];longitude=[];
$.getJSON("../../api/analytics/events/query/tzR46QRZ6FJ.json?stage=o6ps51YxGNb&dimension=pe:THIS_YEAR&dimension=ou:"+orgid+"&dimension=l8VDWUvIHmv&dimension=KOhqEw0UKxA&dimension=xjJR4dTmn4p&dimension=wcmHow1kcBi&dimension=pqVIj8NyTXb&dimension=g7vyRbNim1K&dimension=Gx4VSNet1dC&dimension=bUg8a8bAvJs&dimension="+defservice+"&dimension="+defavail+"&dimension="+defowner+"&dimension="+defhealthfacility+"&dimension=ZUbPsfW6y0C&dimension=CAOM6riDtfU&dimension=YL7OJoQCAmF&dimension=vJO1Jac84Ar&dimension=kF8ZJYe9SJZ&dimension=tNhLX6c7KHp&dimension=bVENUe0eDsO&displayProperty=NAME", function (data) {
console.log("../../api/analytics/events/query/tzR46QRZ6FJ.json?stage=o6ps51YxGNb&dimension=pe:THIS_YEAR&dimension=ou:"+orgid+"&dimension=l8VDWUvIHmv&dimension=KOhqEw0UKxA&dimension=xjJR4dTmn4p&dimension=wcmHow1kcBi&dimension=pqVIj8NyTXb&dimension=g7vyRbNim1K&dimension=Gx4VSNet1dC&dimension=bUg8a8bAvJs&dimension="+defservice+"&dimension="+defowner+"&dimension="+defhealthfacility+"&dimension=jXCd8k2841l&dimension=RkP5neDLbHv&dimension=avHST8wLPnX&dimension=txl9e6UJFP4&dimension=ZUbPsfW6y0C&dimension=CAOM6riDtfU&dimension=YL7OJoQCAmF&dimension=vJO1Jac84Ar&dimension=kF8ZJYe9SJZ&dimension=tNhLX6c7KHp&dimension=bVENUe0eDsO&displayProperty=NAME");
var constants={key:name, value: value}
analyticsMap = calculateIndex(data.headers,analyticsMap);
if(data.rows.length==0)
{
alert("No result found for above selection");
}
for(var k=0;k<data.rows.length;k++){
arrayMap["special"] = special;
arrayMap["name"] = name;
arrayMap["address"] = addressjoin;
arrayMap["pincode"] = pincode;
arrayMap["village"] = village;
arrayMap["mobile"] = mobile;
arrayMap["notspecial"] = notspecial;
arrayMap["hfacilities"] = hfacilities;
arrayMap["nothfacilities"] = nothfacilities;
arrayMap["schemes"] = schemes;
arrayMap["notschemes"] = notschemes;
arrayMap["contactpname"] = contactpname;
arrayMap["contactpnumber"] = contactpnumber;
arrayMap["availspecialities"] = availspecialities;
arrayMap["ownership"] = ownership;
arrayMap["ouid"] = ouid;
for (var j=0;j<analyticsMap.length;j++){
if (analyticsMap[j].index > 0){
var value = data.rows[k][analyticsMap[j].index];
if (value == "1"){
value = data.headers[analyticsMap[j].index].column;
}
if (!value || value == "0"){
value = "";
}
if(arrayMap[analyticsMap[j].arrayName]){
arrayMap[analyticsMap[j].arrayName].push(value);
}
}
}
specialjoin = myJoin(special);
availspecialitiesjoin = myJoin(availspecialities);
notspecialjoin = myJoin(notspecial);
hfacilitiesjoin = myJoin(hfacilities);
nothfacilitiesjoin = myJoin(nothfacilities);
schemesjoin = myJoin(schemes);
notschemesjoin = myJoin(notschemes);
spec.push(specialjoin);
notspec.push(notspecialjoin);
owner.push(hfacilitiesjoin);
availspecialiti.push(availspecialitiesjoin);
notowner.push(nothfacilitiesjoin);
hfschemes.push(schemesjoin);
nothfschemes.push(notschemesjoin);
availspecialities=[];
special = [];
notspecial = [];
hfacilities = [];
nothfacilities = [];
schemes = [];
notschemes = [];
}
var header = {
"Authorization": "Basic " + btoa( "homepage" + ':' + "Homepage123#123" )
};
for (var i = 0; i < name.length; i++) {
$.ajax({
async: false,
type: "GET",
dataType: "json",
contentType: "application/json",
header: header,
url: '../../api/organisationUnits/' + ouid[i] + '.json?fields=[id,name,coordinates]',
success: function (response) {
var coordinates = JSON.parse(response.coordinates);
latitude.push(coordinates[0]);
longitude.push(coordinates[1]);
},
error: function (response) {
}
});
}
for (var i = 0; i < name.length; i++) {
if(ownership[i]=="Public")
{
L.marker([longitude[i], latitude[i]], {icon: blueMarker}).addTo(map1).bindPopup(name[i]+","+"</br><strong>Contact:</strong> "+ mobile[i]+ ",</br> <strong>Schemes:</strong>"+hfschemes[i]+", </br><strong>Availabilities:</strong> "+availspecialiti[i]).openPopup();
}
else if(ownership[i]=="Private")
{
L.marker([longitude[i], latitude[i]], {icon: redMarker}).addTo(map1).bindPopup(name[i]).openPopup();
}
}
});
}
Here map never generates but if i remove marker.clearLayers(); then it is coming fine but problem is it appends every result so I want to clear the last generated markers.
Instead of adding the markers directly to your map, add them to a L.LayerGroup
Whenever you want, you can remove your markers calling the clearLayers method
var layerGroup = L.layerGroup().addTo(map);
// create markers
L.marker().addTo(layerGroup);
// remove all the markers in one go
layerGroup.clearLayers();
You can use this
$(".leaflet-marker-icon").remove();
$(".leaflet-popup").remove();
All simple:
map.eachLayer((layer) => {
layer.remove();
});
from https://leafletjs.com/reference-1.0.3.html#map-event
as the code provided by psyopus removes every layer (base maps, markers..etc); I needed just to remove the markers, the marker layer object has key of'_latlng'. Thus, I check if the object has it, so remove it:
map.eachLayer((layer) => {
if(layer['_latlng']!=undefined)
layer.remove();
});
Disclaimer: I dont know if there are other layer objects with this parameter key.
Related
I have a Flask python application where the user can select a vehicle in the web page and depending on which vehicle is selected, the application should propose different WMS layers in the Leaflet layer control that the user can tick on / off depending of his needs. The logic of feeding new layers depending of vehicle selection is done via ajax, where the layers vs vehicle is fetched from a database.
This works fine the first time the vehicle is selected, however, when a different vehicle is selected and then the first vehicle again, the WMS layer does not show in the leaflet map, though the layer name can be selected in the layer control. To avoid having too many checkboxes the vessels has been added to the same marker group so the user only have the vessel group and a couple WMS layers to tick on/off.
I'm sure the solution is dead simple. However have been exhausing 'every' tip I could find on different forums.
JavaScript:
var vesselVar = null;
var mapVessel = null;
var layerControl = null;
var baseMaps = null;
var overlayMaps = null;
var layerNameArr = null;
var layerLinkArr = null;
var baseMapArr = null;
var myVessels = null;
var sLayerName = null;
var sUrl = null;
var wmsOptions = null;
var myWmsLayer = null;
function myOnSelectedVessel() {
let sSelectedVessel = $('#sSelectedVessel').find(":selected").text()
if (sSelectedVessel.length > 0) {
$.ajax({
url: '/vessel_map_set_vessel_id',
data: {
'sSelectedVesselName': sSelectedVessel,
},
type: 'POST',
dataType: 'json',
success: function (response) {
if (response.result) {
alert(response.msg);
}
myCreateOverlay(response.liVessels, response.liLastVesselPos, response.arrLeaflet.toString());
myCreateBaseLayers();
myCreateMap(response.lat, response.lon);
mapVessel.panTo(new L.LatLng(parseFloat(response.lat), parseFloat(response.lon)));
},
error: function (error) {
alert("error in function vessel_map.myOnSelectedVessel");
}
});
}
}
function myCreateVesselGroup(liVessels, liLastVesselPos) {
try {
myVessels = null;
vesselVar = null;
myVessels = L.layerGroup([]);
vesselVar = [];
let iLen = liLastVesselPos.length;
const arrVesselNames = liVessels.toString().split(',');
const arrVesselPos = liLastVesselPos.toString().split(',');
let iCntVesselPos = 0;
for (let iCn7 = 0; iCn7 < iLen; iCn7++) {
arrPos = liLastVesselPos[iCn7];
//alert(arrVesselNames[iCn7]);
myAddVesselMarker(arrVesselNames[iCn7], arrVesselPos[iCntVesselPos], arrVesselPos[iCntVesselPos + 1]);
myVessels.addLayer(vesselVar[iCn7]);
iCntVesselPos += 2;
}
}
catch (err) {
alert("Error in function myCreateBaseLayers: " + err.message);
}
}
function myCreateOverlay(liVessels, liLastVesselPos, sLeafletWmsString) {
try {
if (mapVessel !== null) {
if ((overlayMaps !== null) && (layerControl !== null)) {
mapVessel.eachLayer(function (layer) {
mapVessel.removeLayer(layer);
});
}
}
overlayMaps = null;
overlayMaps = {};
myCreateVesselGroup(liVessels, liLastVesselPos)
overlayMaps['Vessels'] = myVessels;
if (sLeafletWmsString.length > 1) {
const arrLeaflet2 = sLeafletWmsString.split(',')
let iLen = arrLeaflet2.length;
for (let iCnt4 = 0; iCnt4 < iLen; iCnt4 += 2) {
sLayerName = null;
sLayerName = arrLeaflet2[iCnt4].toString();
wmsOptions = null;
wmsOptions = {};
wmsOptions.layers = sLayerName;
wmsOptions.format = 'image/png';
wmsOptions.transparent = true;
wmsOptions.opacity = 0.5;
sUrl = null;
sUrl = arrLeaflet2[iCnt4 + 1];
myWmsLayer = null
myWmsLayer = new L.tileLayer.wms(sUrl, wmsOptions);
overlayMaps[sLayerName] = myWmsLayer;
}
}
}
catch (err) {
alert("Error in function myCreateOverlay: " + err.message);
}
}
function myCreateBaseLayers() {
try {
layerNameArr = null;
layerLinkArr = null;
baseMaps = null;
layerNameArr = [];
layerLinkArr = [];
baseMaps = []
layerNameArr.push('OpenStreetMap');
layerLinkArr.push(L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: 'OpenStreetMap', transparent: true }));
for (iCn2 = 0; iCn2 < layerLinkArr.length; iCn2++) {
baseMaps[layerNameArr[iCn2]] = layerLinkArr[iCn2];
}
}
catch (err) {
alert("Error in function myCreateBaseLayers: " + err.message);
}
}
function myAddVesselMarker(sTitle, dLat, dLon) {
try {
var markerOptions = {};
markerOptions.title = sTitle;
markerOptions.clickable = true;
markerOptions.draggable = false;
var sPopupText = "Lat: " + dLat.toString() + ", Lon: " + dLon.toString();
vesselVar.push(L.marker([dLat, dLon], markerOptions).bindPopup(sPopupText));
}
catch (err) {
alert("Error in function myAddVesselMarker: " + err.message);
}
}
function myCreateMap(dLatCenter, dLonCenter) {
try {
if (mapVessel !== null) {
mapVessel.invalidateSize();
mapVessel.off();
mapVessel.remove();
}
mapVessel = null;
layerControl = null;
mapVessel = new L.map('map', { center: [dLatCenter, dLonCenter], zoom: 13, layers: [layerLinkArr[0]] });
layerControl = new L.control.layers(baseMaps, overlayMaps).addTo(mapVessel);
}
catch (err) {
alert("Error in function myCreateMap: " + err.message);
}
}
For anybody else that struggles with the same issue. My problem was that the '&' character in the url string is a javascript entity character that is interpreted as javascript code (even though the url string was a varaiable and not in the JS code itself). For the first on load draw I used Flask's Jinja2, which automatically modified all the '&' characters in the url string, hence why the first time draw showed up ok. Once I replaced all the '&' characters in the ajax string, that I sent back to javascript when the user changed a vehicle, with '&', the overlay showed up also when I changed the vehicle.
I am developing an web app in which the user will be able to identify the location from map by clicking on the map (I use jquery 3.1). The problem is that I have to make some ajax calls, one depend on other, and on the last call the result it's not returned as a whole (full array) and I received only a part of array.
The problem survives from var a4.
How I can make that a4 result to be send as a full array because I tried with deferred but with no expecting result?
var getLocDetails = function () {
// Parse a web api based on user lat & lon
var a1 = $.ajax({
method: 'GET',
url: 'http://nominatim.openstreetmap.org/reverse?lat=44.43588&lon=26.04745&accept-language=ro&format=json'
});
// Get osm_type & osm_id and parse another web service to get a XML document (Ex.: https://www.openstreetmap.org/api/0.6/way/28240583)
var a2 = a1.then(function (data) {
return $.ajax({
method: 'GET',
url: 'https://www.openstreetmap.org/api/0.6/' + data.osm_type + '/' + data.osm_id
})
});
// Get all 'ref' attribute from every 'nd' node from XML and make an array with this values
var a3 = a2.then(function (data) {
var osmChildren = data.documentElement.childNodes;
var out = [];
for (var i = 0; i < osmChildren.length; i++) {
if (osmChildren[i].nodeName == 'way') {
var wayChildren = osmChildren[i].childNodes;
for (var j = 0; j < wayChildren.length; j++) {
if (wayChildren[j].nodeName == 'nd') {
var ndRef = Number.parseInt(wayChildren[j].getAttribute('ref'));
out.push(ndRef);
}
}
}
}
return out;
});
// HERE IS THE PROBLEM
// Based on array returned from a3, I am parsing every link like 'https://www.openstreetmap.org/api/0.6/node/ + nodeRef' to extract every lat and lon values for extreme points
var a4 = a3.then(function (data) {
var defer = $.Deferred();
var out = [];
for (var i = 0; i < data.length; i++) {
var nodeRef = data[i];
var nodeUrl = 'https://www.openstreetmap.org/api/0.6/node/' + nodeRef;
$.ajax({
method: 'GET',
url: nodeUrl
}).done(function (response) {
var node = response.documentElement.firstElementChild;
var lat = Number.parseFloat(node.getAttribute('lat'));
var lng = Number.parseFloat(node.getAttribute('lon'));
out.push([lat, lng]);
defer.resolve(out);
});
}
return defer.promise();
});
// When a4 is done, based his result, I have to have an array of lat & lon coordonates, but I recived only 1-2 coordonates even I have 10.
a4.done(function (data) {
console.log(data);
// Here I have to draw a polygon
});
}
you need to handle the requests in an array, as what you are doing tends to resolve the callback for a4 before all are complete.
To do this we can use $.when function
var req = [];
// Based on array returned from a3, I am parsing every link like 'https://www.openstreetmap.org/api/0.6/node/ + nodeRef' to extract every lat and lon values for extreme points
var a4 = a3.then(function (data) {
var defer = $.Deferred();
var out = [];
for (var i = 0; i < data.length; i++) {
var nodeRef = data[i];
var nodeUrl = 'https://www.openstreetmap.org/api/0.6/node/' + nodeRef;
req.push(
$.ajax({
method: 'GET',
url: nodeUrl
}).done(function (response) {
var node = response.documentElement.firstElementChild;
var lat = Number.parseFloat(node.getAttribute('lat'));
var lng = Number.parseFloat(node.getAttribute('lon'));
out.push([lat, lng]);
})
);
}
$.when.apply($, req).done(function(){
return defer.resolve(out);
});
return defer.promise();
});
I have a search form to call a Solr index, filled with geolocations:
jQuery('.form-submit', element).click(function (e) {
e.preventDefault();
search();
});
function search() {
useBBOX = false;
combinedExtent = ol.extent.createEmpty();
data.map.getLayers().forEach(function (layer, index, array) {
if (layer.getSource() instanceof ol.source.Vector) {
var source = layer.getSource().getSource();
var url = data.opt.urls[source.get('machineName')];
var newSource = new ol.source.Vector({
loader: getLoader(data, url),
format: new ol.format.GeoJSON(),
strategy: ol.loadingstrategy.bbox,
reloadOnZoomChange: true,
reloadOnExtentChange: true
});
newSource.set('machineName', source.get('machineName'));
var newCluster = new ol.source.Cluster({
source: newSource,
distance: 200
});
layer.setSource(newCluster);
}
});
}
function getLoader(data, url) {
return function (extent, resolution, projection) {
var bbox = ol.proj.transformExtent(extent, data.map.getView().getProjection(), 'EPSG:4326');
var params = {};
if (data.opt.paramForwarding) {
var get_params = location.search.substring(location.search.indexOf('?') + 1).split('&');
jQuery.each(get_params, function (i, val) {
if (val.length) {
var param = val.split('=');
params[decodeURIComponent(param[0])] = (param[1] !== undefined) ? decodeURIComponent(param[1].replace(/\+/g, ' ')) : '';
}
})
}
if (useBBOX == true) {
params.bbox = bbox.join(',');
params.zoom = data.map.getView().getZoom();
}
var searchQuery = jQuery('#input-search-address').val();
if (searchQuery != 'undefined' && searchQuery != null) {
url = url.substr(0, url.lastIndexOf("/") + 1);
url = url + searchQuery;
}
jQuery(document).trigger('openlayers.bbox_pre_loading', [{
'url': url,
'params': params,
'data': data
}]);
var that = this;
jQuery.ajax({
url: url,
data: params,
success: function (responsdata) {
var features = that.getFeaturesInExtent(extent);
jQuery(features).each(function (i, f) {
that.removeFeature(f);
});
var format = new ol.format.GeoJSON();
var features = format.readFeatures(responsdata, {featureProjection: projection});
that.addFeatures(features);
that._loadingFeatures = false;
if (!ol.extent.isEmpty(that.getExtent())) {
combinedExtent = ol.extent.extend(combinedExtent, that.getExtent());
if (useBBOX == false) {
useBBOX = true;
}
}
}
});
};
}
Basically, it fetches 3 layers, each containing a number of markers. I'ld like to autozoom the map based on those markers. Therefore I'm looking for the extent. The combinedExtent does contain all correct extents...
... but when I add data.map.getView().fit(combinedExtent, data.map.getSize()) INSIDE the getLoader function, it's not working. I looks like only 1 extent get plotted on the map.
Whenever I try to log the combinedExtent in the search() function, I get a weird error...
Google told me I had to wait until the getState() of newSource was ready, but that didn't work out...
So, I'm looking for a solution. My guess would be the use of the ajax return in getLoader...
I just had this issue, so I have a function to listen until the source is ready and finished loading before giving a count of features (otherwise it would update the log with every iteration). Just change my source name (any variable with "parcelquery in it) with yours and hopefully it will at least put you in the right direction.
var listenerKey = wfsSource_parcelquery.on('change', function(e) {
if (wfsSource_parcelquery.getState() == 'ready') { //says source is done loading
var featureCount = wfsSource_parcelquery.getFeatures().length; //getting number of features resulting from query
ol.Observable.unByKey(listenerKey);
// use vectorSource.unByKey(listenerKey) instead
// if you do use the "master" branch of ol3
}
alert("Your query returned "+ featureCount + " results.");
var extent = lyr_parcelquery.getSource().getExtent();
console.log(extent);
map.getView().fit(extent, map.getSize());
});
i was tested to the IdentyfyTask.
But I could not get a response before the value addCallback.
i want to the pnu values.
But pnu vaule was alwayes undefined...
my code is follows.
function poiClick(){
agmap.addEvent("click", function(evt){
getPoi= krcgis.Function.PoiClick(agmap ,evt);
console.log("X === ",getPoi.x);
console.log("Y === ",getPoi.y);
console.log("PNU === ",getPoi.pnu);
});
}
PoiClick : function(map, evt) {
poiInfo = {};
poiInfo.x =evt.mapPoint.x;
poiInfo.y =evt.mapPoint.y;
var targetLayerId = 'LP_PA_CBND';
var url = map.Layers.getLayerInfo(targetLayerId).SVC_URL;
var map = map.getMap();
//파라미터 설정.
var idParams = new krcgis.core.tasks.IdentifyParameters();
idParams.geometry = evt.mapPoint;
idParams.mapExtent = map.extent;
idParams.returnGeometry = true;
idParams.tolerance = 0;
idParams.layerOption = krcgis.core.tasks.IdentifyParameters.LAYER_OPTION_ALL;
idParams.width = map.width;
idParams.height = map.height;
idTask = new krcgis.core.tasks.IdentyfyTask(url);
idTask
.execute(idParams)
.addCallback(function (response) {
if (response) {
poiInfo.pnu =response[0].value;
}
});
return poiInfo;
}
The results were as follows.
IdentifyTask returns a IdentifyResult object. so you code response[0].value will be undefined.
you should use something like response[0].feature.attributes.PNU
//an ajax call to the api
jQuery(document).ready(function() {
jQuery.ajax({
url:"http://localhost:8080/activitiesWithRealData?location=%22SEA%22&startDate=%2205-14-16%22&endDate=%2205-16-16%22&theme=%22food%22",
dataType: 'JSON', type: 'GET',
success: function (data)
var viewModel;
if(data) {
viewModel = new dealsPageModel(data);
var idList = "";
for (var i = 0; i< data.packageDeal.length; i++)
{
if (i == data.packageDeal.length -1)
{ idList += data.packageDeal[i].hotelId;
}
else
{idList += data.packageDeal[i].hotelId + ',';
}
}
var searchUrl = "http://terminal2.expedia.com/x/hotels?hotelids=" + idList + "&apikey=6weV4ksGIJ5eQhd58o2XTDwVo35lZf2S";
//another call to another api to return hotel specific info
jQuery.get(searchUrl, function ( )
{
for(var i=0; i<viewModel.dealList.length; i++)
{
var hotelId = viewModel.dealList[i].hotelId;
for(var i=0; i<data.HotelInfoList.HotelInfo.length; i++)
{
var url = HotelInfoList.HotelInfo[i].ThumbnailUrl;
var name = HotelInfoList.HotelInfo[i].Name;
}
// Get the hotelid from the current deal
// Loop through the hotelinfolist.hotelInfo and find out the url for the hotel idList
//Loop through the hotelinfolist.hotelInfo and find out the name for the hotel
viewModel.dealList.push(new deal(data.packageDeal[i], url, name));
}
ko.applyBindings(viewModel);
});
}
}
})
});
You loop through data.HotelInfoList.HotelInfo but operate on HotelInfoList.HotelInfo[i].ThumbnailUrl. The data. at the beginning is missing.
Also, place data in the callback function in jQuery.get:
jQuery.get(searchUrl, function(data){
// …
your data is in data.HotelInfoList not in HotelInfoList
your loop should be like this
for(var i=0; i<data.HotelInfoList.HotelInfo.length; i++)
{
var url = data.HotelInfoList.HotelInfo[i].ThumbnailUrl;
var name = data.HotelInfoList.HotelInfo[i].Name;
}