ArcGIS API for JavaScript - proceedings.esri.comproceedings.esri.com/library/userconf/devsummit19/papers/DevSummitPS... · 2019 Esri Developer Summit Palm Springs -- Presentation,

Post on 17-Oct-2019

5 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

Transcript

ArcGIS API for JavaScriptArcGIS API for JavaScriptProgramming Patterns and API FundamentalsProgramming Patterns and API Fundamentals

Kelly Hutchins | René Rubalcava

|

slides:

@kellyhutchins @odoenet

https://git.io/fhNcV

What do I get with the 4x JSAPI?What do I get with the 4x JSAPI?Simpli�ed and consistent APIWrite apps in ES6 or TypeScriptModern browser support (IE11+)Supported in 30+ locales

What are my options?What are my options?Needs?Resources?Time?Customizations?

Why start from scratch?Why start from scratch?App startersWidgets

Widgets!Widgets!We'll look at a few ~30 Widgets out of the boxWidgets help make great appsLess code for you to writeDesigned with responsive apps in mind

widgets

Widgets - ExpandWidgets - Expand

IconsGroupMode

Clickable button to open container

Widgets - Use Portal ContentWidgets - Use Portal Content

Basemap GallerySearch

Widgets - Popup TemplateWidgets - Popup TemplateDe�ne �elds, charts, custom html content

PromisesArcade

Using a function

Widgets - Author popup in onlineWidgets - Author popup in online

Layer.fromPortalItemWeb Map or Web Scene

App Demo

Widgets - FeatureWidgets - FeatureDisplay popup template contentHover

Widgets - ArchitectureWidgets - ArchitectureView + View Model

GeocodingGeocodingconstconst locator locator == newnew LocatorLocator(({{ url url:: url url }}));;

locatorlocator..addressToLocationsaddressToLocations(({{

address address:: {{

"singleLine""singleLine":: "380 New York St, Redlands, CA 92373""380 New York St, Redlands, CA 92373"

}}

}}));;

locatorlocator..locationToAddresslocationToAddress(({{ location location:: point point }}));;

GeocodingGeocodingconstconst searchVM searchVM == newnew SearchVMSearchVM(());;

searchVMsearchVM..searchsearch(("380 New York St, Redlands, CA 92373""380 New York St, Redlands, CA 92373"));;

searchVMsearchVM..searchsearch((locationlocation));;

GeocodingGeocodingconstconst portal portal == newnew PortalPortal((......));;

awaitawait portal portal..loadload(());;

portalportal..helperServiceshelperServices..geocodegeocode..mapmap((geocoderServicegeocoderService =>=> {{

// objects with details on// objects with details on

// geocode services for your portal// geocode services for your portal

}}));;

Widgets - StylingWidgets - StylingAvailable Themes

Theme TestingA PEN BY kellyhutchins

Run Pen

Widgets - StylingWidgets - StylingCSS Extension languageSASSTheme Utility

Map and ViewMap and View

Map and ViewMap and Viewconstconst map map == newnew MapMap(({{

basemap basemap:: "topo""topo"

}}));;

constconst mView mView == newnew MapViewMapView(({{

map map:: map map,,

container container:: "viewDiv""viewDiv"

}}));;

constconst sView sView == newnew SceneViewSceneView(({{

map map:: map map,,

container container:: "viewDiv""viewDiv"

}}));;

Basemaps and GroundBasemaps and GroundConvenience Strings

constconst map map == newnew MapMap(({{

/*/*

streets, satellite, hybrid, terrain, topo, gray, streets, satellite, hybrid, terrain, topo, gray,

dark-gray, oceans, national-geographic, osm, dark-gray, oceans, national-geographic, osm,

dark-gray-vector, gray-vector, streets-vector, topo-vector, dark-gray-vector, gray-vector, streets-vector, topo-vector,

streets-night-vector, streets-relief-vector, streets-navigation-vector streets-night-vector, streets-relief-vector, streets-navigation-vector

*/ */

basemap basemap:: "streets""streets"

/*/*

world-elevation world-elevation

*/ */

ground ground:: "world-elevation""world-elevation"

}}));;

