פיתוח Widget בסביבת הפיתוח של ArcGIS Experience Builder

בגרסת המפתחים של ה-ArcGIS Experience Builder ניתן להוסיף ווידג'טים שאינן חלק מתוכנת המדף, ניתן ליצור נושאים חדשים ובכך לאפשר ליישם אפליקציות עשירות יותר הכוללות פקדים שנתפרו ספציפית לדרישות ושיטות העבודה בארגון שלכם.

מעבר לכך, ה-Builder עדיין לא כולל את כל הפקדים הכלולים ב- ArcGIS JavaScript API 4.X, בבלוג זה נראה איך ניתן לבנות ווידג'ט משלנו המאפשר עבודה עם פקדים שעדיין לא כלולים ב-builder

 איך עושים את זה?

מתחילים בהתקנה מאד פשוטה של הסביבה:

  1. מורידים את ה-zip
  2. פורסים אותו על המחשב שלכם
  3. מתקינים את ה-server ב פקודת npm ci
  4. מתקינים את ה-client בפקודת npm ci

ניתן לקרוא יותר באתר

מפעילים את הסביבה

  1. הפעלת ה-server ב בפקודת npm start
  2. הפעלת ה-client בפקודת npm start

גלישה למחולל היישומים שלכם

https://<FQDN>:3001/

ואפשר להתחיל לפתח…

כמה מילים על הסביבה

JIMU  היא ספריית javaScript שה-builder עובד איתה וכוללת מספר חבילות:

  • jimu-core – אחראית לטעינת האפליקציה לפי ה-config , מנהלת את הגישה למאפיינים, מקורות המידע ועוד
  • jimu-arcgis – אחראית לעבודה עם ה-ArcGIS JavaScript API
  • jimu-ui – אחראית לחווית המשתמש
  • jimu-layout – אחראית לעימוד
  • jimu-for-builder- אחראית לפיתוח ה-setting page

ArcGIS JavaScript API 4.X – מאפשר גישה לכל יכולות ה-jsapi

אם הגעתם עד לכאן אני בטח לא צריכה להסביר לכם מה זה  TypeScript, React, Redux או Webpack…

אז בואו נפתח את סביבת הפיתוח (אני ממליצה על VS Code)  ונתחיל לפתח יחד את הווידג'ט הראשון שלנו…

כאמור, מטרת הווידג'ט שלנו היא עבודה עם פקדי jsapi שאינם כלולים עדיין ב-builder.

כל הפיתוח נעשה תחת ספריית your-extension

תחתיו ישנן 2 ספפריות:widgets ו-themes, רנחנו נעבוד תחת ספריית widgets

העתקת ספריית ה-simple לספריה חדשה

שינוי שם הספרייה ל-EXB

בקובץ ה-manifest.json

  • שינוי השם ל-EXB
  • הוספת תלות ב-jimu-arcgis

על מנת לבנות למיישם טופס בו יוכל לעדכן את מאפייני הווידג'ט עלינו לעושים settings לווידג'ט שלנו כך:

הוספת ספריית setting תחת ה-src

הוספת קובץ setting.tsx תחת ספריית setting

 

והקוד:

import {React, Immutable} from 'jimu-core';

import {AllWidgetSettingProps} from 'jimu-for-builder';

import {TextInput} from "jimu-ui";

import {IMConfig} from "../config";

import {JimuMapViewSelector} from 'jimu-ui/advanced/setting-components';

export default function (props: AllWidgetSettingProps<IMConfig>) {

const onExbPropertyChange = (evt: React.FormEvent<HTMLInputElement>) => {

props.onSettingChange({

id: props.id,

config: props.config.set("exampleConfigProperty",
evt.currentTarget.value)

});

};

const onMapSelected = (useMapWidgetIds: string[]) => {

props.onSettingChange({

id: props.id,

useMapWidgetIds: useMapWidgetIds

});

}

return (

<div>

Choose Map:

<div className="sample-use-map-view-setting p-2" >

<JimuMapViewSelector onSelect={onMapSelected}
useMapWidgetIds={props.useMapWidgetIds} />

</div>

<div className="sample-use-map-view-setting p-2">

exampleConfigProperty:

<TextInput

value={props.config.exampleConfigProperty}

onChange={onExbPropertyChange}

></TextInput>

</div>

</div>

);

}

דגשים:

IMConfig – מפנה להגדות שהוגדרו עבור הווידג'ט שלנו בקובץ ה-config.ts

import { ImmutableObject } from 'seamless-immutable';

