Calculate Esri map extents from gps coordinates - esri

I add some markers on Esri map and want to show map at zoom level where all markers are visible. I calculated minimum and maximum lat-lng and set the extent. But its not working.
Given Coordinates
lat, lon:41.984440, -87.827278
lat, lon:41.874489, -87.705772
calculated min-max:
xMax:"-87.827278"
xMin:"-87.705772"
yMax:"41.984440"
yMin:"41.874489"
expected result:
> EsriSetMapExtent:function(obj)
> {
> var extent = new esri.geometry.Extent(obj.xMin, obj.yMin, obj.xMax, obj.yMax);
> m.esriMap.setExtent(extent);
> },

The values of xMin and xMax are reversed., Only the X-axis, please check the function which performs the calculations. If you change them it will work. Below is the working sample
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<title>Simple Map</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.17/esri/css/esri.css">
<style>
html, body, #map {
height: 100%;
margin: 0;
padding: 0;
}
</style>
<script src="https://js.arcgis.com/3.17/"></script>
<script>
var map;
require(["esri/map","esri/geometry/Extent", "esri/SpatialReference", "esri/geometry/Point", "esri/symbols/SimpleMarkerSymbol",
"esri/Color", "esri/graphic", "dojo/domReady!"], function(Map, Extent, SpatialReference, Point, SimpleMarkerSymbol, Color, Graphic) {
map = new Map("map", {
basemap: "topo", //For full list of pre-defined basemaps, navigate to http://arcg.is/1JVo6Wd
center: [-87.705772, 41.874489], // longitude, latitude
zoom: 13
});
map.on('load', function(evt){
var pt = new Point(-87.705772, 41.874489, new SpatialReference({wkid:4326}))
var sms = new SimpleMarkerSymbol().setStyle(SimpleMarkerSymbol.STYLE_SQUARE).setColor(
new Color([255,0,0,0.5]));
var graphic = new Graphic(pt,sms);
map.graphics.add(graphic);
pt = new Point(-87.827278, 41.984440, new SpatialReference({wkid:4326}))
sms = new SimpleMarkerSymbol().setStyle(SimpleMarkerSymbol.STYLE_SQUARE).setColor(
new Color([0,255,0,0.5]));
graphic = new Graphic(pt,sms);
map.graphics.add(graphic);
})
var extent = new Extent(-87.827278, 41.874489, -87.705772, 41.984440, new SpatialReference({ wkid:4326 }));
map.setExtent(extent, true);
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>

The solution that worked for me was:
const geoPoint = new Point(Longitude, Latitude);
if (!map.extent.contains(geoPoint)) {
// point not in view
}

Related

Geocoding Openstreetmap gives different responses depending on zoom-level

I am trying to figure out why when hoovering on a village when zoom level is low show's the town of Västerås instead of Irsta, but when I zoom in it shows the village of Irsta.
You guys can try it yourselves in this example.
I would like to be able to locate Irsta when you can see the label of Irsta, it shouldn't be the bigger city of Västerås in that case.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Query Nominatem</title>
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.8.0/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.8.0/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script>
<style>
html, body, #map {
height:100%;
width:100%;
padding:0px;
margin:0px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const map = L.map('map').setView([48.210033, 16.363449], 10);
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
}).addTo(map);
let timeOut;
let popUp;
let queryState = false;
function mousemove(e) {
clearTimeout(timeOut)
if (!queryState) {
timeOut = setTimeout(() => {
queryState = true;
if (popUp) {
popUp.remove()
}
popPup = L.popup()
.setLatLng(e.latlng)
.setContent("Loading data....")
.openOn(map);
queryNominatem(e)
}, 1000);
}
}
function queryNominatem(e) {
fetch(`https://nominatim.openstreetmap.org/reverse.php?lat=${e.latlng.lat}&lon=${e.latlng.lng}&zoom=${map.getZoom()}&format=json`).then(
(x) => {
return x.json()
}
).then(
(data) => {
popUp = L.popup()
.setLatLng(e.latlng)
.setContent(data.display_name)
.openOn(map);
queryState = false;
}
).catch(
(err) => {
console.log(err);
popUp = L.popup()
.setLatLng(e.latlng)
.setContent("Error Loading data ... ")
.openOn(map);
setTimeout(() => {
popUp.remove();
queryState = false;
}, 1000);
}
);
}
map.on("mousemove", mousemove);
</script>
</body>
</html>
Zoom-in picture of village Irsta
Normal zooom of village Irsta
This is happening as you are using a dynamic zoom level in your reverse Nominatim request. If the zoom level is lower than 14, Nominatim will try to get the next city, (or if it way lower, even the country, etc., see https://nominatim.org/release-docs/develop/api/Reverse/#result-limitation )
So you'll have to define a min-value in your zoom while doing the reverse call, e.g. q&d:
reverseZoom=Math.max(14,map.getZoom());
fetch(`https://nominatim.openstreetmap.org/reverse.php?lat=${e.latlng.lat}&lon=${e.latlng.lng}&zoom=${reverseZoom}&format=json`)
Now the reverse call will always try to get a village, but - and this may be a problem - also a suburb instead of a city (but this would have happened with your original code as well if you zoom in). So I would recommend to use addressdetails=1 in your request and parse the addressdetails response for city/village/town to return that value instead of the display name value.

Change search result marker icon to a custom

I have the following code that is currently working. I have been looking all over and cannot find how to change the icon way from the tiny dot that defaults on the location. The code below is set to a specific address on page load.
I have tried PictureMarkerSymbol as you'll see I have that loaded into the function, but I'm not getting the right logic.
I figured this would be the easy part of using arcgis, but it's proving to be difficult.
thanks!
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<title>ArcGIS API for JavaScript</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.20/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.20/"></script>
<script>
require([
'esri/config',
'esri/Map',
'esri/views/MapView',
'esri/symbols/PictureMarkerSymbol',
'esri/widgets/Search',
'esri/layers/FeatureLayer',
], function (
esriConfig,
Map,
MapView,
PictureMarkerSymbol,
Search,
FeatureLayer
) {
esriConfig.apiKey =
'API-KEY';
const map = new Map({
basemap: 'arcgis-navigation',
});
const view = new MapView({
container: 'viewDiv',
map: map,
center: [-77.050636, 38.889248],
zoom: 13,
});
const search = new Search({
//Add Search widget
view: view,
});
view.ui.add(search, 'top-right'); //Add to the map
searchWidget = new Search({
view: view,
searchTerm: '43 Valley Oak Ct',
popupEnabled: false,
});
view.ui.add(searchWidget, 'bottom-right');
view.when(() => {
searchWidget.search();
});
});
</script>
It looks as the search widget resultGraphic is readonly, but it looks like you can specify a collection of SearchSource and provide it a symbol. You can almost use the default setting provided in an example under sources in documentation. Below is an example. You can use this tool for creating symbols.
<!--
To run this demo, you need to replace 'YOUR_API_KEY' with an API key from the ArcGIS Developer dashboard.
Sign up for a free account and get an API key.
https://developers.arcgis.com/documentation/mapping-apis-and-services/get-started/
-->
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Search widget with multiple sources | Sample | ArcGIS API for JavaScript 4.20</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.20/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.20/"></script>
<script>
require(["esri/Map", "esri/views/MapView", "esri/layers/FeatureLayer", "esri/widgets/Search", "esri/tasks/Locator", "esri/symbols/SimpleMarkerSymbol"], (
Map,
MapView,
FeatureLayer,
Search,
Locator,
SimpleMarkerSymbol,
) => {
const map = new Map({
basemap: "dark-gray-vector"
});
const view = new MapView({
container: "viewDiv",
map: map,
center: [-97, 38], // lon, lat
scale: 10000000
});
var marker = new SimpleMarkerSymbol({ color: [203, 52, 52, 0.93] });
const searchWidget = new Search({
view: view,
searchTerm: '43 Valley Oak Ct',
popupEnabled: false,
sources: [
{
locator: new Locator("//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"),
singleLineFieldName: "SingleLine",
outFields: ["Addr_type", "Match_addr", "StAddr", "City"],
name: "ArcGIS World Geocoding Service",
placeholder: "Find address or place",
resultSymbol: marker,
}
]
});
searchWidget.viewModel.includeDefaultSources = false;
// Add the search widget to the top left corner of the view
view.ui.add(searchWidget, {
position: "top-right"
});
view.when(() => {
searchWidget.search();
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

arcGIS 4.18 locate widget custom icon

I have to change the default icon on the Locate widget on arcGIS 4.18. The default icon class is, esri-icon-locate how can I change it to the class, 'esri-icon-navigation'?
I am going through the documentation,
https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Locate.html#iconClass
I have tried to use the property, 'iconClass'. But not reflecting in the map icon. Please find the code below,
var locateBtn = new Locate({
view: view,
// iconClass: '\ue666'
iconClass: 'esri-icon-navigation'
});
view.ui.add(locateBtn, {
position: "manual",
});
KER,
You actually right, does not work as expected. Setting iconClass should be the solution.
Funny fact if you check the default iconClass is actually esri-icon-north-navigation, which obviously in not.
Anyway, I am gonna give a dirty solution, just overlap the class you want,
view.when(_ => {
const n = document.getElementsByClassName("esri-icon-locate");
if (n && n.length === 1) {
n[0].classList += " esri-icon-navigation"
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>Locate button | Sample | ArcGIS API for JavaScript 4.18</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css" />
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script src="https://js.arcgis.com/4.18/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/widgets/Locate"
], function (Map, MapView, Locate) {
var map = new Map({
basemap: "topo-vector"
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-56.049, 38.485, 78],
zoom: 3
});
var locateBtn = new Locate({
view: view
});
// Add the locate widget to the top left corner of the view
view.ui.add(locateBtn, {
position: "top-left"
});
view.when(_ => {
const n = document.getElementsByClassName("esri-icon-locate");
if (n && n.length === 1) {
n[0].classList += " esri-icon-navigation"
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

How do I add graphics to Map in a projected coordinate system other than Web Mercator?

I am trying to draw a cross at London in a map.
The code works if I specify the coordinates of the point in either geographic or web mercator.
However it does not work if I specify the coordinates in ED50 / UTM zone 31N.
According to the documentation the Point constructor takes the spatial reference as the last argument. I would think that this would mean that the point would be transformed to the coordinate system of the map (web mercator)? However the point now appears somewhere in the middle of France. Not sure what is happening here?
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>London Map</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.17/esri/css/esri.css">
<style>
html, body, #map {
height: 100%;
margin: 0;
padding: 0;
}
</style>
<script src="https://js.arcgis.com/3.17/"></script>
<script>
var map;
require(["esri/map", "esri/geometry/Point", "esri/SpatialReference", "esri/graphic", "dojo/domReady!"], function (Map, Point, SpatialReference, Graphic) {
map = new Map("map", {
basemap: "topo", //For full list of pre-defined basemaps, navigate to http://arcg.is/1JVo6Wd
center: [0.1, 51.5], // longitude, latitude
zoom: 8
});
map.on("load", function () {
//var P = new Point({ "x": 0.1, "y": 51.5, "spatialReference": { "wkid": 4326 } }); // geographic: works!
//var P = new Point({ "x": -10978, "y": 6708911, "spatialReference": { "wkid": 102100 } }); // web mercator: works!
//var P = new Point({ "x": 284879, "y": 5711864, "spatialReference": { "wkid": 23031 } }); // somewhere in the middle of France !!??
var P = new Point([284879, 5711864], new SpatialReference({ wkid: 23031 })); // somewhere in the middle of France !!??
var pointSymbol = new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_X, 10, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0, 0, 0]), 2), new dojo.Color([0, 255, 0, 0.25]));
var mapPointGraphic = new Graphic(P, pointSymbol);
map.graphics.add(mapPointGraphic);
});
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>
ESRI JavaScript API, does not have any client side projection api, except between WebMercator(102100,102113,3875) and WGS84(4326). For these it uses esri/geometry/webMercatorUtils module for convert the spatial reference. For all other projection systems you need to use GeometryService to project. Below is a sample code for the same.
require(["dojo/_base/array", "esri/tasks/GeometryService", "esri/tasks/ProjectParameters", "esri/SpatialReference"], function(GeometryService, ProjectParameters, array) {
var gsvc = new GeometryService("https://utility.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
var P = new Point([284879, 5711864], new SpatialReference({ wkid: 23031 }));
var outSR = new SpatialReference({wkid:102110});
var params = new ProjectParameters();
params.geometries = [P];
params.outSR = outSR;
params.transformation = transformation;
gsvc.project(params, function(projectedGeometries){
P = projectedGeometries[0];
});
});

How to open popup at (lng,lat) position in arcgis 4.0

Let's consider this code from the reference (https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Popup.html#open):
view.on("click", function(evt){
view.popup.open({
location: evt.mapPoint, // location of the click on the view
title: "Some title",
});
This works. But how to open a popup at the point, specified by predefined lng,lat coords?
First try:
var point = new Point({latitude:lat,longitude:lng});
view.popup.open({
location: point,
title: "Some title"
});
This does not work. The reason is that created point currently disconnected from map view. Is there a way to receive screen coords (x,y) of the current view by specified (lng,lat)? In google maps api there're methods like latLngToDivPixel, latLngToDivPoint, so what argis offers for this task?
Looks like you're having a SpatialReference issue. Since you're creating the point via lat/lng, it's not in WebMercator, so when you add it to the map it's going to the wrong place. Here's a fixed code for you:
// this works, but needs to be in webmercator:
// var point = new Point({x:-9035831.315416021, y:3095345.196351918});
// as an alternative you can translate to webmercator on the fly:
var point = webMercatorUtils.geographicToWebMercator(new Point({latitude:28.526622,longitude:-81.914063}));
view.popup.open({
location: point,
title: "Some title"
});
Here is the above code in an example.
The answer/issue above was correct for version 4.0 and 4.1.
However, for the newly released version 4.2, this has been simplified. Popup.location now automatically converts WGS84 (latitude, longitude) points to web mercator when map is in web mercator projection.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="description" content="[Define custom Popup actions - 4.2]">
<!--
ArcGIS API for JavaScript, https://js.arcgis.com
For more information about the popup-actions sample, read the original sample description at developers.arcgis.com.
https://developers.arcgis.com/javascript/latest/popup-actions/index.html
-->
<title>Define custom Popup actions - 4.2</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.2/esri/css/main.css">
<script src="https://js.arcgis.com/4.2/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/geometry/Point",
"dojo/domReady!"
], function(
Map,
MapView,
Point
) {
// Create the Map
var map = new Map({
basemap: "topo"
});
// Create the MapView
var view = new MapView({
container: "viewDiv",
map: map,
center: [-117, 34],
zoom: 9
});
view.then(function() {
var peak = new Point({
latitude: 34.09916,
longitude: -116.82485
});
view.popup.open({
location: peak,
title: "San Gorgonio Mountain",
content: "Tallest peak in Southern California"
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
https://jsbin.com/heqotom/edit?html,output