Basemaps and GroundBasemaps and Groundconstconst map map == newnew MapMap(({{

basemap basemap:: {{

// Layers drawn at the bottom// Layers drawn at the bottom

baseLayers baseLayers:: [[

newnew TileLayerTileLayer(({{ url url:: baselayer baselayer }}))

]],,

// Layers drawn on top// Layers drawn on top

referenceLayers referenceLayers:: [[

newnew TileLayerTileLayer(({{ url url:: refUrl refUrl }}))

]],,

}},,

ground ground:: {{

layers layers:: [[

newnew ElevationLayerElevationLayer(({{ url url:: elevationUrl elevationUrl }}))

]]

Basemap and GroundBasemap and Ground

VT BasemapsA PEN BY odoe

Run Pen

CollectionsCollections

CollectionA PEN BY odoe

Run Pen

esri/core/Collection

Working with AccessorWorking with AccessorObjects are have properties that can be:

read and setor read-onlyconstructor argumentswatchable

Accessor - property accessAccessor - property access

layerlayer..opacity opacity == 0.50.5;;

layerlayer..title title == "My test layer""My test layer";;

// setting multiple values// setting multiple values

layerlayer..setset(({{

opacity opacity:: 0.50.5,,

title title:: "My test layer""My test layer"

}}));;

// accessing the value of a deep property// accessing the value of a deep property

viewview..getget(("map.basemap.title""map.basemap.title"));;

viewview..setset(("map.basemap.title""map.basemap.title",, "new title""new title"));;

Accessor - property watchingAccessor - property watching

mapViewmapView..watchwatch(("scale""scale",, ((newValuenewValue,, oldValue oldValue,, property property,, target target)) =>=> {{

consoleconsole..loglog((`scale changed: `scale changed: ${${newValuenewValue}}`̀));;

}}));;

mapViewmapView..watchwatch(("map.basemap.title""map.basemap.title",, ((newValuenewValue,, oldValue oldValue,, property property,, target target)) =>=> {{

consoleconsole..loglog((`new basemap title: `new basemap title: ${${newValuenewValue}}`̀));;

}}));;

mapViewmapView..watchwatch(("ready, stationary""ready, stationary",, ((newValuenewValue,, oldValue oldValue,, property property,, target target)) =>=> {{

consoleconsole..loglog((`property `property ${${propertyproperty}}: : ${${newValuenewValue}}`̀));;

}}));;

watchUtilswatchUtils..whenTruewhenTrue((viewview,, "stationary""stationary",, (()) =>=> {{

watchUtils

Accessor - autocasting and single constructorAccessor - autocasting and single constructor

// 4.x// 4.x

{{

type type:: "simple-marker""simple-marker",,

style style:: 'square''square',,

color color:: 'red''red',,

size size:: 1010,,

outline outline:: {{

color color:: 'rgba(255, 255, 255, 0.5)''rgba(255, 255, 255, 0.5)'

width width:: 44

}}

}}));;

// 3.x// 3.x

newnew SimpleMarkerSymbolSimpleMarkerSymbol((SimpleMarkerSymbolSimpleMarkerSymbol..STYLE_SQUARESTYLE_SQUARE,, 1010,,

newnew SimpleLineSymbolSimpleLineSymbol((SimpleLineSymbolSimpleLineSymbol..STYLE_SOLIDSTYLE_SOLID,,

PromisesPromises

PromisesPromisesAll asynchronous methods return a promise, no more The basic pattern looks like this:

events

layerlayer..queryFeaturesqueryFeatures((queryquery))..thenthen((handleResulthandleResult))..catchcatch((handleErrorhandleError));;

Promises with async/awaitPromises with async/awaitwork with native promises

constconst doQuerydoQuery == asyncasync ((queryquery)) =>=> {{

constconst results results == awaitawait layer layer..queryFeaturesqueryFeatures((queryquery));;

constconst transformedResults transformedResults == results results..mapmap((transformDatatransformData));;

returnreturn transformedResults transformedResults;;

}}

PromisesPromisesLoad resourcesAsychronously initialized Layer, WebMap, WebScene, View

constconst map map == newnew MapMap(({{......}}))

view view == newnew SceneViewSceneView(({{

map map:: map map,,

//...//...

}}));;

viewview..whenwhen(((()) =>=> {{

// the view is ready to go// the view is ready to go

}}));;

PromisesPromisesviewview..whenwhen(((()) =>=> {{

returnreturn view view..whenLayerViewwhenLayerView((mapmap..findLayerByIdfindLayerById(("awesomeLayer""awesomeLayer"))));;

}}))

..thenthen((layerViewlayerView =>=> {{

returnreturn watchUtils watchUtils..whenFalseOncewhenFalseOnce((layerViewlayerView,, "updating""updating"));;

}}))

..thenthen((resultresult =>=> {{

constconst layerView layerView == result result..targettarget;;

returnreturn layerView layerView..queryFeaturesqueryFeatures(());;

}}))

..thenthen((doSomethingWithFeaturesdoSomethingWithFeatures))

..catchcatch((errorHandlererrorHandler));;

API sample

async/awaitasync/awaitconstconst initinit == asyncasync ((doSomethingWithFeaturesdoSomethingWithFeatures)) =>=> {{

awaitawait view view..whenwhen(());;

constconst layerView layerView == awaitawait view view..whenLayerViewwhenLayerView((mapmap..findLayerByIdfindLayerById(("awesomeLayer""awesomeLayer"))));;

constconst {{ target target asas layerView layerView }} == awaitawait watchUtils watchUtils..whenFalseOncewhenFalseOnce((layerViewlayerView,, "updating""updating"));;

constconst features features == awaitawait layerView layerView..queryFeaturesqueryFeatures(());;

doSomethingWithFeaturesdoSomethingWithFeatures((featuresfeatures));;

}};;

trytry {{

initinit(());;

}}

catchcatch((errorerror)) {{

errorHandlererrorHandler((errorerror));;

}}

PatternsPatterns

Interactivity with view eventsInteractivity with view eventsUse view events to interact with the view

You can stop the propagation of the event to prevent the defaultbehavior

List of events

viewview..onon(("drag""drag",, eventevent =>=> {{

// user won't be able to drag// user won't be able to drag

event event..stopPropagationstopPropagation(());;

}}))

Interactivity with view eventsInteractivity with view eventsAccess the features on click

viewview..onon(("click""click",, (({{ x x,, y y }})) =>=> {{

constconst screenPoint screenPoint == {{xx,, y y}};;

view view..hitTesthitTest((screenPointscreenPoint))

..thenthen((responseresponse =>=> {{

// do something with the result graphic// do something with the result graphic

constconst graphic graphic == response response..resultsresults[[00]]..graphicgraphic;;

}}));;

}}));;

API Sample

goTo() with ViewgoTo() with ViewSets the view to a given target.

Navigate to a geometry/feature/locationAPI Sample

LoadablesLoadablesbrings better control, and scheduling of loading resources.extension of esri/core/Promisein 3.x, instanciating a layer loads it. in 4.0, it's an explicit callthe views automatically loads the map and its layers

LoadablesLoadablesWebMap / WebScene need to load:

the portal itemthe layer modulethe layer's item

MapView / SceneView need to load:the mapthe layers

//In a single page application, get a feature from a FeatureLayer from a WebMap without displaying i//In a single page application, get a feature from a FeatureLayer from a WebMap without displaying i

constconst webmap webmap == newnew WebMapWebMap(({{

portalItem portalItem:: {{

id id:: 'affa021c51944b5694132b2d61fe1057''affa021c51944b5694132b2d61fe1057'

}}

}}));;

webmap webmap..loadload(())

..thenthen(((()) =>=> {{

returnreturn webmap webmap..getLayergetLayer(('myFeatureLayerId''myFeatureLayerId'))..loadload(());;

}}))

..thenthen((featureLayerfeatureLayer =>=> {{

returnreturn featureLayer featureLayer..queryFeaturesqueryFeatures(({{

where where:: 'OBJECTID = 1''OBJECTID = 1'

}}));;

Zoom or ScaleZoom or Scale

Zoom = LOD (Level of Details)Not all LODs are created equal

constconst view view == newnew MapViewMapView(({{

container container:: "viewDiv""viewDiv",,

map map:: map map,,

center center:: [[--116.5116.5,, 33.8033.80]],,

zoom zoom:: 1414 // what does that really mean?// what does that really mean?

}}));;

Zoom is not ScaleZoom is not Scale

Scale is portableScale has meaningWe still snap to closest LOD/zoom

constconst view view == newnew MapViewMapView(({{

container container:: "viewDiv""viewDiv",,

map map:: map map,,

center center:: [[--116.5116.5,, 33.8033.80]],,

scale scale:: 5000050000 // I know what that means!// I know what that means!

}}));;

WebMap is still a MapWebMap is still a Map

Still acts like a regular MapHas some advantages

constconst map map == newnew WebMapWebMap(({{

basemap basemap:: {{ ...... }},,

layers layers:: [[ ...... ]]

}}));;

WebMap is still a MapWebMap is still a Map

Local bookmarksA PEN BY odoe

Run Pen

Sublayer to FeatureLayerSublayer to FeatureLayerYou can extract a FeatureLayer from MapImageLayer Sublayersublayer.createFeatureLayer()Can use capabilities not normally available with Sublayer

Sublayer to FeatureLayerSublayer to FeatureLayer

createFeatureLayerA PEN BY odoe

Run Pen

createQuerycreateQueryWhen you can do layer.createQuery()query object will already have the layers �lters and layerde�nitionsmore consistent

Use new Query() when you don't want prede�ned �lters to beapplied

createQuerycreateQuery

createQueryA PEN BY odoe

Run Pen

MapImageLayerMapImageLayerIf you want to modify Sublayers, do it after you load the layerDe�ning them upfront overrides the defaults

May not be what you want

MapImageLayerMapImageLayer

MapImageLayer - Load SublayersA PEN BY odoe

Run Pen

LayerViewsLayerViewsRenders the LayerWhen is it done though?

hotly debated topic!When can you actually use it!!Behavior different with optimized FeatureLayer

LayerViewsLayerViews

LayerView - ReadyA PEN BY odoe

Run Pen

top related