Веб-компоненты
Если вы хоть сколько-нибудь долго создаете веб-приложения, вы наверняка сталкивались с веб-компонентами. Веб-компоненты могут многое предложить. Они позволяют создать набор общих компонентов, которые можно использовать везде, независимо от используемого фреймворка. Я не буду подробно останавливаться на этом, но хочу подчеркнуть, что вы можете использовать библиотеку Web-компонентов, например Calcite Components, в своих собственных приложениях. Сегодня использовать Web-компоненты в некоторых фреймворках проще, чем в других. Одним из самых дружелюбных является Svelte.
В этом посте мы будем следовать этому руководству по Calcite Components, чтобы создать картографическое приложение, но с использованием Svelte!
Исходный код для демонстрации в этой статье находится на github.
Начало работы
Вы можете прочитать отличное введение по использованию Svelte с ArcGIS API for JavaScript в блоге Esri.
Мы можем начать создание приложения Svelte с помощью Vite, и да, я использую Vite практически для всего.
npm init @vitejs/app svelte-calcite
cd svelte-calcite
npm install @arcgis/core
После установки мы можем установить ArcGIS API for JavaScript. Вместе с ним будет установлена библиотека Calcite Components. На этом этапе мы можем очистить файлы css и .svelte
в приложении scaffold. Мы можем добавить несколько основных CSS для начала работы.
/** app.css **/
@import "https://js.arcgis.com/calcite-components/1.0.0-beta.86/calcite.css";
@import "https://js.arcgis.com/4.24/esri/themes/light/main.css";
html,
body,
#app {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
Создание картографического приложения
Затем мы можем начать обновлять наш компонент App.svelte
, следуя руководству по созданию картографического приложения. Мы можем просто начать с HTML-скелета приложения.
<calcite-shell content-behind>
<h2 id="header-title" slot="header">
<!-- Dynamically populated -->
</h2>
<calcite-shell-panel slot="primary-panel" detached>
</calcite-shell-panel>
<div class="viewDiv"></div>
</calcite-shell>
Это базовая оболочка для приложения, но нам все еще нужно подключить ее к некоторым другим компонентам, чтобы отобразить карту.
<script>
// calcite components
import "@esri/calcite-components/dist/components/calcite-shell";
import "@esri/calcite-components/dist/components/calcite-shell-panel";
// arcgis js api
import config from "@arcgis/core/config";
import WebMap from "@arcgis/core/WebMap";
import MapView from "@arcgis/core/views/MapView";
import { onMount } from "svelte";
config.apiKey = import.meta.env.VITE_API_KEY;
let viewContainer;
let item = {};
onMount(() => {
const map = new WebMap({
portalItem: {
id: "cc3bd744b9a44feaa493dd867a1d48dd",
},
});
const view = new MapView({
container: viewContainer,
map,
padding: {
left: 49,
},
});
view.ui.move("zoom", "bottom-right");
map.when(() => {
item = map.portalItem;
});
});
</script>
Для начала мы делаем несколько вещей. Во-первых, мы импортируем модули из Calcite Components, которые мы уже использовали в нашем приложении. Если мы этого не сделаем, они не зарегистрируются как пользовательские элементы и не будут отображаться. Затем мы определяем пару переменных, на которые можно ссылаться на странице. В Svelte есть очень четкий способ привязки переменных и придания им реактивности. Это глоток свежего воздуха, исходящий от некоторых других фреймворков. Переменная viewContainer
будет использоваться как ссылка на элемент, в котором мы можем отобразить нашу карту, а объект item
может быть использован для отображения текста.
<calcite-shell content-behind>
<h2 id="header-title" slot="header">
{item.title || "...loading"}
</h2>
<calcite-shell-panel slot="primary-panel" detached>
</calcite-shell-panel>
<div class="viewDiv" bind:this={viewContainer} />
</calcite-shell>
Обратите внимание, что мы просто ссылаемся на item.title
, и когда мы обновим эту переменную, она будет отражена на нашей странице. Мы используем синтаксис bind:this
для привязки переменной viewContainer
к элементу div. Синтаксис this
относится к элементу, для которого вы используете синтаксис bind:
. Мне очень нравится этот API.
Следующим шагом в этом руководстве будет настройка панели действий и панелей, куда будет помещен виджет.
<calcite-shell content-behind>
<h2 id="header-title" slot="header">
{item.title || "...loading"}
</h2>
<calcite-shell-panel slot="primary-panel" detached>
<calcite-action-bar slot="action-bar">
<calcite-action data-action-id="layers" icon="layers" text="Layers" />
<calcite-action
data-action-id="basemaps"
icon="basemap"
text="Basemaps"
/>
<calcite-action data-action-id="legend" icon="legend" text="Legend" />
<calcite-action
data-action-id="bookmarks"
icon="bookmark"
text="Bookmarks"
/>
<calcite-action data-action-id="print" icon="print" text="Print" />
<calcite-action
data-action-id="information"
icon="information"
text="Information"
/>
</calcite-action-bar>
<calcite-panel
heading="Layers"
height-scale="l"
data-panel-id="layers"
hidden
>
<div id="layers-container" bind:this={layerListContainer} />
</calcite-panel>
<calcite-panel
heading="Basemaps"
height-scale="l"
data-panel-id="basemaps"
hidden
>
<div id="basemaps-container" bind:this={bmgContainer} />
</calcite-panel>
<calcite-panel
heading="Legend"
height-scale="l"
data-panel-id="legend"
hidden
>
<div id="legend-container" bind:this={legendContainer} />
</calcite-panel>
<calcite-panel
heading="Bookmarks"
height-scale="l"
data-panel-id="bookmarks"
hidden
>
<div id="bookmarks-container" bind:this={bookmarksContainer} />
</calcite-panel>
<calcite-panel
heading="Print"
height-scale="l"
data-panel-id="print"
hidden
>
<div id="print-container" bind:this={printContainer} />
</calcite-panel>
<!-- Info panel (populates with info from the web map) -->
<calcite-panel heading="Details" data-panel-id="information" hidden>
<div id="info-content">
<img
id="item-thumbnail"
alt="webmap thumbnail"
src={item.thumbnailUrl}
/>
<div id="item-description">
<!-- Dynamically populated -->
{item.description}
</div>
<calcite-label layout="inline">
<b>Rating:</b>
<calcite-rating id="item-rating" read-only>
<!-- Dynamically populated -->
{item.avgRating}
</calcite-rating>
</calcite-label>
</div>
</calcite-panel>
</calcite-shell-panel>
<div class="viewDiv" bind:this={viewContainer} />
</calcite-shell>
Итак, теперь мы многое добавили. У нас есть еще несколько компонентов и панель действий, которая позволяет нам добавлять кнопки и переключать видимость некоторых виджетов. Мы используем тот же синтаксис bind:this
, который мы использовали ранее. Поскольку мы добавили больше компонентов, нам нужно импортировать еще несколько модулей, плюс мы можем начать инициализацию наших виджетов.
<script>
// calcite components
import "@esri/calcite-components/dist/components/calcite-shell";
import "@esri/calcite-components/dist/components/calcite-shell-panel";
import "@esri/calcite-components/dist/components/calcite-action";
import "@esri/calcite-components/dist/components/calcite-action-bar";
import "@esri/calcite-components/dist/components/calcite-panel";
import "@esri/calcite-components/dist/components/calcite-label";
import "@esri/calcite-components/dist/components/calcite-rating";
// arcgis js api
import config from "@arcgis/core/config";
import WebMap from "@arcgis/core/WebMap";
import MapView from "@arcgis/core/views/MapView";
import Bookmarks from "@arcgis/core/widgets/Bookmarks";
import BasemapGallery from "@arcgis/core/widgets/BasemapGallery";
import LayerList from "@arcgis/core/widgets/LayerList";
import Legend from "@arcgis/core/widgets/Legend";
import Print from "@arcgis/core/widgets/Print";
import { onMount } from "svelte";
config.apiKey = import.meta.env.VITE_API_KEY;
let viewContainer;
let bookmarksContainer;
let bmgContainer;
let layerListContainer;
let legendContainer;
let printContainer;
let item = {};
onMount(() => {
const map = new WebMap({
portalItem: {
id: "cc3bd744b9a44feaa493dd867a1d48dd",
},
});
const view = new MapView({
container: viewContainer,
map,
padding: {
left: 49,
},
});
view.ui.move("zoom", "bottom-right");
const basemaps = new BasemapGallery({
view,
container: bmgContainer,
});
const bookmarks = new Bookmarks({
view,
container: bookmarksContainer,
});
const layerList = new LayerList({
view,
selectionEnabled: true,
container: layerListContainer,
});
const legend = new Legend({
view,
container: legendContainer,
});
const print = new Print({
view,
container: printContainer,
});
map.when(() => {
item = map.portalItem;
});
});
</script>
На данный момент наше приложение почти готово. За исключением того, что у нас пока нет возможности переключать виджеты. В учебнике по отображению есть синтаксис кода, который мы можем использовать в точности как есть.
let activeWidget;
const handleActionBarClick = ({ target }) => {
if (target.tagName !== "CALCITE-ACTION") {
return;
}
if (activeWidget) {
document.querySelector(`[data-action-id=${activeWidget}]`).active = false;
document.querySelector(`[data-panel-id=${activeWidget}]`).hidden = true;
}
const nextWidget = target.dataset.actionId;
if (nextWidget !== activeWidget) {
document.querySelector(`[data-action-id=${nextWidget}]`).active = true;
document.querySelector(`[data-panel-id=${nextWidget}]`).hidden = false;
activeWidget = nextWidget;
} else {
activeWidget = null;
}
};
Нам просто нужно добавить слушателя событий на панель действий.
<calcite-action-bar slot="action-bar" on:click={handleActionBarClick}>
...
</calcite-action-bar>
Синтаксис on:eventname
— это то, как вы можете добавлять слушателей событий в Svelte.
Теперь наше приложение завершено, и вы можете просматривать карту и переключать виджеты.
Резюме
Я не являюсь опытным пользователем Svelte, но он быстро набирает обороты. Любой фреймворк, который может облегчить мне использование веб-компонентов, мне нравится. Calcite Components также является отличной библиотекой веб-компонентов для создания приложений ArcGIS Platform.
Вы можете посмотреть это видео для получения дополнительной информации!