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