Is there a solution like leaflet-knn in ArcGIS (js-api) for finding the nearest point in a geoJSON multi-point feature to a given point? - leaflet

This is how i get the closest point on a geoJSON line to a given point using leaflet-knn:
Given a point, find the nearest points to it. If the index contains multi-point features, like lines, polygons, and so on, it returns points in those features and can return more than one point in each feature.
const line= L.geoJSON(this.lineFromGeoJson, {
onEachFeature: (feature, layer) => {
layer.bindPopup(
'insignificant feature stuff here',
{maxHeight: this.screenHeight, maxWidth: this.screenWidth, autoPan: true});
}
}).addTo(this.map);
const nearest = leafletKnn(line).nearest(L.latLng(this.lat, this.longt), 1);
Is there anything similar in #arcgis/core?
I'm already using the geodesicUtils.geodesicLengths from arcgis to get the length of this geoJSON line and i figured perhaps there was a solution for this in arcgis that i have not found?

I think you could use geometryEngine.nearestVertices method (ArcGIS JS API - esriGeometry).
Now, this method actually takes a geometry as parameter instead of a layer, so you will probably will need to "create" the geometry using the layer or better a subset of the layer.
You can get a subset of the layer (set of features) with a distance query on the layer using ArcGIS JS API - Query.

Related

how convert coordinates from UTM Ghana meter Grid to Latitude Longitude and vice versa from leaflet js

