1

As many of you know I have been producing a Leaflet map with a KNN function to show the closest pubs to a user's location.

Live example to test for yourself: https://ces-web2.southwales.ac.uk/students/18018815/mitchtut/giscw3/Geoserv2.php

The system itself works on mine and various others PC's within Chrome, however, I when opened within other browsers it is a bit more finicky and requires either a cache refresh to work or it doesn't successfully preform the KNN function. Below shows the working script on my PC showing the closest pubs. This also works with other locations through Chrome's dev tools too.

Working KNN on Chrome PC

Using remote target devices in Chrome, I had a look at the browser logs within my mobile device and received the error:

pg_query(): Query failed: ERROR:  parse error - invalid geometry HINT:
"point()" <-- parse error at position 8

This suggests that the script or function cannot parse the data being return from the script.

The Chrome logs show that the device's location is being received and passed to the script but the data/points are not being returned.

Mobile Phone Dev tools showing successful location grab

The same issue can be seen within Microsoft Edge too, again location is being grabbed from the device but the KNN showing Blue Markers (closest pubs) does not show. Edge Console showing similar issue with successful coord grab

Is there any reason this error is occurring as I know the code itself works and as achieved from previous answers the race problem issue was fixed.

I have successful screenshots of colleagues and friends devices showing successful KNN execution, even within different browsers such as Edge and Safari, but on some devices this issue seems to persist.

My original thought process was that this could be something to be the decimal positions within the lat and long being too large to parse, however, the same coordinates spoofed into Chrome work. And this would not be an issue for more general Lat and Longs from IP address based locations as these are less accurate.

The current code for the script is:

//Map instantiation and layer calls
pub_map = L.map('mapspce');
pub_map.setView([54.00, -2.54],5.5);
pub_map.addLayer(basetiles);

//User location
var Position, Accuracy,test = null;
function onLocationFound(e) {
    if(Position){
        pub_map.removeLayer(Position);
        pub_map.removeLayer(Accuracy);
    }
test = e.latlng;
console.log("user lat long in script is: " + test);
lon = test.lng;
lat = test.lat;
lat = lat.toString();
lon = lon.toString();
kLOC = lon + " " + lat;
console.log("lon lat " + kLOC);
var radius = e.accuracy / 2;
//pop up stating the users position
Position = L.marker(e.latlng).addTo(pub_map).bindPopup("<h4>You are here</h4><p>You are  within " + radius + " metres from here</p>").openPopup();
Accuracy = L.circle(e.latlng, radius).addTo(pub_map);

/* var lat, lon;
lat = parseFloat(Position.coords.latitude);
lon = parseFloat(Position.coords.longitude);

console.log("user lat is: " +lat);
console.log("user lat is: "+lon); */
//return lon;
//return lat;
return test;
}

//error message if user location cannot be found
 function onLocationError(e) {
    alert(e.message);
}
//display the layers to the map
pub_map.on('locationfound', onLocationFound);
pub_map.on('locationerror', onLocationError);

//locate function
pub_map.locate({setView: true, maxZoom:16});



//knn feature

var kTable = 'geoupload.pubs';
var kColumn =["id", "p_name", "address1", "postcode", "local_authority"];
var kGeom = "geom";
var kLOC;
//"51.59977 -3.325952";
//"307998 189349";

//var klocy = "User location is " + test;

//passing variable to the console to show values are being picked up 
// console.log(kLOC);
// console.log("user lat long is: " + test);
// console.log("user lat is: " + lat);
// console.log("user lon is: " + lon);

$(document).ready(function(){
    $.ajax({
        url: "knn.php",
        data:{ktable: kTable, kinclu: kColumn, kgeomy: kGeom, Loc: kLOC}
    })
    .done(function(data){
        knnPubsLay = L.geoJSON(JSON.parse(data),{
            pointToLayer: function (feature, latlng){
                return L.circleMarker(latlng,nearStyle);
        }});
        console.log("after " + kLOC);
        pub_map.addLayer(knnPubsLay);
        knnPubsLay.bringToFront();
    })
});

With the PHP script calling the KNN function being:

//call tables for knn query although same as the previous I have changed the variable names to keep them seperate
    $ktable = $_GET['ktable'];
    $kinclu = $_GET['kinclu'];
    $kgeomy = $_GET['kgeomy'];
    $Loc = $_GET['Loc'];
    
//substitutes
$fields = "";
    foreach ($kinclu as $i => $col) {
        $fields = $fields . $col . ", ";
    }
    $fields = $fields . $kgeomy;
    $geom = " - " . $kgeomy;


//knn query
$knn1 =
    "SELECT jsonb_build_object(
            'type',     'FeatureCollection',
            'features', jsonb_agg(feature))
    FROM (
        SELECT jsonb_build_object(
            'type',       'Feature',
            'geometry',   ST_AsGeoJSON(st_transform(geom,4326),4)::jsonb,
            'properties', to_jsonb(row) #omits#
        ) AS feature
        FROM (SELECT #fields# FROM #table# as K, st_transform(st_geomfromtext('point(#location#)',4326),27700) ORDER BY st_distance(K.geom, st_transform(st_geomfromtext('point(#location#)',4326),27700)) LIMIT 5) row) features;";

//27700
//4326
//geomfromtext
//pointfromtext


    //replace placeholders
    $knn2 = str_replace("#table#", $ktable, $knn1);
    $knn3 = str_replace("#fields#", $fields, $knn2);
    $knn4 = str_replace("#location#", $Loc, $knn3);
    $knn5 = str_replace("#omits#", $geom, $knn4);
    ChromePhp::log($knn5);

//execute query
if (!$response = pg_query($conn, $knn5)) {
    ChromePhp::error("*KNN script failed*");
    exit;
}
    
//return data
while ($row = pg_fetch_row($response)) {
    foreach ($row as $i => $attr){
        echo $attr;
    }
}

1 Answer 1

1

You have a race condition problem here, and that's the reason why on some browsers/environments it works and on some doesn't.

You have $(document).ready(function() ... function which is called when document is loaded. Within it you call $.ajax( ..., which uses variable kLOC as one of the input parameters for call. But this kLOC variable is filled with valid value only after async locationfound event is processed with onLocationFound function.

Obviously on some browsers/environments event locationfound is processed early enough so that kLOC has valid data at the time of document load, and on some browsers/environments this happens later, which of course causes an error in your $.ajax( ... call.

Solution is to fire your AJAX call only after the first locationfound event.

1
  • Perfect It seems to work on those affected browsers and devices now.
    – WMTS
    Apr 7, 2021 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.