-
Notifications
You must be signed in to change notification settings - Fork 911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed displacing points specified from context menu #4904
Fixed displacing points specified from context menu #4904
Conversation
How does it "address" that issue? What is the change you are making to address it? |
77a8796
to
7afb4ce
Compare
Dear @tomhughes , Thank you for your review and comment. I updated PR and commit messages. Please, let me know if I can improve it further. Thanks, |
Doesn't it still do unnecessary geocoding for the first point? And then its marker may get shifted as a result of this geocoding. What an endpoint should do is to detect that it has coordinates as a value and don't try to query nominatim if it does. Search has server-side regexps to detect coordinates:
Here something simpler might suffice like number, number format without all those degree signs, N/S/E/W letters etc. |
related #1754 |
7afb4ce
to
b0b3ecd
Compare
Dear @AntonKhorev , I've just updated PR with the latest, simplified and corrected sources. I made short video displaying new functionality (I added debugging alert("GEOCODING") call to directions.js just before $.getJSON(OSM.NOMINATIM_URL .. line to catch geocoding requests). Screen.Recording.2024-07-02.144007.mp4Now, geocoding is called only once when user selects "Directions from here" or "Directions to there" or when new address is selected. Another way is to call geocoding only when address is typed, but, then, address will be lost when context menu options are selected (like when dragging markers, i.e. in From / To fields will be drawn Lat / Lng only). Please, let me know which one option is ideal or if it could be further improved? Thanks, |
var precision = OSM.zoomPrecision(map.getZoom()); | ||
input.val(ll.lat.toFixed(precision) + ", " + ll.lng.toFixed(precision)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was used by $("#map").on("drop" ...
to populate an input when the marker next to the input is dragged and dropped on the map.
What happens now:
Screencast from 04.07.2024 06:35:02.webm
What used to happen:
Screencast from 04.07.2024 06:38:26.webm
b0b3ecd
to
8aa3ff8
Compare
Dear @AntonKhorev , Good catch, thank you very much! I've just fixed it and now it works fine! Please, let me know if I could further improve it. Thanks, |
Going to Nominatim with coordinates still happens. Try entering "0,0" into from/to inputs. Before the changes the code always went to Nominatim and searched for these numbers, found them somewhere in Taiwan (or elsewhere depending on the current map view) and placed the marker there. After the changes the same happens except the marker is at 0, 0. We should
|
8aa3ff8
to
afc0f21
Compare
Dear @AntonKhorev , Thanks for reviewing and comments. Now, we are contacting nominatim only if: point is defined using context menu (right click + Directions from/to here) or something is entered that doesn't look like coordinates (Number "," or "/" Number). Also, we improved focusing of map view, so it focuses on union of markers and path (if exists), previously it focused only on path. Please, let me know if we could further improve it. Thanks, |
Another bug:
simplescreenrecorder-2024-07-18_17.44.10.mp4 |
98acb86
to
eb504ae
Compare
Dear @AntonKhorev , Thank you for catching this! I've just fixed it. Please, let me know if I could further improve it. Thanks, |
5b2e432
to
6489d0e
Compare
}); | ||
|
||
endpoint.setValue = function (value, latlng) { | ||
endpoint.setValue = function (value, force_reverse_geocoding, latlng) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is force_reverse_geocoding
? Is there any code here that actually does reverse geocoding?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is. Reverse geocoding is done when user right-clicks on map and selects "Directions from here" or "Directions to here".
Variable force_reverse_geocoding is introduced to pass information that user did this (right clicked and selected from context menu) and to perform reverse geocoding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no forcing of reverse geocoding. There's no code calling reverse
like here. Nominatim will usually do reverse geocoding when "Directions from/to here" are selected, but that's because it decides on its own that the input query looks like coordinates. It won't make this decision correctly every time.
simplescreenrecorder-2024-07-22_01.46.00.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this! I've just updated with adding code for calling "reverse" like in above link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this! I've just updated with adding code for calling "reverse" like in above link.
We have just gotten another idea how to improve this part. I'll make another push soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AntonKhorev I've just pushed the latest fixes.
We improved logic of what is displayed in input boxes after right-clicking and selecting option from context menu. Now, if nominatim doesn't return anything or it returns something that is more than 200m away from clicked position, we will display coordinates (Number, Number), otherwise we will display what nominatim returned. The logic behind is "in input boxes should be displayed user-friendly text iff user entered it manually or user clicked on / or near the object recognized by nominatim, otherwise, coordinates will be displayed".
For calculating distance between position where user clicked and position of what nominatim returned, we used distanceTo method provided by Leaflet's LatLng which reduces it to calculating distance on great circle. After testing on Longyearbyen and Longyearbyen, it seems this approximation works fine.
Please, let me know if we can further improve it.
Thanks,
Nenad.
@@ -402,8 +440,10 @@ OSM.Directions = function (map) { | |||
} | |||
} | |||
|
|||
endpoints[0].setValue(params.from || "", from); | |||
endpoints[1].setValue(params.to || "", to); | |||
var ll_from_search_form = decodeURIComponent(location.search).match(/^\?from=([+-]?\d+(\.\d*)?)(?:\s+|\s*[/,]\s*)([+-]?\d+(\.\d*)?)$/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this regexp ever match anything?
"Directions from here" generate location.search
like ?from=52.54124,13.56290&to=
which doesn't match. Do you want it to match?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it does. It captures the situation when user inputs some coordinates into search field and then pushes "Find directions between two points" button. Earlier, this performed reverse geocoding, now it doesn't do it anymore.
Our idea behind the current solution is "if user enters the coordinates or drags markers, leave the coordinates. If user right-clicks and selects from context menu, perform reverse geocoding".
6489d0e
to
139d6c4
Compare
139d6c4
to
4394f80
Compare
When user tries to add a marker out of the borders of countries, alert is thrown "Sorry - couldn't locate", but marker is still added and if user drags it to the valid position, route is not updated (see Video 1). Video 1: OpenStreetMap.and.45.more.pages.-.Work.-.Microsoft.Edge.2024-08-06.13-37-54.mp4Contrary to this, if user adds marker in the valid location and then drags it out of the borders, route is still calculated and shown without any alerts (see Video 2). Video 2: OpenStreetMap.and.45.more.pages.-.Work.-.Microsoft.Edge.2024-08-06.13-38-13.mp4Maybe, in the first case, we should still show coordinates and calculate route even though Nominatim location was not found (as it is done in the second case). |
The same logic is with "Couldn't find a route between those two places" error. If it is thrown, dragging location pin doesn't update route (see Video). Video: OpenStreetMap.and.45.more.pages.-.Work.-.Microsoft.Edge.2024-08-06.13-53-27.mp4 |
I know that we are using |
alert(I18n.t("javascripts.directions.errors.no_place", { place: endpoint.value })); | ||
return; | ||
} | ||
if (endpoint.value.match(/^([+-]?\d+(\.\d*)?)(?:\s+|\s*[/,]\s*)([+-]?\d+(\.\d*)?)$/)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we reuse /^([+-]?\d+(\.\d*)?)(?:\s+|\s*[/,]\s*)([+-]?\d+(\.\d*)?)$/
regex, it would be more understandable if we create separate constant variable for it and then use it with the variable name.
geocodeCallback(); | ||
}); | ||
} else { | ||
$.getJSON(OSM.NOMINATIM_URL + "search?q=" + encodeURIComponent(endpoint.value) + "&format=json&viewbox=" + viewbox, function (json) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When concatenating many strings, I think, using Template literals are more suitable and easier to read way.
$.getJSON(OSM.NOMINATIM_URL + "search?q=" + encodeURIComponent(endpoint.value) + "&format=json&viewbox=" + viewbox, function (json) { | ||
endpoint.awaitingGeocode = false; | ||
endpoint.hasGeocode = true; | ||
if (!json || json.length === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be shortened as !json?.length
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let/const
, template literals, ?.
etc - we should decide on these in a separate issue, not in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it needs a separate issue, we can create it, however I didn't mean refactoring of the old code (which definitely would be a separate issue), but to change them in the new code. Also, if somewhere we have coding style guidelines, please, link it and I'll create an issue linked to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked at what is already in use by included libraries:
let/const
- used by Bootstrap and Turbo?.
- used by Turbo- template literals - used by Bootstrap and Turbo
4394f80
to
2e20a63
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything I tested, worked perfectly. This is just recommendation for less code to be written.
@@ -5,6 +5,7 @@ | |||
OSM.Directions = function (map) { | |||
var awaitingRoute; // true if we've asked the engine for a route and are waiting to hear back | |||
var chosenEngine; | |||
var coordinatesRegularExpression = "([+-]?\\d+(\\.\\d*)?)(?:\\s+|\\s*[/,]\\s*)([+-]?\\d+(\\.\\d*)?)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid new RegExp("^" + coordinatesRegularExpression + "$")
every time we use this variable, you can define it as var coordinatesRegularExpression = /^([+-]?\d+(\.\d*)?)(?:\s+|\s*[\/,]\s*)([+-]?\d+(\.\d*)?)$/;
and it will automatically be regexp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this expression have capture groups if they are not used? Instead there's endpoint.value.split(/[/,]/)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree, I could have used better solutions on many places. My intention was to fix the bug and to make it simple, short and readable as much as I can. The source code is already a little bit complex and requires refactoring. We can optimize it in some other PR.
All above is fixed and PR is again ready to be reviewed. Thanks! |
@@ -51,7 +43,7 @@ OSM.Directions = function (map) { | |||
select.append("<option value='" + i + "'>" + I18n.t("javascripts.directions.engines." + engine.id) + "</option>"); | |||
}); | |||
|
|||
function Endpoint(input, iconUrl, dragCallback, geocodeCallback) { | |||
function Endpoint(input, iconUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're undoing #4902. I was going to move endpoint code into a separate module because it's difficult to test this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize for the undoing, I thought it's just simplifying .. I returned using callback for calling getRoute, so, Endpoint can be pulled out now to separate module.
Thanks,
Nenad.
2e20a63
to
5b6e81e
Compare
Fixes openstreetmap#2982 by updating directions.js so it doesn't perform unnecessary geocoding anymore for previously selected point (either source or destination) when entering second point. Allows reverse geocoding only when coordinates are specified from context menu. Also, improved setting markers by positioning it to selected position (not to result of geocoding) and improved focusing map view to include markers.
5b6e81e
to
f9d39a5
Compare
}); | ||
|
||
endpoint.setValue = function (value, latlng) { | ||
endpoint.setValue = function (value, force_reverse_geocoding, latlng, fitMap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would a single endpoint control fitting?
Then below you have:
endpoints[0].setValue(params.from || "", !ll_from_search_form, from, false);
endpoints[1].setValue(params.to || "", !ll_from_search_form, to, true);
And not it's not clear why the first endpoint gets fitMap = false
but the second one gets fitMap = true
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would a single endpoint control fitting?
Because the route can change on single endpoint update, so, it can go out of viewing area and we need to fit bounds.
Then below you have:
endpoints[0].setValue(params.from || "", !ll_from_search_form, from, false); endpoints[1].setValue(params.to || "", !ll_from_search_form, to, true);
And not it's not clear why the first endpoint gets
fitMap = false
but the second one getsfitMap = true
.
Because in some situations there is a flickering if we are doing fitting both times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would a single endpoint control fitting?
Because the route can change on single endpoint update
It's for the code outside of endpoints to determine what to do with the route.
return; | ||
} | ||
|
||
if (endpoint.latlng.distanceTo(L.latLng(json.lat, json.lon)) > 200.0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was this distance check about? Was it to filter out useless reverse geocoding results that are too far away from the endpoint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly! If it is found something near (e.g. 200m) the clicked coordinates, accept it, otherwise, display coordinates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't do this in #5064 because it's a different problem, but it probably should be solved somewhere.
What's "near" probably depends on the current zoom level if the coordinates came from a click on the map.
Closed in favor of #5064 |
This PR addresses "Directions from here often places the point hundreds of meters elsewhere" issue mentioned in #2982
Fixes #2982 by updating directions.js so it doesn't perform unnecessary geocoding anymore for previously selected point (either source or destination), when entering second point. Also, improved setting markers by positioning it to selected position (not to result of geocoding).