I'm working on leaflet Js in which I expect user inputs of coordinates in X, Y form. i.e. Ghana meter Grid and I need to convert the X, Y into latitudes, and longitudes so that they can be plotted as markers on leaflet Js.
Since you are working with Javascript, I suggest to approach this problem with proj4js (the Javascript implementation of OSGeo's proj, the industry standard for converting coordinates between coordinate reference systems).
First, grab a release of proj4js, or use a CDN-hosted release, e.g.:
<script src='https://unpkg.com/proj4#2.6.2/dist/proj4.js'></script>
Proj4js doesn't come with the full definition list of CRSs (Coordinate Reference Systems), so you'll have to define the CRSs you want to work with. In your case, it's gonna be EPSG:25000 AKA "Ghana Metre Grid" and EPSG:4326 AKA "Equirectangular WGS84" AKA "latitude-longitude":
proj4.defs("EPSG:4326","+proj=longlat +datum=WGS84 +no_defs");
proj4.defs("EPSG:25000","+proj=tmerc +lat_0=4.666666666666667 +lon_0=-1 +k=0.99975 +x_0=274319.51 +y_0=0 +ellps=clrk80 +towgs84=-130,29,364,0,0,0,0 +units=m +no_defs");
You can fing the PROJ definitions of CRSs in either the data files of a PROJ release, or websites such as epsg.io.
Once the CRSs have been defined, call proj4js with their names and the coordinates to transform, e.g. to transform from EPSG:4326 to EPSG:25000...
console.log( proj4("EPSG:4326", "EPSG:25000", [-0.187, 5.6037]) );
...or from EPSG:25000 to EPSG:4326...
console.log( proj4("EPSG:25000", "EPSG:4326", [364346.57, 103339.95]) );
See a working example here.
Be wary of the order of coordinates (lat-lon vs lon-lat, or x-y vs y-x). Leaflet uses lat-lng, but proj uses x-y and lng-lat, so you'll have to flip the coordinates, e.g.
var accraLngLat = proj4("EPSG:25000", "EPSG:4326", [364346.57, 103339.95]);
L.marker([accraLngLat[1], accraLngLat[0]]).addTo(map);
or
var accraLngLat = proj4("EPSG:25000", "EPSG:4326", [364346.57, 103339.95]);
var accraLatLng = L.GeoJSON.coordsToLatLng(accraLngLat);
L.marker(accraLatLng).addTo(map);
See a working example here.
Also note that proj4js does all the reprojection work and there are no API calls involved.
Since you are specifically working with Leaflet, you might also be interested in proj4leaflet, although you might not need it. It'll be useful if you want to use Leaflet to display raster data (or map tiles) in different projections.
You can use this online converter: http://epsg.io/?q=Ghana
Using API parameters, you may be able to perform a GET request when the user inputs coordinates for conversion via your app.

Leaflet or mapbox icon rotation like computeheading

I have a map in leafletJS and when the icon moves along, I have the angle and I am using the Leaflet.RotatedMarker plugin to rotate the icon to face where its heading.
Does leaflet js have a plugin that can enable me to not supply the angle myself ...
L.marker([48.8631169, 2.3708919], {
rotationAngle: 45
}).addTo(map);
...and instead use a function like gogle maps' computeheading() ?
Edit:
Does mapbox have a function like computeHeading
https://github.com/bbecquet/Leaflet.RotatedMarker
js:
var boat_marker = L.marker([set_lat, set_long], {
pid: guid(),
// rotationAngle: 45,
icon: boatIcon,
draggable: true,
}).addTo(mymap);
function rotated_point() {
boat_marker.setRotationAngle(90);
}
No.
Leaflet has only a minimal set of geodesy-related functions. Functions to calculate headings, azymuths, geodesic distances or great circles are not needed for basic Leaflet functionality, and are not included.
A popular approach to this kind of problems is to rely on the javascript bindings of geographiclib for geodesy-related calculations (such as heading/azymuth), in the same way turf.js helps with geoprocessing of vector data.
Note that geographiclib is not a Leaflet plugin, but rather a generic set of geodesic functions. You will need to use a bit of care to get the latitude and longitude components of L.LatLngs, and fetch only the azymuth (and drop the distance) from the solution to the geodesic problem.

How can I query the feature that's closest to the geocode result in Mapbox?

I'm trying to create a Mapbox map with thousands of points. I want the user to be able to type an address and a div to be filled with information from the closest point to that address. I'm using the mapbox-gl-geocoder control
What would be perfect is if I could use something like:
geocoder.on('result', function(e) {
var features = map.queryRenderedFeatures(e.result.center)
});
But queryRenderedFeatures doesn't accept latlong coordinates, it requires viewport coordinates.
The next thing I tried was
map.on('moveend', function () {
var xwindow = window.innerWidth / 2;
var ywindow = window.innerHeight / 2;
var xywindow = {'x': xwindow, 'y': ywindow};
var features = map.queryRenderedFeatures(xywindow);
});
That gives results that are near the queried address, but not the closest point. For instance if I geocode an address where I know a point exists, this query will return a different point a few streets away.
Is there a way to use queryRenderedFeatures to get a feature on the location that is returned by the geocode control?
But queryRenderedFeatures doesn't accept latlong coordinates, it requires viewport coordinates.
Yes but you can use map.project that Returns a Point representing pixel coordinates, relative to the map's container, that correspond to the specified geographical location.
Once you have all the features you'll need to get the distance to each of them to find the closest. cheap-ruler would be a good choice for that.
An index like geokdbush probably doesn't make sense here as you're only running it once.

Leafletjs GeoJSON layer is not working for map data from Natural Earth

I am using leafletjs to plot geographical maps using OSM tiles. I used the following GeoJSON as a map layer http://code.highcharts.com/mapdata/1.0.0/custom/world.js which uses data from naturalearthdata.com
But it is not working. The tile layer is shown correctly. But the GeoJSON data is not being shown. I can only see a white line across the map.
var worldMapData = {}; //the geoJson data from http://code.highcharts.com/mapdata/1.0.0/custom/world.js
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osm = L.tileLayer(osmUrl, {
noWrap: true,
attribution: "<a href='http://openstreetmap.org'>OpenStreetMap</a>"
});
var map = L.map('map').setView([0, 0], 1).addLayer(osm);
function style( feature ) {
return {
fillColor: '#FFEDA0',
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
map.addLayer(L.geoJson(worldMapData, {style: style}));
Am I missing something? Is the above GeoJSON not according to specification? And if not, from where can I download GeoJSONs for all countries which are compatible with leafletjs?
[Edit] Here is the jsfiddle for the above problem http://jsfiddle.net/1x1p55fy/
The GeoJSON data is being loaded correctly, and is being displayed as expected. However, the GeoJSON data is not conformant to the GeoJSON spec, in regards to the coordinate reference system. Let me quote from the GeoJSON specs:
The coordinate reference system for all GeoJSON coordinates is a
geographic coordinate reference system, using the World Geodetic
System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
of decimal degrees. This is equivalent to the coordinate reference
system identified by the Open Geospatial Consortium (OGC) URN
urn:ogc:def:crs:OGC::CRS84. An OPTIONAL third-position element SHALL
be the height in meters above or below the WGS 84 reference
ellipsoid. In the absence of elevation values, applications
sensitive to height or depth SHOULD interpret positions as being at
local ground or sea level.
Note: the use of alternative coordinate reference systems was
specified in [GJ2008], but it has been removed from this version of
the specification because the use of different coordinate reference
systems -- especially in the manner specified in [GJ2008] -- has
proven to have interoperability issues. In general, GeoJSON
processing software is not expected to have access to coordinate
reference system databases or to have network access to coordinate
reference system transformation parameters. However, where all
involved parties have a prior arrangement, alternative coordinate
reference systems can be used without risk of data being
misinterpreted.
If you have a closer look at the data in https://code.highcharts.com/mapdata/custom/world-highres.geo.json (or http://code.highcharts.com/mapdata/1.0.0/custom/world.js for that matter) you'll see that, in fact, the coordinates are not in latitude-longitude relative to the WGS84 geoid, and that there is a reference to the EPSG:54003 coordinate reference system (cylindrical miller), with a custom scale and offset transform.
As the GeoJSON spec already stated, you are hereby discouraged to use any other CRS than EPSG:4326 (WGS84 in latitude-longitude) in your GeoJSON data.
Find some conformant GeoJSON, and it will look OK in Leaflet. Leaflet does not handle reprojection of GeoJSON data, nor it handles the scale transforms that highcharts data implies.

Leafletjs How to project EPSG4326 points to the leaflet default

I am using Australian government map data found here: Victoria, Australia locality data, which is provided in the EPSG4326 projection.
When I try to use the data with leaflet, of course, my data is a bit distorted due to the earth's curvature - so my data is not represented properly on the screen because the maps are using a different projection to my data.
I have tried to force the map to use EPSG4326 by setting it in Map options and also in the TileLayer, as shown here:
var gisLayer = L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
//subdomains: ['0', '1', '2', '3'],
attribution: 'openstreetmap',
reuseTiles: true,
updateWhenIdle: false,
crs: L.CRS.EPSG4326
});
var map = L.map('map', {
center: [-28.5, 135.575],
zoom: 4
,crs: L.CRS.EPSG4326
});
map.addLayer(gisLayer);
but when I do this, the maps do not display. I don't believe the map tiles have been generated for this projection. That said, there is a suggestion in the docos here that it might be possible, but I couldn't get this working. (Did I just get the configuration wrong?)
It seemed like it was working when I retrieved the data and placed it on the map, but when I got the map bounds to select the data for the visible region, it also showed distorted. So I tried to convert the map bounds to EPSG4326 manually, to pass that to the database, as follows:
var bounds = map.getBounds();
var coords4326_NE = L.Projection.SphericalMercator.unproject(bounds._northEast);
console.log(coords4326_NE);
but that broke the code. I was passing the wrong structure in and I couldn't get this right either.
Of course, I would also accept transforming every point returned from the database to the default projection, which I think is EPSG3857. But I am having doing this as well.
I have provided as jsFiddle here where I have been attempting to do the above.
Does anyone know how I can achieve this?
Your GeoJSON data is encoded in WGS84, which can be simply plotted on EPSG4326, but is also the expected input for EPSG3857 (Web Mercator).
From that Wikipedia article:
While the Web Mercator's formulas are for the spherical form of the Mercator, geographical coordinates are required to be in the WGS 84 ellipsoidal datum.
Therefore, you do not have to change anything to plot your data onto a regular Leaflet map, using regular tiles (from OSM or Mapbox, which provide tiles only for EPSG3857).