@deck.gl/widgets
Version:
UI widgets for deck.gl
137 lines • 5.81 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { Widget } from '@deck.gl/core';
import { FlyToInterpolator, LinearInterpolator } from '@deck.gl/core';
import { render } from 'preact';
import { DropdownMenu } from "./lib/components/dropdown-menu.js";
import { GeocoderHistory } from "./lib/geocode/geocoder-history.js";
import { GoogleGeocoder, MapboxGeocoder, OpenCageGeocoder, CoordinatesGeocoder, CurrentLocationGeocoder } from "./lib/geocode/geocoders.js";
const CURRENT_LOCATION = 'current';
/**
* A widget that display a text box that lets user type in a location
* and a button that moves the view to that location.
* @todo For now only supports coordinates, Could be extended with location service integrations.
*/
export class GeocoderWidget extends Widget {
constructor(props = {}) {
super(props);
this.className = 'deck-widget-geocoder';
this.placement = 'top-left';
this.geocodeHistory = new GeocoderHistory({});
this.addressText = '';
this.geocoder = CoordinatesGeocoder;
this.setInput = (text) => {
this.addressText = text;
};
this.handleKeyPress = e => {
if (e.key === 'Enter') {
this.handleSubmit();
}
};
this.handleSelect = (address) => {
this.setInput(address);
this.handleSubmit();
};
/** Sync wrapper for async geocode() */
this.handleSubmit = () => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.geocode(this.addressText);
};
/** Perform geocoding */
this.geocode = async (address) => {
const useGeolocation = this.props._geolocation && address === CURRENT_LOCATION;
const geocoder = useGeolocation ? CurrentLocationGeocoder : this.geocoder;
const coordinates = await this.geocodeHistory.geocode(geocoder, this.addressText, this.props.apiKey);
if (coordinates) {
this.setViewState(coordinates);
}
};
this.viewports = {};
this.setProps(this.props);
}
setProps(props) {
this.placement = props.placement ?? this.placement;
this.viewId = props.viewId ?? this.viewId;
this.geocoder = getGeocoder(this.props);
if (this.geocoder.requiresApiKey && !this.props.apiKey) {
throw new Error(`API key is required for the ${this.geocoder.name} geocoder`);
}
super.setProps(props);
}
onRenderHTML(rootElement) {
const menuItems = this.props._geolocation
? [CURRENT_LOCATION, ...this.geocodeHistory.addressHistory]
: [...this.geocodeHistory.addressHistory];
render(_jsxs("div", { className: "deck-widget-geocoder", style: {
pointerEvents: 'auto',
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap' // Allows wrapping on smaller screens
}, children: [_jsx("input", { type: "text", placeholder: this.geocoder.placeholderLocation ?? 'Enter address or location', value: this.geocodeHistory.addressText,
// @ts-expect-error event type
onInput: e => this.setInput(e.target?.value || ''), onKeyPress: this.handleKeyPress, style: {
flex: '1 1 auto',
minWidth: '200px',
margin: 0,
padding: '8px',
boxSizing: 'border-box'
} }), _jsx(DropdownMenu, { menuItems: menuItems, onSelect: this.handleSelect, style: {
margin: 2,
padding: '4px 2px',
boxSizing: 'border-box'
} }), this.geocodeHistory.errorText && (_jsx("div", { className: "error", children: this.geocodeHistory.errorText }))] }), rootElement);
}
// TODO - MOVE TO WIDGETIMPL?
setViewState(viewState) {
const viewId = this.props.viewId || viewState?.id || 'default-view';
const viewport = this.viewports[viewId] || {};
const nextViewState = {
...viewport,
...viewState
};
if (this.props.transitionDuration > 0) {
nextViewState.transitionDuration = this.props.transitionDuration;
nextViewState.transitionInterpolator =
'latitude' in nextViewState ? new FlyToInterpolator() : new LinearInterpolator();
}
// @ts-ignore Using private method temporary until there's a public one
this.deck._onViewStateChange({ viewId, viewState: nextViewState, interactionState: {} });
}
onViewportChange(viewport) {
this.viewports[viewport.id] = viewport;
}
}
GeocoderWidget.defaultProps = {
...Widget.defaultProps,
id: 'geocoder',
viewId: null,
placement: 'top-left',
label: 'Geocoder',
transitionDuration: 200,
geocoder: 'coordinates',
customGeocoder: CoordinatesGeocoder,
apiKey: '',
_geolocation: false
};
function getGeocoder(props) {
switch (props.geocoder) {
case 'google':
return GoogleGeocoder;
case 'mapbox':
return MapboxGeocoder;
case 'opencage':
return OpenCageGeocoder;
case 'coordinates':
return CoordinatesGeocoder;
case 'custom':
if (!props.customGeocoder) {
throw new Error('Custom geocoder is not defined');
}
return props.customGeocoder;
default:
throw new Error(`Unknown geocoder: ${props.geocoder}`);
}
}
//# sourceMappingURL=geocoder-widget.js.map