export interface Config {

  exampleConfigProperty: string;

}

export type IMConfig = ImmutableObject<Config>;

את הקישור למפה מעדכנים באמצעות JimuMapViewSelector

על מנת לאפשר בטופס ההגדרות לעדכן משתנה מסוג string השתמשנו ב- TextInput

לכל סוגי המאפיינים, מעדכנים את המאפיינים בעזרת הפעלת props.onSettingChange (props הוא מסוג AllWidgetSettingProps)

לאחר שקיבלנו את כל מאפייני הןןידג'ט שלנו אנחנו יכולים לעבור לכתיבה שלו…

הקוד:

/** @jsx jsx */

import { React, AllWidgetProps, jsx } from 'jimu-core';

import { IMConfig } from '../config';

import { JimuMapViewComponent, JimuMapView } from 'jimu-arcgis';

import * as Legend from "esri/widgets/BasemapGallery";

import { useEffect } from 'react';

export default function Widget(props: AllWidgetProps<IMConfig>) {

  let apiWidgetContainer: React.RefObject<HTMLDivElement>;

  let legendWidget: Legend;

  let mapView: __esri.MapView | __esri.SceneView;

  apiWidgetContainer = React.createRef();

  let onActiveViewChange = (jimuMapView: JimuMapView) => {

    if (!(jimuMapView && jimuMapView.view)) {

      return;

    }

    mapView = jimuMapView.view;

    createAPIWidget();

  }

  let createAPIWidget = () => {

    if (!mapView) {

      return;

    }

    if (!legendWidget && apiWidgetContainer && apiWidgetContainer.current) {

      legendWidget = new Legend({

        view: mapView,

        container: apiWidgetContainer.current

      })

    }

  }

  useEffect(() => {

    createAPIWidget();

    return function cleanup() {

      if(legendWidget){

        legendWidget.destroy();

        legendWidget = null;

      }

    };

  });

  return (

    <div className="widget-demo jimu-widget m-2">

      <p>Simple Widget</p>

      <h3>{props.config.exampleConfigProperty}</h3>

      <JimuMapViewComponent

        useMapWidgetIds={props.useMapWidgetIds}

        onActiveViewChange={onActiveViewChange}></JimuMapViewComponent>

      {(!props.useMapWidgetIds || props.useMapWidgetIds.length < 1) ?

        "בחר מפה" :

        <div ref={apiWidgetContainer}></div>}

    </div>

  );

}

דגשים:

import { JimuMapViewComponent, JimuMapView } from 'jimu-arcgis';

import * as Legend from "esri/widgets/BasemapGallery";

הפניה ל-mapview מתבצעץ באמצעות המעטפת של JimuMapViewComponent המוסיפה את כל הנדרש לנו לקישור ולעבודה עםווידג'טים אך עדיין חושפת לנו את אותו mapView או sceneView שאנחנו מכירים מהעבודה עם ה-jsapi

מאחר וההדגמה נבנתה במקור לעבודה עם Legend כך קראנו ב-alias לפקד שלנו אך כל פקד של ה-jsapi שנפנה אליו (בקוד למעלה פונה ל- esri/widgets/BasemapGallery) יוכל לעבוד אם כל הנדרש להפעלתו זה הגדרת view ו-container (בהדגמה ראינו עבודה עם measure,legend ויש עוד).

useEffect – HOOK מאפשר בדומה ל componentDidMount and componentDidUpdate המוכרים מעבודה עם class לפעול לאחר טעינת הקומפוננטה.

React.createRef בשילוב עם הגדרת ref ל-div שחוזר מהפונקציה, מאפשר פניה ישירה למקום בקונטרול שלנו לצורך אכלוסו עם הפקד שלנו.

מאחר וקוד זה מדגים לנו רק כיצד להוסיף פקד של jsapi למפה, כצעד המשך אני ממליצה להוריד את הדוגמאות מאתר ה-github ולעבור באופן ספציפי על הווידג'ט get-map-coordinates-function.
בדוגמה זו ניתן לראות שילוב של עבודה עם events ו-watch על מאפיינים של פקד ה-view של ה-jsapi.
כמו כן, מדגים גם שימוש ב-useState HOOK.

לסיכום, כמה לינקים שחשוב שתכירו (אם עדיין לא הכרתם):

לכניסה לדף הבית – לחצו כאן

לכניסה ל- GITHUB

לכניסה ל- JSAPI

קישור להורדת קובץ ZIP פרויקט הקוד

ונסיים בברכת HAPPY CODING 😊