esrieact 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +309 -0
- package/dist/core/Graphic.d.ts +16 -0
- package/dist/core/Graphic.js +67 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +3 -0
- package/dist/core/renderers/Renderer.d.ts +11 -0
- package/dist/core/renderers/Renderer.js +11 -0
- package/dist/core/renderers/SimpleRenderer.d.ts +11 -0
- package/dist/core/renderers/SimpleRenderer.js +12 -0
- package/dist/core/renderers/UniqueValueRenderer.d.ts +12 -0
- package/dist/core/renderers/UniqueValueRenderer.js +12 -0
- package/dist/core/renderers/createRendererComponent.d.ts +13 -0
- package/dist/core/renderers/createRendererComponent.js +63 -0
- package/dist/core/renderers/index.d.ts +4 -0
- package/dist/core/renderers/index.js +4 -0
- package/dist/core/symbols/PictureMarkerSymbol.d.ts +9 -0
- package/dist/core/symbols/PictureMarkerSymbol.js +43 -0
- package/dist/core/symbols/SimpleFillSymbol.d.ts +9 -0
- package/dist/core/symbols/SimpleFillSymbol.js +34 -0
- package/dist/core/symbols/index.d.ts +2 -0
- package/dist/core/symbols/index.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/layers/FeatureLayer.d.ts +27 -0
- package/dist/layers/FeatureLayer.js +13 -0
- package/dist/layers/GraphicsLayer.d.ts +14 -0
- package/dist/layers/GraphicsLayer.js +13 -0
- package/dist/layers/GroupLayer.d.ts +14 -0
- package/dist/layers/GroupLayer.js +30 -0
- package/dist/layers/ImageryLayer.d.ts +14 -0
- package/dist/layers/ImageryLayer.js +13 -0
- package/dist/layers/ImageryTileLayer.d.ts +14 -0
- package/dist/layers/ImageryTileLayer.js +13 -0
- package/dist/layers/KMLLayer.d.ts +14 -0
- package/dist/layers/KMLLayer.js +13 -0
- package/dist/layers/LayerView.d.ts +52 -0
- package/dist/layers/LayerView.js +70 -0
- package/dist/layers/VectorTileLayer.d.ts +14 -0
- package/dist/layers/VectorTileLayer.js +13 -0
- package/dist/layers/WMSLayer.d.ts +14 -0
- package/dist/layers/WMSLayer.js +13 -0
- package/dist/layers/WebTileLayer.d.ts +14 -0
- package/dist/layers/WebTileLayer.js +13 -0
- package/dist/layers/createLayerComponent.d.ts +36 -0
- package/dist/layers/createLayerComponent.js +54 -0
- package/dist/layers/index.d.ts +11 -0
- package/dist/layers/index.js +11 -0
- package/dist/map/MapView.d.ts +144 -0
- package/dist/map/MapView.js +109 -0
- package/dist/map/index.d.ts +1 -0
- package/dist/map/index.js +1 -0
- package/dist/symbols/SymbolPreview.d.ts +16 -0
- package/dist/symbols/SymbolPreview.js +21 -0
- package/dist/symbols/index.d.ts +1 -0
- package/dist/symbols/index.js +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +30 -0
- package/dist/utils/useEsriPropertyUpdates.d.ts +10 -0
- package/dist/utils/useEsriPropertyUpdates.js +26 -0
- package/dist/utils/useEvents.d.ts +20 -0
- package/dist/utils/useEvents.js +38 -0
- package/dist/utils/usePrevious.d.ts +2 -0
- package/dist/utils/usePrevious.js +9 -0
- package/dist/widgets/BasemapGallery.d.ts +14 -0
- package/dist/widgets/BasemapGallery.js +13 -0
- package/dist/widgets/Expand.d.ts +14 -0
- package/dist/widgets/Expand.js +15 -0
- package/dist/widgets/LayerList/ListItem.d.ts +14 -0
- package/dist/widgets/LayerList/ListItem.js +13 -0
- package/dist/widgets/LayerList/index.d.ts +14 -0
- package/dist/widgets/LayerList/index.js +13 -0
- package/dist/widgets/Legend.d.ts +14 -0
- package/dist/widgets/Legend.js +15 -0
- package/dist/widgets/SearchBar.d.ts +14 -0
- package/dist/widgets/SearchBar.js +13 -0
- package/dist/widgets/Sketch.d.ts +24 -0
- package/dist/widgets/Sketch.js +13 -0
- package/dist/widgets/createWidgetComponent.d.ts +29 -0
- package/dist/widgets/createWidgetComponent.js +47 -0
- package/dist/widgets/index.d.ts +7 -0
- package/dist/widgets/index.js +7 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">ESRIEACT</h1>
|
|
3
|
+
</p>
|
|
4
|
+
<p align="center">
|
|
5
|
+
A react component library for the ArcGIS Javascript API.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
## 📘 [Read the Docs (Work in Progress!)](https://slutske22.github.io/esrieact/)
|
|
9
|
+
|
|
10
|
+
## File Organization
|
|
11
|
+
|
|
12
|
+
- `/lib` contains actual map component files that are the source code and main feature of this repository
|
|
13
|
+
- `/src` is simply an example application to showcase the code written in `/lib`
|
|
14
|
+
|
|
15
|
+
## Why?
|
|
16
|
+
|
|
17
|
+
The goal of wrapping ArcGIS JS API components in react wrappers is to maintain a react-style flow of data, i.e. state and prop changes cause components to react and auto-update. For example, rendering a map, or map components, normally requires many `useEffect` calls:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import React, { useEffect } from "react";
|
|
21
|
+
import Map from "@arcgis/core/Map";
|
|
22
|
+
import MapView from "@arcgis/core/views/MapView";
|
|
23
|
+
|
|
24
|
+
export const EffectBasedMap: React.FC = () => {
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const map = new Map({
|
|
27
|
+
basemap: "topo-vector",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
new MapView({
|
|
31
|
+
container: "map-div",
|
|
32
|
+
map,
|
|
33
|
+
});
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return <div id="map-div" />;
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
While the above is not terribly complex or ugly, mangaging map state with React is more complex as we add more ESRI components. For example, keeping the map up to date with a list of layers requires some confusing `useEffect`s:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
export const EffectBasedMap: React.FC = ({ layerList }) => {
|
|
44
|
+
const [map, setMap] = useState<__esri.Map>();
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const map = new Map({
|
|
48
|
+
basemap: "topo-vector",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
new MapView({
|
|
52
|
+
container: "map-div",
|
|
53
|
+
map,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
setMap(map);
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (map) {
|
|
61
|
+
layerList.forEach((layer) => {
|
|
62
|
+
if (!map.layers.map((l) => l.id).includes(layer.id)) {
|
|
63
|
+
map.add(layer);
|
|
64
|
+
}
|
|
65
|
+
// We would also need some ugly logic here to test if the map has
|
|
66
|
+
// layers that are not part of the new layer list prop
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}, [map, layerList]);
|
|
70
|
+
|
|
71
|
+
return <div id="map-div" />;
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Instead, wrapper components are available to make map presentation clear and declarative:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import React from "react";
|
|
79
|
+
import { FeatureLayer, MapView } from "./esri";
|
|
80
|
+
|
|
81
|
+
export const ReactMap: React.FC = ({ layerList }) => {
|
|
82
|
+
return (
|
|
83
|
+
<MapView>
|
|
84
|
+
{layerList.map((layer) => (
|
|
85
|
+
<FeatureLayer url={layer.url} />
|
|
86
|
+
))}
|
|
87
|
+
</MapView>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The wrappers for ESRIEACT components often do not render anything, but rather simply use react lifecycle methods to manage the interaction of an ESRI component to the map. If children of a component are needed, ESRIEACT components render a context object that provides the ESRI instance to any children.
|
|
93
|
+
|
|
94
|
+
### What about ESRI's react library?
|
|
95
|
+
|
|
96
|
+
ESRI recently released [@arcgis/map-components-react](https://www.npmjs.com/package/@arcgis/map-components-react), which offers some support for ArcGIS components in react. Their [documentation](https://developers.arcgis.com/javascript/latest/get-started-react/) shows a basic example, but in the current early stage of this library, react components for map layers, renderers, graphics, etc, do not exist, and must still be added to a map using the classic imperative programming style.
|
|
97
|
+
|
|
98
|
+
## Props
|
|
99
|
+
|
|
100
|
+
Vanilla ESRI component properties are class-based, and often circular. For example:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// Using vanilla ArcGIS JS API
|
|
104
|
+
|
|
105
|
+
const view = new MapView({
|
|
106
|
+
extent: new Extent({
|
|
107
|
+
xmin: 10,
|
|
108
|
+
xmax: 100,
|
|
109
|
+
ymin: -20,
|
|
110
|
+
ymax: 120,
|
|
111
|
+
spatialReference: new SpatialReference({
|
|
112
|
+
wkid: 102100,
|
|
113
|
+
}),
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Beacuse react-wrapped ESRI component props extend directly from ESRI class options, this would technically work:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import React from "react";
|
|
122
|
+
import { FeatureLayer, MapView } from "./esri";
|
|
123
|
+
|
|
124
|
+
export const ReactMap: React.FC = ({ layerList }) => {
|
|
125
|
+
return (
|
|
126
|
+
<MapView
|
|
127
|
+
extent={new Extent({
|
|
128
|
+
xmin: 10,
|
|
129
|
+
xmax: 100,
|
|
130
|
+
ymin: -20,
|
|
131
|
+
ymax: 120,
|
|
132
|
+
spatialReference: new SpatialReference({
|
|
133
|
+
wkid: 102100
|
|
134
|
+
})
|
|
135
|
+
})}
|
|
136
|
+
/>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
However, any propery then updated within the above `new Extent` would not register as a property change with react. The reason for this is that many ArcGIS class-based instance properties and [non-Enumerable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties), and as such, React will not know they have been changed, and will not update the property accordingly. For example, this will not work as expected:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import React from "react";
|
|
145
|
+
import { FeatureLayer, MapView } from "./esri";
|
|
146
|
+
import FeatureEffect from '@arcgis/core/layers/FeatureEffect'
|
|
147
|
+
import FeatureFilter from '@arcgis/core/layers/FeatureFilter'
|
|
148
|
+
|
|
149
|
+
export const ReactMap: React.FC = ({ layerList }) => {
|
|
150
|
+
const [clause, setClause] = useState("SOME SQL CLAUSE");
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<MapView>
|
|
154
|
+
<FeatureLayer featureEffect={new FeatureEffect({
|
|
155
|
+
filter: new FeatureFilter({
|
|
156
|
+
where: clause
|
|
157
|
+
})
|
|
158
|
+
})} />
|
|
159
|
+
</MapView>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Because the property being updated is deeply nested within class-based ESRI components, whose resultant properties are non-enumerable, react will not sense the change and will not update the component. However, most ESRI component properties accept simple objects as option parameters in place of class constructors:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import React from "react";
|
|
168
|
+
import { FeatureLayer, MapView } from "./esri";
|
|
169
|
+
|
|
170
|
+
export const ReactMap: React.FC = ({ layerList }) => {
|
|
171
|
+
const [clause, setClause] = useState("SOME SQL CLAUSE");
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<MapView>
|
|
175
|
+
<FeatureLayer featureEffect={{
|
|
176
|
+
filter: {
|
|
177
|
+
where: clause
|
|
178
|
+
}
|
|
179
|
+
}} />
|
|
180
|
+
</MapView>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
It is prefereable to use this second syntax in this codebase. (Though in the case of trying to filter a FeatureLayer, it is preferable to use a [definitionExpression](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html#definitionExpression) for server-side filtering, or a `<FeatureLayerView />` component with a `filter` applied for front-end filtering).
|
|
186
|
+
|
|
187
|
+
## Context
|
|
188
|
+
|
|
189
|
+
Many components provide, and rely on, parent contexts. For example, a `Mapview` provides a context that can be consumed by all children of the map, so that those children have access to the underlying esri Map instance. Similarly, even sub-components like layers or widgets provide a context object, whose value is simply the instance of the esri class instance being wrapped.
|
|
190
|
+
|
|
191
|
+
## Utility factory functions
|
|
192
|
+
|
|
193
|
+
Factory functions help to quickly create layer and widget components. They are inspired largely by [react-leaflet's core architecture](https://react-leaflet.js.org/docs/core-introduction/).
|
|
194
|
+
|
|
195
|
+
Layer components should be created by using the `createLayerComponent` function. Widget components should be created using the `createWidgetComponent` function. Use of these factory functions may need to be tweaked, especially for complex widgets with different sub-components. Use these as a starting point for wrapping esri components in react lifecycle methdos.
|
|
196
|
+
|
|
197
|
+
## Major Components
|
|
198
|
+
|
|
199
|
+
### `MapView`
|
|
200
|
+
|
|
201
|
+
A `MapView` is a react component which combines both an ESRI [Map](https://developers.arcgis.com/javascript/latest/api-reference/esri-Map.html) and a [MapView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html) into a singular component. It will render a div, and once rendered, use it to render an ArcGIS JS API MapView. `MapView` accepts all `HTMLAttributes<HTMLDivElement>` properties, as well as optional `MapProperties` and `ViewProperties`, which allow you to set the inital `Map` and `MapView` options:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const Page: React.FC = () => {
|
|
205
|
+
return (
|
|
206
|
+
<MapView
|
|
207
|
+
id="standard-html-id-for-wrapper-div"
|
|
208
|
+
style={{ /* use this to ensure map is the size you need */ }}
|
|
209
|
+
MapProperties={{ basemap: "topo-vector" }}
|
|
210
|
+
ViewProperties={{ extent: SOME_EXTENT_OBJECT }}
|
|
211
|
+
/>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `MapContextProvider`
|
|
217
|
+
|
|
218
|
+
In order for `<MapView />` child components to be properly associated with the underlying `map` and `view` instances, a `<MapView />` provides its own `MapContextProvider` wrapper out of the box. However, if you find that you need to access the `map` and `view` from outside the `<MapView />` component, you can instead use the `MapViewCore` wrapped in the `MapContextProvider`:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
// App.tsx
|
|
222
|
+
import { MapViewCore, MapContextProvider } from 'lib/map/MapView';
|
|
223
|
+
|
|
224
|
+
const App = () => {
|
|
225
|
+
// Wrap MapViewCore and other components that need access to the map context
|
|
226
|
+
return (
|
|
227
|
+
<MapContextProvider>
|
|
228
|
+
<MapViewCore />
|
|
229
|
+
<OtherUI />
|
|
230
|
+
</MapContextProvider>
|
|
231
|
+
)
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// OtherUI.tsx
|
|
235
|
+
import { useContext } from 'react';
|
|
236
|
+
import { MapContext } from 'lib/map/MapView';
|
|
237
|
+
|
|
238
|
+
const OtherUI = () => {
|
|
239
|
+
const { view } = useContext(MapContext);
|
|
240
|
+
return <button onClick={() => view.zoom = view.zoom + 1}>Zoom in!</button>
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### `FeatureLayer`
|
|
245
|
+
|
|
246
|
+
One of the most used layer types is the `FeatureLayer`. A `FeatureLayer` can be declared alone, or can accept a `FeatureLayerView` as a child to help taylor the layer:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
import React from "react";
|
|
250
|
+
import { FeatureLayer, FeautureLayerView, MapView } from "./esri";
|
|
251
|
+
|
|
252
|
+
export const ReactMap: React.FC = () => {
|
|
253
|
+
const flRef = useRef<__esri.FeatureLayer>();
|
|
254
|
+
const flViewRef = useRef<__esri.FeatureLayerView>();
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<MapView>
|
|
258
|
+
{/* A simple featurelayer: */}
|
|
259
|
+
<FeatureLayer url="some service url" />
|
|
260
|
+
|
|
261
|
+
{/* A featurelayer that uses a FeatureLayerView to do some front-end filtering: */}
|
|
262
|
+
<FeatureLayer
|
|
263
|
+
ref={flRef}
|
|
264
|
+
url="https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0"
|
|
265
|
+
>
|
|
266
|
+
<FeatureLayerView
|
|
267
|
+
ref={flViewRef}
|
|
268
|
+
filter={{
|
|
269
|
+
where: `C_Storage < ${maxStorage}`,
|
|
270
|
+
}}
|
|
271
|
+
/>
|
|
272
|
+
</FeatureLayer>
|
|
273
|
+
</MapView>
|
|
274
|
+
);
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
As you can see, all ESRIEACT components can take a ref, whose value is the underlying ESRI instance.
|
|
279
|
+
|
|
280
|
+
# React + TypeScript + Vite Readme
|
|
281
|
+
|
|
282
|
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
283
|
+
|
|
284
|
+
Currently, two official plugins are available:
|
|
285
|
+
|
|
286
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
|
287
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
288
|
+
|
|
289
|
+
## Expanding the ESLint configuration
|
|
290
|
+
|
|
291
|
+
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
|
292
|
+
|
|
293
|
+
- Configure the top-level `parserOptions` property like this:
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
export default {
|
|
297
|
+
// other rules...
|
|
298
|
+
parserOptions: {
|
|
299
|
+
ecmaVersion: "latest",
|
|
300
|
+
sourceType: "module",
|
|
301
|
+
project: ["./tsconfig.json", "./tsconfig.node.json"],
|
|
302
|
+
tsconfigRootDir: __dirname,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
|
308
|
+
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
|
309
|
+
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
|
+
import EsriGraphic from "@arcgis/core/Graphic.js";
|
|
3
|
+
export interface GraphicProps extends __esri.GraphicProperties, PropsWithChildren {
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The react context object that any Grpahic component creates when rendered
|
|
7
|
+
* and makes available to its descendants
|
|
8
|
+
*/
|
|
9
|
+
export declare const GraphicContext: React.Context<EsriGraphic>;
|
|
10
|
+
/**
|
|
11
|
+
* A Graphic component, must be rendered as a child of a GraphicsLayer
|
|
12
|
+
*
|
|
13
|
+
* ArcGIS JS API Source Components:
|
|
14
|
+
* - [Graphic](https://developers.arcgis.com/javascript/latest/api-reference/esri-Graphic.html)
|
|
15
|
+
*/
|
|
16
|
+
export declare const Graphic: React.ForwardRefExoticComponent<GraphicProps & React.RefAttributes<EsriGraphic>>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { createContext, useContext, useEffect, useImperativeHandle, useMemo, } from "react";
|
|
3
|
+
import EsriGraphic from "@arcgis/core/Graphic.js";
|
|
4
|
+
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer";
|
|
5
|
+
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
|
|
6
|
+
import Collection from "@arcgis/core/core/Collection.js";
|
|
7
|
+
import { LayerContext } from "../layers";
|
|
8
|
+
import { useEsriPropertyUpdates } from "../utils";
|
|
9
|
+
/**
|
|
10
|
+
* The react context object that any Grpahic component creates when rendered
|
|
11
|
+
* and makes available to its descendants
|
|
12
|
+
*/
|
|
13
|
+
export const GraphicContext = createContext({});
|
|
14
|
+
/**
|
|
15
|
+
* A Graphic component, must be rendered as a child of a GraphicsLayer
|
|
16
|
+
*
|
|
17
|
+
* ArcGIS JS API Source Components:
|
|
18
|
+
* - [Graphic](https://developers.arcgis.com/javascript/latest/api-reference/esri-Graphic.html)
|
|
19
|
+
*/
|
|
20
|
+
export const Graphic = React.forwardRef(({ children, ...properties }, ref) => {
|
|
21
|
+
const parent = useContext(LayerContext);
|
|
22
|
+
/**
|
|
23
|
+
* Create instance only on first mount
|
|
24
|
+
*/
|
|
25
|
+
const instance = useMemo(() => {
|
|
26
|
+
const graphic = new EsriGraphic(properties);
|
|
27
|
+
if (!(parent instanceof GraphicsLayer) &&
|
|
28
|
+
!(parent instanceof FeatureLayer)) {
|
|
29
|
+
// Allow this because it only happens in development and is helpful for devs
|
|
30
|
+
// eslint-disable-next-line
|
|
31
|
+
console.error("You are trying to render a Graphic component that is not a descendant of a GraphicsLayer or FeatureLayer.", "Did you forget to wrap your Graphic in a GraphicsLayer or FeatureLayer?");
|
|
32
|
+
}
|
|
33
|
+
if (parent instanceof GraphicsLayer) {
|
|
34
|
+
parent.add(graphic);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* If using the Graphic to craft a client-side featurelayer, we push to the FeatureLayer.source property
|
|
38
|
+
* See https://developers.arcgis.com/javascript/latest/sample-code/layers-featurelayer-collection/
|
|
39
|
+
*/
|
|
40
|
+
if (parent instanceof FeatureLayer) {
|
|
41
|
+
if (!parent.source) {
|
|
42
|
+
parent.source = new Collection();
|
|
43
|
+
}
|
|
44
|
+
parent.source.add(graphic);
|
|
45
|
+
}
|
|
46
|
+
return graphic;
|
|
47
|
+
}, []);
|
|
48
|
+
/**
|
|
49
|
+
* Remove the graphic from the GraphicsLayer or FeatureLayer on unmount
|
|
50
|
+
*/
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
return () => {
|
|
53
|
+
if (parent instanceof GraphicsLayer) {
|
|
54
|
+
parent.remove(instance);
|
|
55
|
+
}
|
|
56
|
+
if (parent instanceof FeatureLayer) {
|
|
57
|
+
parent.source.remove(instance);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}, []);
|
|
61
|
+
useImperativeHandle(ref, () => instance);
|
|
62
|
+
useEsriPropertyUpdates(instance, properties);
|
|
63
|
+
// If no children, there is no need to render a context provider
|
|
64
|
+
if (!children)
|
|
65
|
+
return null;
|
|
66
|
+
return (_jsx(GraphicContext.Provider, { value: instance, children: children }));
|
|
67
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriRenderer from "@arcgis/core/renderers/Renderer";
|
|
3
|
+
/**
|
|
4
|
+
* A generic Renderer component
|
|
5
|
+
*
|
|
6
|
+
* ArcGIS JS API Source Components:
|
|
7
|
+
* - [Renderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-Renderer.html)
|
|
8
|
+
*/
|
|
9
|
+
export declare const Renderer: React.ForwardRefExoticComponent<__esri.RendererProperties & {
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
} & React.RefAttributes<EsriRenderer>>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriRenderer from "@arcgis/core/renderers/Renderer";
|
|
3
|
+
import { createRendererComponent, } from "./createRendererComponent";
|
|
4
|
+
const createRenderer = (properties) => new EsriRenderer(properties);
|
|
5
|
+
/**
|
|
6
|
+
* A generic Renderer component
|
|
7
|
+
*
|
|
8
|
+
* ArcGIS JS API Source Components:
|
|
9
|
+
* - [Renderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-Renderer.html)
|
|
10
|
+
*/
|
|
11
|
+
export const Renderer = React.forwardRef((properties, ref) => createRendererComponent(createRenderer, ref, properties));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A SimpleRenderer component. Use as a descendant of any esri component that can use a SimpleRenderer
|
|
4
|
+
* and the renderer will be applied
|
|
5
|
+
*
|
|
6
|
+
* ArcGIS JS API Source Components:
|
|
7
|
+
* - [SimpleRenderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-SimpleRenderer.html)
|
|
8
|
+
*/
|
|
9
|
+
export declare const SimpleRenderer: React.ForwardRefExoticComponent<__esri.SimpleRendererProperties & {
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
} & React.RefAttributes<__esri.UniqueValueRenderer>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriSimpleRenderer from "@arcgis/core/renderers/SimpleRenderer";
|
|
3
|
+
import { createRendererComponent, } from "./createRendererComponent";
|
|
4
|
+
const createSimpleRenderer = (properties) => new EsriSimpleRenderer(properties);
|
|
5
|
+
/**
|
|
6
|
+
* A SimpleRenderer component. Use as a descendant of any esri component that can use a SimpleRenderer
|
|
7
|
+
* and the renderer will be applied
|
|
8
|
+
*
|
|
9
|
+
* ArcGIS JS API Source Components:
|
|
10
|
+
* - [SimpleRenderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-SimpleRenderer.html)
|
|
11
|
+
*/
|
|
12
|
+
export const SimpleRenderer = React.forwardRef((properties, ref) => createRendererComponent(createSimpleRenderer, ref, properties));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriUniqueValueRenderer from "@arcgis/core/renderers/UniqueValueRenderer";
|
|
3
|
+
/**
|
|
4
|
+
* A UniqueValueRenderer component. Use as a descendant of any esri component that can use a UniqueValueRenderer
|
|
5
|
+
* and the renderer will be applied
|
|
6
|
+
*
|
|
7
|
+
* ArcGIS JS API Source Components:
|
|
8
|
+
* - [UniqueValueRenderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-UniqueValueRenderer.html)
|
|
9
|
+
*/
|
|
10
|
+
export declare const UniqueValueRenderer: React.ForwardRefExoticComponent<__esri.UniqueValueRendererProperties & {
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
} & React.RefAttributes<EsriUniqueValueRenderer>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriUniqueValueRenderer from "@arcgis/core/renderers/UniqueValueRenderer";
|
|
3
|
+
import { createRendererComponent, } from "./createRendererComponent";
|
|
4
|
+
const createUniqueValueRenderer = (properties) => new EsriUniqueValueRenderer(properties);
|
|
5
|
+
/**
|
|
6
|
+
* A UniqueValueRenderer component. Use as a descendant of any esri component that can use a UniqueValueRenderer
|
|
7
|
+
* and the renderer will be applied
|
|
8
|
+
*
|
|
9
|
+
* ArcGIS JS API Source Components:
|
|
10
|
+
* - [UniqueValueRenderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-UniqueValueRenderer.html)
|
|
11
|
+
*/
|
|
12
|
+
export const UniqueValueRenderer = React.forwardRef((properties, ref) => createRendererComponent(createUniqueValueRenderer, ref, properties));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { Ref } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The react context object that any layer component creates when rendered
|
|
4
|
+
* and makes available to its descendants
|
|
5
|
+
*/
|
|
6
|
+
export declare const RendererContext: React.Context<__esri.Renderer>;
|
|
7
|
+
export type RendererProps<T extends __esri.RendererProperties = __esri.RendererProperties> = React.PropsWithChildren<T>;
|
|
8
|
+
/**
|
|
9
|
+
* Function that takes in renderer properties and returns an esri Renderer instance. Properties must be
|
|
10
|
+
* any esri properties that extend esri.LayerProperties, and optional children
|
|
11
|
+
*/
|
|
12
|
+
export type CreateRendererFunction<T extends RendererProps> = (properties: T) => __esri.Renderer;
|
|
13
|
+
export declare const createRendererComponent: (createRenderer: CreateRendererFunction<RendererProps>, ref: Ref<__esri.Renderer>, { children, ...properties }: RendererProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useImperativeHandle, useMemo, } from "react";
|
|
3
|
+
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
|
|
4
|
+
import SceneLayer from "@arcgis/core/layers/SceneLayer";
|
|
5
|
+
import Sublayer from "@arcgis/core/layers/support/Sublayer";
|
|
6
|
+
import CSVLayer from "@arcgis/core/layers/CSVLayer";
|
|
7
|
+
import GeoJSONLayer from "@arcgis/core/layers/GeoJSONLayer";
|
|
8
|
+
import OGCFeatureLayer from "@arcgis/core/layers/OGCFeatureLayer";
|
|
9
|
+
import StreamLayer from "@arcgis/core/layers/StreamLayer";
|
|
10
|
+
import WFSLayer from "@arcgis/core/layers/WFSLayer";
|
|
11
|
+
import { LayerContext } from "../../layers";
|
|
12
|
+
import { useEsriPropertyUpdates } from "../../utils";
|
|
13
|
+
/**
|
|
14
|
+
* The react context object that any layer component creates when rendered
|
|
15
|
+
* and makes available to its descendants
|
|
16
|
+
*/
|
|
17
|
+
export const RendererContext = createContext({});
|
|
18
|
+
export const createRendererComponent = (createRenderer, ref, { children, ...properties }) => {
|
|
19
|
+
const parent = useContext(LayerContext);
|
|
20
|
+
const defaultRenderer = parent.renderer;
|
|
21
|
+
const instance = useMemo(() => {
|
|
22
|
+
const renderer = createRenderer(properties);
|
|
23
|
+
if (parent instanceof FeatureLayer ||
|
|
24
|
+
parent instanceof SceneLayer ||
|
|
25
|
+
parent instanceof Sublayer ||
|
|
26
|
+
parent instanceof CSVLayer ||
|
|
27
|
+
parent instanceof GeoJSONLayer ||
|
|
28
|
+
parent instanceof OGCFeatureLayer ||
|
|
29
|
+
parent instanceof StreamLayer ||
|
|
30
|
+
parent instanceof WFSLayer) {
|
|
31
|
+
parent.renderer = renderer;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Allow this because it only happens in development and is helpful for devs
|
|
35
|
+
// eslint-disable-next-line
|
|
36
|
+
console.error("You are trying to use a <Renderer /> component as the descendant of a component that does not take an ESRI renderer.");
|
|
37
|
+
}
|
|
38
|
+
return renderer;
|
|
39
|
+
}, []);
|
|
40
|
+
useImperativeHandle(ref, () => instance);
|
|
41
|
+
useEsriPropertyUpdates(instance, properties);
|
|
42
|
+
/**
|
|
43
|
+
* Set the renderer of the parent layer back to its initial default on unmount
|
|
44
|
+
*/
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
return () => {
|
|
47
|
+
if (parent instanceof FeatureLayer ||
|
|
48
|
+
parent instanceof SceneLayer ||
|
|
49
|
+
parent instanceof Sublayer ||
|
|
50
|
+
parent instanceof CSVLayer ||
|
|
51
|
+
parent instanceof GeoJSONLayer ||
|
|
52
|
+
parent instanceof OGCFeatureLayer ||
|
|
53
|
+
parent instanceof StreamLayer ||
|
|
54
|
+
parent instanceof WFSLayer) {
|
|
55
|
+
parent.renderer = defaultRenderer;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
// If no children, there is no need to render a context provider
|
|
60
|
+
if (!children)
|
|
61
|
+
return null;
|
|
62
|
+
return (_jsx(RendererContext.Provider, { value: instance, children: children }));
|
|
63
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriPictureMarkerSymbol from "@arcgis/core/symbols/PictureMarkerSymbol.js";
|
|
3
|
+
/**
|
|
4
|
+
* A PictureMarkerSymbol component, must be rendered as a child of a Renderer component or Graphic component
|
|
5
|
+
*
|
|
6
|
+
* ArcGIS JS API Source Components:
|
|
7
|
+
* - [PictureMarkerSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PictureMarkerSymbol.html)
|
|
8
|
+
*/
|
|
9
|
+
export declare const PictureMarkerSymbol: React.ForwardRefExoticComponent<__esri.PictureMarkerSymbolProperties & React.RefAttributes<EsriPictureMarkerSymbol>>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useContext, useImperativeHandle, useMemo } from "react";
|
|
2
|
+
import EsriPictureMarkerSymbol from "@arcgis/core/symbols/PictureMarkerSymbol.js";
|
|
3
|
+
import Graphic from "@arcgis/core/Graphic";
|
|
4
|
+
import Renderer from "@arcgis/core/renderers/Renderer";
|
|
5
|
+
import { GraphicContext } from "../Graphic";
|
|
6
|
+
import { useEsriPropertyUpdates } from "../../utils";
|
|
7
|
+
import { RendererContext } from "../renderers";
|
|
8
|
+
/**
|
|
9
|
+
* A PictureMarkerSymbol component, must be rendered as a child of a Renderer component or Graphic component
|
|
10
|
+
*
|
|
11
|
+
* ArcGIS JS API Source Components:
|
|
12
|
+
* - [PictureMarkerSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PictureMarkerSymbol.html)
|
|
13
|
+
*/
|
|
14
|
+
export const PictureMarkerSymbol = React.forwardRef((properties, ref) => {
|
|
15
|
+
const parentGraphic = useContext(GraphicContext);
|
|
16
|
+
const parentRenderer = useContext(RendererContext);
|
|
17
|
+
/**
|
|
18
|
+
* Create instance only on first mount
|
|
19
|
+
*/
|
|
20
|
+
const instance = useMemo(() => {
|
|
21
|
+
const symbol = new EsriPictureMarkerSymbol(properties);
|
|
22
|
+
if (!(parentGraphic instanceof Graphic) &&
|
|
23
|
+
!(parentRenderer instanceof Renderer)) {
|
|
24
|
+
// Allow this because it only happens in development and is helpful for devs
|
|
25
|
+
// eslint-disable-next-line
|
|
26
|
+
console.error("You are trying to render a PictureMarkerSymbol component that is not a descendant of a Graphic or Renderer.", "Did you forget to wrap your PictureMarkerSymbol in a Graphic or Renderer?");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (parentRenderer) {
|
|
30
|
+
// @ts-expect-error allow this for renderers that do take a symbol
|
|
31
|
+
parentRenderer.symbol = symbol;
|
|
32
|
+
return symbol;
|
|
33
|
+
}
|
|
34
|
+
if (parentGraphic) {
|
|
35
|
+
parentGraphic.symbol = symbol;
|
|
36
|
+
return symbol;
|
|
37
|
+
}
|
|
38
|
+
return symbol;
|
|
39
|
+
}, []);
|
|
40
|
+
useImperativeHandle(ref, () => instance);
|
|
41
|
+
useEsriPropertyUpdates(instance, properties);
|
|
42
|
+
return null;
|
|
43
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import EsriSimpleFillSymbol from "@arcgis/core/symbols/SimpleFillSymbol";
|
|
3
|
+
/**
|
|
4
|
+
* A SimpleFillSymbol component, must be rendered as a child of a Renderer component or Graphic component
|
|
5
|
+
*
|
|
6
|
+
* ArcGIS JS API Source Components:
|
|
7
|
+
* - [SimpleFillSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleFillSymbol.html)
|
|
8
|
+
*/
|
|
9
|
+
export declare const SimpleFillSymbol: React.ForwardRefExoticComponent<__esri.SimpleFillSymbolProperties & React.RefAttributes<EsriSimpleFillSymbol>>;
|