7 changed files with 181 additions and 0 deletions
-
3FetchLatLong/config.json
-
17FetchLatLong/icon.svg
-
31FetchLatLong/manifest.json
-
7FetchLatLong/src/config.ts
-
85FetchLatLong/src/runtime/widget.tsx
-
24FetchLatLong/src/styles.css
-
14FetchLatLong/tests/simple-widget.test.tsx
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"exampleConfigProperty": "test" |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> |
||||
|
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" |
||||
|
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve"> |
||||
|
<g> |
||||
|
<path d="M31.4,15.3h8.2c0.6,0,1.1-0.5,1.1-1.1l0,0c0-0.3-0.1-0.5-0.3-0.8L30.2,3.3C29.9,3.1,29.7,3,29.4,3l0,0 |
||||
|
c-0.6,0-1.1,0.5-1.1,1.1v8.1C28.3,13.9,29.7,15.3,31.4,15.3z"/> |
||||
|
<path d="M49.5,25.7l-0.9-0.9c-0.6-0.6-1.5-0.6-2.2,0L34.5,36.7c-0.1,0.1,0,0.2,0,0.3v2.5c0,0.2,0,0.4,0.2,0.4h2.6 |
||||
|
c0.1,0,0.2-0.1,0.3-0.1L49.5,28C50.2,27.2,50.2,26.3,49.5,25.7z"/> |
||||
|
<path d="M39.9,44.4h-1.8h-3.6h-1.7c-1.6,0-2.9-1.3-2.9-2.9v-5.4c0-0.8,0.2-1.6,0.9-2.1l9.5-9.5 |
||||
|
c0.3-0.3,0.5-0.7,0.5-1.1v-2c0-0.8-0.7-1.5-1.5-1.5H28.3c-2.6,0-4.6-2.1-4.6-4.6V4.5C23.7,3.7,23,3,22.1,3H6.6C4.1,3,2,5.1,2,7.6 |
||||
|
v36.8C2,46.9,4.1,49,6.6,49h29.4c2.2,0,4.2-1.6,4.6-3.7C40.7,44.9,40.3,44.4,39.9,44.4z M8.2,16.8c0-0.8,0.7-1.5,1.5-1.5h6.2 |
||||
|
c0.9,0,1.5,0.7,1.5,1.5v1.5c0,0.8-0.7,1.5-1.5,1.5H9.7c-0.9,0-1.5-0.7-1.5-1.5V16.8z M23.7,36.7c0,0.8-0.7,1.5-1.5,1.5H9.7 |
||||
|
c-0.9,0-1.5-0.7-1.5-1.5v-1.5c0-0.8,0.7-1.5,1.5-1.5h12.4c0.9,0,1.5,0.7,1.5,1.5V36.7z M26.8,27.5c0,0.8-0.7,1.5-1.5,1.5H9.7 |
||||
|
c-0.9,0-1.5-0.7-1.5-1.5V26c0-0.8,0.7-1.5,1.5-1.5h15.5c0.9,0,1.5,0.7,1.5,1.5V27.5z"/> |
||||
|
</g> |
||||
|
</svg> |
||||
@ -0,0 +1,31 @@ |
|||||
|
{ |
||||
|
"name": "FetchLatLong", |
||||
|
"label": "FetchLatLong", |
||||
|
"type": "widget", |
||||
|
"version": "1.16.0", |
||||
|
"exbVersion": "1.16.0", |
||||
|
"author": "Esri R&D Center Beijing", |
||||
|
"description": "This is a barebones, simple widget. It includes an example of how to use the config file, and it includes a placeholder SVG icon. It intentionally does not include the following so you can use this to start from scratch: i18n translations, a Settings panel, unit tests. See the documentation for more information on how to implement these features.", |
||||
|
"copyright": "", |
||||
|
"license": "http://www.apache.org/licenses/LICENSE-2.0", |
||||
|
"properties": { |
||||
|
"hasSettingPage": false, |
||||
|
"useMapWidget": true |
||||
|
}, |
||||
|
"widgets": [ |
||||
|
{ |
||||
|
"uri": "FetchLatLong", |
||||
|
"label": "FetchLatLong", |
||||
|
"thumbnail": "thumbnail.png", |
||||
|
"description": "Select the lat long." |
||||
|
} |
||||
|
], |
||||
|
"framework": "react", |
||||
|
"translatedLocales": ["en"], |
||||
|
"dataSources": [], |
||||
|
"elements": [] |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
@ -0,0 +1,7 @@ |
|||||
|
import { type ImmutableObject } from 'seamless-immutable' |
||||
|
|
||||
|
export interface Config { |
||||
|
exampleConfigProperty: string |
||||
|
} |
||||
|
|
||||
|
export type IMConfig = ImmutableObject<Config> |
||||
@ -0,0 +1,85 @@ |
|||||
|
/** @jsx jsx */ |
||||
|
import { React, jsx, AllWidgetProps } from 'jimu-core' |
||||
|
import { TextInput } from 'jimu-ui' |
||||
|
import { JimuMapViewComponent, JimuMapView } from 'jimu-arcgis' |
||||
|
import Point from 'esri/geometry/Point' |
||||
|
import { throttle } from 'lodash' |
||||
|
|
||||
|
interface State { |
||||
|
latitude: string |
||||
|
longitude: string |
||||
|
scale: number |
||||
|
zoom: number |
||||
|
mapViewReady: boolean |
||||
|
} |
||||
|
|
||||
|
export default class GetLatLongWidget extends React.PureComponent<AllWidgetProps<any>, State> { |
||||
|
mapView: __esri.MapView = null |
||||
|
|
||||
|
constructor(props: AllWidgetProps<any>) { |
||||
|
super(props) |
||||
|
this.state = { |
||||
|
latitude: '', |
||||
|
longitude: '', |
||||
|
scale: 0, |
||||
|
zoom: 0, |
||||
|
mapViewReady: false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
activeViewChangeHandler = (jimuMapView: JimuMapView) => { |
||||
|
if (jimuMapView) { |
||||
|
this.mapView = jimuMapView.view as __esri.MapView |
||||
|
|
||||
|
// Update when extent changes (zoom, pan)
|
||||
|
this.mapView.watch('extent', () => { |
||||
|
this.setCenterState() |
||||
|
}) |
||||
|
|
||||
|
// Pointer move with throttling
|
||||
|
this.mapView.on('pointer-move', throttle((evt) => { |
||||
|
const point: Point = this.mapView.toMap({ x: evt.x, y: evt.y }) |
||||
|
if (point) { |
||||
|
this.setCenterState(point) |
||||
|
} |
||||
|
}, 300)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
setCenterState = (point?: Point) => { |
||||
|
const centerPoint = point || this.mapView?.center |
||||
|
if (!centerPoint) return |
||||
|
|
||||
|
this.setState({ |
||||
|
latitude: centerPoint.latitude.toFixed(5), |
||||
|
longitude: centerPoint.longitude.toFixed(5), |
||||
|
scale: Math.round(this.mapView.scale), |
||||
|
zoom: this.mapView.zoom, |
||||
|
mapViewReady: true |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { latitude, longitude, scale, zoom, mapViewReady } = this.state |
||||
|
|
||||
|
return ( |
||||
|
<div className="widget-get-latlong p-3"> |
||||
|
<JimuMapViewComponent |
||||
|
useMapWidgetId={this.props.useMapWidgetIds?.[0]} |
||||
|
onActiveViewChange={this.activeViewChangeHandler} |
||||
|
/> |
||||
|
|
||||
|
<div className="mt-3"> |
||||
|
<TextInput value={latitude} readOnly placeholder="Latitude" className="mb-2" /> |
||||
|
<TextInput value={longitude} readOnly placeholder="Longitude" className="mb-2" /> |
||||
|
<TextInput value={scale.toString()} readOnly placeholder="Scale" className="mb-2" /> |
||||
|
<TextInput value={zoom.toString()} readOnly placeholder="Zoom Level" className="mb-2" /> |
||||
|
|
||||
|
<div style={{ color: mapViewReady ? 'green' : 'red' }}> |
||||
|
{mapViewReady ? 'Map View Ready' : 'Waiting for Map Interaction...'} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
.widget-container { |
||||
|
padding: 15px; |
||||
|
background: white; |
||||
|
border-radius: 8px; |
||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); |
||||
|
} |
||||
|
|
||||
|
h3 { |
||||
|
font-size: 18px; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.export-button { |
||||
|
margin-top: 10px; |
||||
|
background-color: #0078d4; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
.table-container { |
||||
|
max-height: 400px; |
||||
|
overflow-y: auto; |
||||
|
border: 1px solid #ddd; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,14 @@ |
|||||
|
import { React } from 'jimu-core' |
||||
|
import _Widget from '../src/runtime/widget' |
||||
|
import { widgetRender, wrapWidget } from 'jimu-for-test' |
||||
|
|
||||
|
const render = widgetRender() |
||||
|
describe('test simple widget', () => { |
||||
|
it('simple test', () => { |
||||
|
const Widget = wrapWidget(_Widget, { |
||||
|
config: { exampleConfigProperty: 'a' } |
||||
|
}) |
||||
|
const { queryByText } = render(<Widget widgetId="Widget_1" />) |
||||
|
expect(queryByText('exampleConfigProperty: a').tagName).toBe('P') |
||||
|
}) |
||||
|
}) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue