Learn how to display geometries in different projections.
A geometry projection transforms the vertices of a geometric shape from one coordinate system (a spatial reference) to another. For example, you can project a geographic coordinate system such as WGS84 (4326) to a projected coordinate system such as World Sinusoidal (54008).
Each projection can maintain one of the following: area, angle, or direction. The projection you use is based on your application's requirements. For example, if you have data centered on the North Pole, the Web Mercator (3857) spatial reference is typically not used as the pole features are not correctly represented by the projection; there is a large area distortion. Instead, you might use the North Pole Gnomonic (102034) spatial reference because it preserves the area around the North Pole.
In this tutorial, you will project GeoJSON features using the projection engine and a spatial reference chosen from the selector. The map's center point and buffer graphic are also added to the map view.
Prerequisites
Steps
Create a new pen
- To get started, either complete the Display a map tutorial or .
Get an access token
You need an access token with the correct privileges to access the location services used in this tutorial.
- Go to the Create an API key tutorial and create an API key with the following privilege(s):
- Privileges
- Location services > Basemaps
- Privileges
- In CodePen, set
esri
to your access token.Config.api Key Use dark colors for code blocks var esriConfig = { apiKey: "YOUR_ACCESS_TOKEN" };
To learn about other ways to get an access token, go to Types of authentication.
Add a Calcite select to change the spatial reference
-
In CodePen > HTML, modify the
arcgis-map
component'sbasemap
,center
andzoom
attributes.Use dark colors for code blocks <body> <arcgis-map basemap="none" center="-10, 30" scale="150000000"> <arcgis-zoom position="top-left"></arcgis-zoom> </arcgis-map> </body>
-
Add HTML to add an
arcgis-placement
with acalcite-select
inside. Thecalcite-select
component will be used to switch between spatial references.Use dark colors for code blocks <body> <arcgis-map basemap="none" center="-10, 30" scale="150000000"> <arcgis-zoom position="top-left"></arcgis-zoom> <arcgis-placement position="top-right"> <div class="select-container"> <calcite-label> Select a projection <calcite-select id="wkid"> <calcite-option-group label="Equidistant (maintain length)"> <calcite-option value="4326" selected> WGS84 (GCS) -> pseudo Plate Carrée (Cylindrical) </calcite-option> <calcite-option value="54028">World Cassini (Cylindrical)</calcite-option> <calcite-option value="54027">World Equidistant conic (Conic)</calcite-option> </calcite-option-group> <calcite-option-group label="Conformal (maintain angles)"> <calcite-option value="54026">World Stereographic (Azimuthal)</calcite-option> </calcite-option-group> <calcite-option-group label="Equal-area (maintain area)"> <calcite-option value="54010">World Eckert VI (Pseudocylindrical)</calcite-option> <calcite-option value="54008">World Sinusoidal (Pseudocylindrical)</calcite-option> </calcite-option-group> <calcite-option-group label="Gnomonic (distances)"> <calcite-option value="102034">North Pole Gnomonic (Azimuthal)</calcite-option> </calcite-option-group> <calcite-option-group label="Compromise (distort all)"> <calcite-option value="3857"> Web Mercator Auxiliary Sphere (Cylindrical) </calcite-option> <calcite-option value="54016"> World Gall Stereographic (Cylindrical) </calcite-option> <calcite-option value="54042">World Winkel Tripel (Pseudoazimuthal)</calcite-option> <calcite-option value="54050"> World Fuller / Dymaxion map (Polyhedral) </calcite-option> </calcite-option-group> </calcite-select> </calcite-label> </div> </arcgis-placement> </arcgis-map> </body>
-
Within the
<style
tags, apply some CSS styles for the> div
containing thecalcite-select
component.Use dark colors for code blocks <style> html, body, arcgis-map { padding: 0; margin: 0; height: 100%; width: 100%; background-color: #ffffff; } .select-container { background-color: white; border-radius: 5px; padding: 10px; width: 400px; } </style>
Add modules
-
In a new
<script
at the bottom of the> <body
, use a> require
statement to add the modules we need.The ArcGIS Maps SDK for JavaScript is available as AMD modules and ES modules, but this tutorial is based on AMD. The AMD
require
function uses references to determine which modules will be loaded – for example, you can specify"esri/layers/
for loading the FeatureLayer module. After the modules are loaded, they are passed as parameters (e.g.Feature Layer" Feature
) to the callback function where they can be used in your application. It is important to keep the module references and callback parameters in the same order. To learn more about the API's different modules visit the Overview Guide page.Layer Use dark colors for code blocks <script> require([ "esri/Graphic", "esri/geometry/Extent", "esri/geometry/Geometry", "esri/geometry/geometryEngine", "esri/geometry/Point", "esri/geometry/projection", "esri/geometry/SpatialReference", "esri/layers/GeoJSONLayer", "esri/renderers/SimpleRenderer", "esri/symbols/SimpleFillSymbol", "esri/symbols/SimpleMarkerSymbol" ], ( Graphic, Extent, Geometry, geometryEngine, Point, projection, SpatialReference, GeoJSONLayer, SimpleRenderer, SimpleFillSymbol, SimpleMarkerSymbol ) => { }); </script>
Set symbols and graphics
Create the buffer and point symbols that will for graphics created in a later step.
-
Set polygon and point styling that will display when a point is buffered on the map.
Use dark colors for code blocks const bufferSymbol = new SimpleFillSymbol({ color: [150, 130, 220, 0.85], outline: { color: "gray", width: 0.5 } }); const pointSymbol = new SimpleMarkerSymbol({ color: "red", outline: { color: "white", width: 0.5 }, size: 5 });
-
To visualize the extent of the world for each spatial reference, create a new Graphic with a SimpleFillSymbol set to a gray dashed outline and a fully transparent fill. Set the geometry to to an Extent that covers the entire world with the
spatial
property toReference WG
.S84 Use dark colors for code blocks const projectionBoundary = new Graphic({ symbol: new SimpleFillSymbol({ color: [0, 0, 0, 0], outline: { width: 0.5, color: [50, 50, 50, 0.75], style: "dash" } }), geometry: new Extent({ xmin: -180, xmax: 180, ymin: -90, ymax: 90, spatialReference: SpatialReference.WGS84 }) });
Add a GeoJSON layer
Create a layer based on GeoJSON data with the GeoJSONLayer class. GeoJSON features are in the WGS84 geographic coordinate system. Once added to the map, the features are automatically projected to the match the spatial reference in the map view.
-
Create a
countries
element that instantiates the GeoJSONLayer class. Set theGeo Json renderer
to add a purple outline around the countries.Use dark colors for code blocks const countriesGeoJSON = new GeoJSONLayer({ url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/ArcGIS/rest/services/World_Countries_(Generalized)/FeatureServer/0/query?where=1%3D1&outFields=*&f=geojson", copyright: "Esri", spatialReference: { wkid: 4326 }, renderer: new SimpleRenderer({ symbol: new SimpleFillSymbol({ color: [255, 255, 255, 1], outline: { width: 0.5, color: [100, 70, 170, 0.75] } }) }) });
-
Get a reference to the
arcgis-map
component. Set thespatial
of the map component toReference 4326
(WGS84).Use dark colors for code blocks const arcgisMap = document.querySelector("arcgis-map"); arcgisMap.spatialReference = new SpatialReference({ wkid: 4326 });
-
Wait for the map to become ready before adding the
projection
andBoundary countries
layers to the map.Geo Json Use dark colors for code blocks arcgisMap.addEventListener("arcgisViewReadyChange", () => { arcgisMap.addLayer(countriesGeoJSON); arcgisMap.graphics.add(projectionBoundary); });
Switch between spatial references
The default spatial reference for a GeoJSON layer is WGS84 (4326). Use the selector to switch between WGS84 and the other projections defined in the calcite-select
.
-
Create a
change
function that will change the spatial reference of the map based on theSpatial Reference wkid
that chosen from thecalcite-select
.Use dark colors for code blocks function changeSpatialReference(wkid) { const spatialReference = new SpatialReference({ wkid: Number(wkid) }); arcgisMap.spatialReference = spatialReference; }
-
Get a reference to the
calcite-select
element. Add an event listener to set the spatial reference and project the map's center point using thechange
function.Spatial Reference Use dark colors for code blocks arcgisMap.addEventListener("arcgisViewReadyChange", () => { arcgisMap.addLayer(countriesGeoJSON); arcgisMap.graphics.add(projectionBoundary); }); const wkidSelect = document.getElementById("wkid"); wkidSelect?.addEventListener("calciteSelectChange", () => { changeSpatialReference(wkidSelect.value); });
-
Run the app. Switch between spatial reference and observe how the shape of the layers and graphics change.
View projected coordinates
To visualize the effect of the reprojected maps's center point, add it as a graphic to the view and display its x/y coordinates from a new spatial reference.
-
Create a
display
function with aCoordinates point
parameter. Define apopup
to display theTemplate wkid
,x
, andy
coordinates of thepoint
.Use dark colors for code blocks function displayCoordinates(point) { const popupTemplate = { title: `WKID: ${point.spatialReference.wkid}`, content: `<b>X:</b> ${point.x.toFixed(5)} | <b>Y:</b> ${point.y.toFixed(5)}`, overwriteActions: true }; }
-
Create a
graphic
. Set thegeometry
with thepoint
and thepopup
with theTemplate popup
defined in the previous step. Add theTemplate graphic
to theview
and call theopen
method to display the popup when the application loads.Popup Use dark colors for code blocks function displayCoordinates(point) { const popupTemplate = { title: `WKID: ${point.spatialReference.wkid}`, content: `<b>X:</b> ${point.x.toFixed(5)} | <b>Y:</b> ${point.y.toFixed(5)}`, overwriteActions: true }; const graphic = new Graphic({ geometry: point, popupTemplate: popupTemplate }); arcgisMap.graphics.add(graphic); arcgisMap.openPopup({ features: [graphic] }); }
-
Update the
create
function and theView With Spatial Reference arcgis
event listener to call theView Ready Change display
function with the map's center point as its parameter.Coordinates Use dark colors for code blocks function changeSpatialReference(wkid) { const spatialReference = new SpatialReference({ wkid: Number(wkid) }); arcgisMap.spatialReference = spatialReference; displayCoordinates(arcgisMap.center); }
Use dark colors for code blocks arcgisMap.addEventListener("arcgisViewReadyChange", () => { arcgisMap.addLayer(countriesGeoJSON); arcgisMap.graphics.add(projectionBoundary); displayCoordinates(arcgisMap.center); });
-
Run the app. Switch between spatial references to view the projected coordinates of the center of the map.
View the effects of a projection
Each projection maintains the accuracy of one dimension, but creates inaccuracies in another. For example, you might be able to maintain area but not distance. To view the effects each spatial reference has on a circular shape, create a geodesic buffer where you move the mouse. The geodesic
method only works in WGS84 (4326) and Web Mercator (3857) spatial references. To view the buffer in another spatial reference, you need to reproject the point first to either 4326 or 3857 and then call the geodesic
method.
-
Create a
buffer
function that takes thePoint point
as its parameter. If thepoint
is in another spatial reference, then call theprojection
module and transform the coordinates into4326
to create the buffer. If there is nopoint
, thenreturn
.Use dark colors for code blocks function bufferPoint(point) { const wkid = point.spatialReference.wkid; if (wkid != 4326 && wkid != 3857) { point = projection.project(point, new SpatialReference({ wkid: 4326 })); if (!point) { return; } } } }
-
Create a
buffer
graphic from thegeodesic
method on theBuffer point
. It will buffer thepoint
with a radius of1000
kilometers
.Use dark colors for code blocks function bufferPoint(point) { const wkid = point.spatialReference.wkid; if (wkid != 4326 && wkid != 3857) { point = projection.project(point, new SpatialReference({ wkid: 4326 })); if (!point) { return; } } const buffer = geometryEngine.geodesicBuffer(point, 1000, "kilometers"); } }
-
Remove existing
graphics
from theview
except for the map projection boundary and map's center point graphics.Use dark colors for code blocks function bufferPoint(point) { const wkid = point.spatialReference.wkid; if (wkid != 4326 && wkid != 3857) { point = projection.project(point, new SpatialReference({ wkid: 4326 })); if (!point) { return; } } const buffer = geometryEngine.geodesicBuffer(point, 1000, "kilometers"); if (point && buffer) { // Avoid removing the map projection boundary arcgisMap.graphics.removeMany([arcgisMap.graphics.getItemAt(2), arcgisMap.graphics.getItemAt(3)]); } }
-
Create a
buffer
that takes theGraphic buffer
as itsgeometry
and thebuffer
for itsSymbol symbol
styling. Add thebuffer
, along with theGraphic point
, created from moving the mouse, and itspoint
styling to theSymbol arcgis-map
.Use dark colors for code blocks function bufferPoint(point) { const wkid = point.spatialReference.wkid; if (wkid != 4326 && wkid != 3857) { point = projection.project(point, new SpatialReference({ wkid: 4326 })); if (!point) { return; } } const buffer = geometryEngine.geodesicBuffer(point, 1000, "kilometers"); if (point && buffer) { // Avoid removing the map projection boundary arcgisMap.graphics.removeMany([arcgisMap.graphics.getItemAt(2), arcgisMap.graphics.getItemAt(3)]); const bufferGraphic = new Graphic({ geometry: buffer, symbol: bufferSymbol }); arcgisMap.graphics.addMany([ bufferGraphic, new Graphic({ geometry: point, symbol: pointSymbol }) ]); } }
-
Create a
create
function that takes theBuffer event
as its parameter. Define apoint
based on thex
andy
coordinates from theevent
. If there is apoint
, call thebuffer
function.Point Use dark colors for code blocks function createBuffer(event) { const point = arcgisMap.view.toMap({ x: event.x, y: event.y }); if (point) { bufferPoint(point); } }
-
Create an event handler that will buffer a point based on the movement of the mouse.
Use dark colors for code blocks arcgisMap.addEventListener("arcgisViewReadyChange", () => { arcgisMap.addLayer(countriesGeoJSON); arcgisMap.graphics.add(projectionBoundary); displayCoordinates(arcgisMap.center); }); arcgisMap.addEventListener("arcgisViewPointerMove", (event) => { createBuffer(event.detail); }); const wkidSelect = document.getElementById("wkid"); wkidSelect?.addEventListener("calciteSelectChange", () => { changeSpatialReference(wkidSelect.value); });
Run the app
In CodePen, run your code to display the map.
When you run the app, you will see the map's center point and its coordinates. The features in the GeoJSON layer, as well as the geometries of the map's center point and buffer, are reprojected when you choose a new spatial reference. Move the mouse around the map to view the distortion for each spatial reference.
What's next?
Learn how to use additional API features and ArcGIS services in these tutorials: