Using Frameworks with the ArcGIS API for...

Post on 02-Nov-2018

284 views 0 download

Transcript of Using Frameworks with the ArcGIS API for...

UsingFrameworkswiththeArcGISAPIforJavaScriptRenéRubalcava

@odoenet

AgendaOptionsAngularEmberReactVueJSElm

Options

TemplatesEasytouseConfigurableIntegrateswithPortal

WebAppBuilderCanbethoughtofasitsownframeworkjimu-theLegoframework

ArcGISJSAPIWidgetFramework

BasedonTypeScriptJSX

CustomWidgetDevelopmentMaquetteJS

Whyuseaframework?SimplifyworkflowAllteamsonsamepage

ChallengesJSAPIAMDLoaderMostissueswithloaderpluginsWehavesolutionsformosttooling!

define([ "dojo/has!webgl?esri/package1:esri/package2"], function(myDrawingPackage) {...});

Angular

FeaturesDirectivesareWebComponentsDependencyInjectionRxJSUsesTypeScript

SystemJS

esri-system-js esriSystem.register( // array of Esri module names to load and then register with SystemJS [ 'esri/Map', 'esri/views/SceneView', 'esri/layers/FeatureLayer' ], // optional callback function function() { // then bootstrap application System.import('app/main') .then(null, console.error.bind(console)); });

github

Componentimport { Component } from '@angular/core';

@Component({ selector: 'my-app', styles: [` section { width: 100%; margin: 0 auto; padding: 4em 0 0 0; } `], template: ` <main> <section> <esri-scene-view></esri-scene-view> </section> </main> `})export class AppComponent { }

Injectableimport { Injectable } from "@angular/core";

import EsriMap from "esri/Map";

@Injectable()export class SimpleMapService { map: EsriMap; constructor() { this.map = new EsriMap({ basemap: "satellite", ground: "world-elevation" }); }}

DependencyInjectionimport { Component, ElementRef, Input, Output, EventEmitter } from "@angular/core";import SceneView from "esri/views/SceneView";import { SimpleMapService } from "./map.services";

@Component({ selector: "esri-scene-view", template: `<div id="viewDiv" style="height:600px"><ng-content></ng-content></div>`, providers: [SimpleMapService]})export class EsriSceneViewComponent { @Output() viewCreated = new EventEmitter();

view: any = null;

constructor( private _mapService: SimpleMapService, private elRef: ElementRef ) {}

ngOnInit() { this.view = new SceneView({ container: this.elRef.nativeElement.firstChild, map: this._mapService.map, camera: {...}

AngularLotsofiterationssinceannouncedStabilizing

Ember

FeaturesTheEmberWay

Emberwayorgetouttheway!FocusonWebComponents

Robustadd-onsystemGreatforteams!

ember-cli

Weuseit!OperationsDashboardOpenDataWorkforceWebApp

ChallengesUsesit'sownsynchronousAMD-likeloaderDoesn'tlikeRequireJSorDojoloaders

Solutions!Sowewroteanaddontohelpwiththatember-cli-amd

Configureember install ember-cli-amdvar EmberApp = require('ember-cli/lib/broccoli/ember-app');module.exports = function(defaults) { var app = new EmberApp(defaults, { amd :{ loader: 'https://js.arcgis.com/4.3/', packages: [ 'esri','dojo','dojox','dijit', 'moment', 'dgrid', 'dstore' ] } }); return app.toTree();};

MapasaServiceimport Ember from 'ember';import EsriMap from 'esri/Map';

export default Ember.Service.extend({ map: null,

loadMap() { let map = this.get('map'); if (map) { return map; } else { map = new EsriMap({ basemap: 'hybrid', ground: 'world-elevation' }); this.set('map', map); return map; } }});

Componentimport Ember from 'ember';import SceneView from 'esri/views/SceneView';

export default Ember.Component.extend({

classNames: ['viewDiv'],

mapService: Ember.inject.service('map'),

didInsertElement() { let map = this.get('map'); if (!map) { map = this.get('mapService').loadMap(); this.set('map', map); } },

createMap: function() { let map = this.get('map'); let view = new SceneView({ map, container: this.elementId, center: [-101.17, 21.78], zoom: 10

AddComponent

Magic

{{esri-map}}

EmberLargecommunityFlexibleecosystemLotsofaddons!

React

FeaturesTechnically,notaframeworkReusable,composablecomponentsJSX-declarative

Componentsclass Recenter extends React.Component<Props, State> { state = { x: 0, y: 0, interacting: false }; ... render() { let style: Style = { textShadow: this.state.interacting ? '-1px 0 red, 0 1px red, 1px 0 red, 0 -1px red' : '' }; let { x, y } = this.state; return ( <div className='recenter-tool' style={style} onClick={this.defaultCenter}> <p>x: {Number(x).toFixed(3)}</p> <p>y: {Number(y).toFixed(3)}</p> </div> ); }}

Composeview.then(() => { ReactDOM.render( <div> <Recenter view={view} initialCenter={[-100.33, 25.69]} /> </div>, document.getElementById('appDiv') );}, (err: Error) => { console.warn('Error: ', err);});

StateManagementforReact

-Reactcli

ReduxMobXCreateReactApp

Canuseesri-loadercreateMap() { dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => { new MapView({ container: this.refs.mapView, map: new Map({basemap: 'topo'}) }) });}componentWillMount() { if (!isLoaded()) { bootstrap((err) => { if (err) { console.error(err) } this.createMap(); }, { url: 'https://js.arcgis.com/4.3/' }); } else { this.createMap(); }}

ReactVerypopular,largecommunityHasonejobVarietyofwaysitcanbeused

VueJS

FeaturesNotaframework,butsosoniceBuildcomponentsSimpleSmall(under20kb)

EasytointegrateVue.component("camera-info", { props: ["camera"], template: "<div>" + "<h2>Camera Details</h2>" + "<p><strong>Heading</strong>: {{ camera.heading.toFixed(3) }}</p>" + "<p><strong>Tilt</strong>: {{ camera.tilt.toFixed(3) }}</p>" + "<p><strong>Latitude</strong>: {{ camera.position.latitude.toFixed(2) }}</p>" + "<p><strong>Longitude</strong>: {{ camera.position.longitude.toFixed(2) }}</p>" + "</div>"});view.then(function() { var info = new Vue({ el: "#info", data: { camera: view.camera } }); view.ui.add(info.$el, "top-right"); view.watch("camera", function() { info.camera = view.camera; });});

Hasacli!Usestemplates!

<template> ... <div id="viewDiv"></div> ...</template>

Canuseesri-loaderimport * as esriLoader from 'esri-loader'export default { ... mounted () { const createMap = () => { esriLoader.dojoRequire([ 'esri/Map', 'esri/views/SceneView', 'esri/core/watchUtils' ], (EsriMap, SceneView, watchUtils) => { ... return view }) } ... }, ...}

vue-clidemo

Elm

FeaturesPurelyFunctionalLanguageAlsoaFrameworkCrazyrightStaticallytypeddescribetheshapeofyourvalue

ElmArchitectureModel—thestateofyourapplicationUpdate—awaytoupdateyourstateView—awaytoviewyourstateasHTML

Modeltype alias Model = { items : List Card }

type alias Card = { id : String , title : String , thumbnailUrl : Maybe String , itemUrl : String , snippet : Maybe String , selected : Bool }

Updatetype Msg = Select String | UpdateSave String Int | Change Model

update : Msg -> Model -> ( Model, Cmd Msg )update msg model = case msg of Change newItems -> ( newItems, Cmd.none )

UpdateSave itemid rating -> model ! [] |> andThen update (Select itemid) ...

UpdateSelect itemid -> let selected t = if t.id == itemid then { t | selected = True } else { t | selected = False }

findCard itemid = let valid val = case val of Nothing -> sampleCard

Just val -> val

card = model.items |> List.filter (\x -> x.id == itemid) |> List.head in valid card

ViewviewCard : Card -> Html MsgviewCard card = ... div [ class cardStyle ] [ figure [ class "card-image-wrap" ] [ img [ class "card-image" , card.thumbnailUrl |> showVal |> src ] [] , div [ class "card-image-caption" ] [ text card.title ] ] , div [ class "card-content" ] [ card.snippet |> showVal |> text , div [ class "btn btn-fill leader-1" , onClick (Select card.id) ]

Lookingforward

Dojo2multiplepackages

willhave dojo-clidojo/corestillBeta

TypeScript2.2introduced and object typeFutureupdates

mixins

NotableMentions

-hyperscriptRiotMithrilCycle

Questions?Helpustoimprovefillingoutthesurvey

ReneRubalcava( )

Slides:

@odoenet

github.com/odoe/presentations/2017-devsummit-ps-using-frameworks/