mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Maps] Added options to disable zoom, hide tool tips, widgets/overlays in embeddable maps (#50663) (#51811)
* added options to disable zoom, hide tool tips, widgets/overlays in embeddable maps * revert panel changes * added disable interactive * remove redundant code * update redux state and removed widget over lay hiding * update readme with added map props
This commit is contained in:
parent
03d08c3d79
commit
328ae2b0d7
9 changed files with 265 additions and 194 deletions
|
@ -67,6 +67,9 @@ export const SET_TOOLTIP_STATE = 'SET_TOOLTIP_STATE';
|
|||
export const UPDATE_DRAW_STATE = 'UPDATE_DRAW_STATE';
|
||||
export const SET_SCROLL_ZOOM = 'SET_SCROLL_ZOOM';
|
||||
export const SET_MAP_INIT_ERROR = 'SET_MAP_INIT_ERROR';
|
||||
export const SET_INTERACTIVE = 'SET_INTERACTIVE';
|
||||
export const DISABLE_TOOLTIP_CONTROL = 'DISABLE_TOOLTIP_CONTROL';
|
||||
export const HIDE_TOOLBAR_OVERLAY = 'HIDE_TOOLBAR_OVERLAY';
|
||||
|
||||
function getLayerLoadingCallbacks(dispatch, layerId) {
|
||||
return {
|
||||
|
@ -814,3 +817,15 @@ export function updateDrawState(drawState) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function disableInteractive() {
|
||||
return { type: SET_INTERACTIVE, disableInteractive: true };
|
||||
}
|
||||
|
||||
export function disableTooltipControl() {
|
||||
return { type: DISABLE_TOOLTIP_CONTROL, disableTooltipControl: true };
|
||||
}
|
||||
|
||||
export function hideToolbarOverlay() {
|
||||
return { type: HIDE_TOOLBAR_OVERLAY, hideToolbarOverlay: true };
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ import {
|
|||
areLayersLoaded,
|
||||
getRefreshConfig,
|
||||
getMapInitError,
|
||||
getQueryableUniqueIndexPatternIds
|
||||
getQueryableUniqueIndexPatternIds,
|
||||
isToolbarOverlayHidden,
|
||||
} from '../../selectors/map_selectors';
|
||||
|
||||
function mapStateToProps(state = {}) {
|
||||
|
@ -28,6 +29,7 @@ function mapStateToProps(state = {}) {
|
|||
refreshConfig: getRefreshConfig(state),
|
||||
mapInitError: getMapInitError(state),
|
||||
indexPatternIds: getQueryableUniqueIndexPatternIds(state),
|
||||
hideToolbarOverlay: isToolbarOverlayHidden(state),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -21,12 +21,11 @@ import uuid from 'uuid/v4';
|
|||
const RENDER_COMPLETE_EVENT = 'renderComplete';
|
||||
|
||||
export class GisMap extends Component {
|
||||
|
||||
state = {
|
||||
isInitialLoadRenderTimeoutComplete: false,
|
||||
domId: uuid(),
|
||||
geoFields: [],
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
|
@ -65,9 +64,9 @@ export class GisMap extends Component {
|
|||
if (el) {
|
||||
el.dispatchEvent(new CustomEvent(RENDER_COMPLETE_EVENT, { bubbles: true }));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_loadGeoFields = async (nextIndexPatternIds) => {
|
||||
_loadGeoFields = async nextIndexPatternIds => {
|
||||
if (_.isEqual(nextIndexPatternIds, this._prevIndexPatternIds)) {
|
||||
// all ready loaded index pattern ids
|
||||
return;
|
||||
|
@ -78,19 +77,22 @@ export class GisMap extends Component {
|
|||
const geoFields = [];
|
||||
try {
|
||||
const indexPatterns = await getIndexPatternsFromIds(nextIndexPatternIds);
|
||||
indexPatterns.forEach((indexPattern) => {
|
||||
indexPatterns.forEach(indexPattern => {
|
||||
indexPattern.fields.forEach(field => {
|
||||
if (field.type === ES_GEO_FIELD_TYPE.GEO_POINT || field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE) {
|
||||
if (
|
||||
field.type === ES_GEO_FIELD_TYPE.GEO_POINT ||
|
||||
field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE
|
||||
) {
|
||||
geoFields.push({
|
||||
geoFieldName: field.name,
|
||||
geoFieldType: field.type,
|
||||
indexPatternTitle: indexPattern.title,
|
||||
indexPatternId: indexPattern.id
|
||||
indexPatternId: indexPattern.id,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// swallow errors.
|
||||
// the Layer-TOC will indicate which layers are disfunctional on a per-layer basis
|
||||
}
|
||||
|
@ -100,7 +102,7 @@ export class GisMap extends Component {
|
|||
}
|
||||
|
||||
this.setState({ geoFields });
|
||||
}
|
||||
};
|
||||
|
||||
_setRefreshTimer = () => {
|
||||
const { isPaused, interval } = this.props.refreshConfig;
|
||||
|
@ -116,12 +118,9 @@ export class GisMap extends Component {
|
|||
this._clearRefreshTimer();
|
||||
|
||||
if (!isPaused && interval > 0) {
|
||||
this.refreshTimerId = setInterval(
|
||||
() => {
|
||||
this.props.triggerRefreshTimer();
|
||||
},
|
||||
interval
|
||||
);
|
||||
this.refreshTimerId = setInterval(() => {
|
||||
this.props.triggerRefreshTimer();
|
||||
}, interval);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -134,16 +133,13 @@ export class GisMap extends Component {
|
|||
// Mapbox does not provide any feedback when rendering is complete.
|
||||
// Temporary solution is just to wait set period of time after data has loaded.
|
||||
_startInitialLoadRenderTimer = () => {
|
||||
setTimeout(
|
||||
() => {
|
||||
if (this._isMounted) {
|
||||
this.setState({ isInitialLoadRenderTimeoutComplete: true });
|
||||
this._onInitialLoadRenderComplete();
|
||||
}
|
||||
},
|
||||
5000
|
||||
);
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (this._isMounted) {
|
||||
this.setState({ isInitialLoadRenderTimeoutComplete: true });
|
||||
this._onInitialLoadRenderComplete();
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
|
@ -164,14 +160,12 @@ export class GisMap extends Component {
|
|||
<div data-render-complete data-shared-item>
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.maps.map.initializeErrorTitle', {
|
||||
defaultMessage: 'Unable to initialize map'
|
||||
defaultMessage: 'Unable to initialize map',
|
||||
})}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<p>
|
||||
{mapInitError}
|
||||
</p>
|
||||
<p>{mapInitError}</p>
|
||||
</EuiCallOut>
|
||||
</div>
|
||||
);
|
||||
|
@ -183,21 +177,15 @@ export class GisMap extends Component {
|
|||
currentPanel = null;
|
||||
} else if (addLayerVisible) {
|
||||
currentPanelClassName = 'mapMapLayerPanel-isVisible';
|
||||
currentPanel = <AddLayerPanel/>;
|
||||
currentPanel = <AddLayerPanel />;
|
||||
} else if (layerDetailsVisible) {
|
||||
currentPanelClassName = 'mapMapLayerPanel-isVisible';
|
||||
currentPanel = (
|
||||
<LayerPanel/>
|
||||
);
|
||||
currentPanel = <LayerPanel />;
|
||||
}
|
||||
|
||||
let exitFullScreenButton;
|
||||
if (isFullScreen) {
|
||||
exitFullScreenButton = (
|
||||
<ExitFullScreenButton
|
||||
onExitFullScreenMode={exitFullScreen}
|
||||
/>
|
||||
);
|
||||
exitFullScreenButton = <ExitFullScreenButton onExitFullScreenMode={exitFullScreen} />;
|
||||
}
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
|
@ -213,10 +201,9 @@ export class GisMap extends Component {
|
|||
geoFields={this.state.geoFields}
|
||||
renderTooltipContent={renderTooltipContent}
|
||||
/>
|
||||
<ToolbarOverlay
|
||||
addFilters={addFilters}
|
||||
geoFields={this.state.geoFields}
|
||||
/>
|
||||
{!this.props.hideToolbarOverlay && (
|
||||
<ToolbarOverlay addFilters={addFilters} geoFields={this.state.geoFields} />
|
||||
)}
|
||||
<WidgetOverlay/>
|
||||
</EuiFlexItem>
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ import {
|
|||
getLayerList,
|
||||
getMapReady,
|
||||
getGoto,
|
||||
getScrollZoom
|
||||
getScrollZoom,
|
||||
isInteractiveDisabled,
|
||||
isTooltipControlDisabled,
|
||||
} from '../../../selectors/map_selectors';
|
||||
import { getInspectorAdapters } from '../../../reducers/non_serializable_instances';
|
||||
|
||||
|
@ -31,7 +33,9 @@ function mapStateToProps(state = {}) {
|
|||
goto: getGoto(state),
|
||||
inspectorAdapters: getInspectorAdapters(state),
|
||||
tooltipState: getTooltipState(state),
|
||||
scrollZoom: getScrollZoom(state)
|
||||
scrollZoom: getScrollZoom(state),
|
||||
disableInteractive: isInteractiveDisabled(state),
|
||||
disableTooltipControl: isTooltipControlDisabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,10 @@ import { ResizeChecker } from '../../../../../../../../src/plugins/kibana_utils/
|
|||
import {
|
||||
syncLayerOrderForSingleLayer,
|
||||
removeOrphanedSourcesAndLayers,
|
||||
addSpritesheetToMap
|
||||
addSpritesheetToMap,
|
||||
} from './utils';
|
||||
import { getGlyphUrl, isRetina } from '../../../meta';
|
||||
import {
|
||||
DECIMAL_DEGREES_PRECISION,
|
||||
ZOOM_PRECISION,
|
||||
} from '../../../../common/constants';
|
||||
import { DECIMAL_DEGREES_PRECISION, ZOOM_PRECISION } from '../../../../common/constants';
|
||||
import mapboxgl from 'mapbox-gl';
|
||||
import chrome from 'ui/chrome';
|
||||
import { spritesheet } from '@elastic/maki';
|
||||
|
@ -26,7 +23,6 @@ import { DrawControl } from './draw_control';
|
|||
import { TooltipControl } from './tooltip_control';
|
||||
|
||||
export class MBMapContainer extends React.Component {
|
||||
|
||||
state = {
|
||||
prevLayerList: undefined,
|
||||
hasSyncedLayerList: false,
|
||||
|
@ -73,12 +69,15 @@ export class MBMapContainer extends React.Component {
|
|||
_debouncedSync = _.debounce(() => {
|
||||
if (this._isMounted) {
|
||||
if (!this.state.hasSyncedLayerList) {
|
||||
this.setState({
|
||||
hasSyncedLayerList: true
|
||||
}, () => {
|
||||
this._syncMbMapWithLayerList();
|
||||
this._syncMbMapWithInspector();
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
hasSyncedLayerList: true,
|
||||
},
|
||||
() => {
|
||||
this._syncMbMapWithLayerList();
|
||||
this._syncMbMapWithInspector();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}, 256);
|
||||
|
@ -91,25 +90,24 @@ export class MBMapContainer extends React.Component {
|
|||
zoom: _.round(zoom, ZOOM_PRECISION),
|
||||
center: {
|
||||
lon: _.round(mbCenter.lng, DECIMAL_DEGREES_PRECISION),
|
||||
lat: _.round(mbCenter.lat, DECIMAL_DEGREES_PRECISION)
|
||||
lat: _.round(mbCenter.lat, DECIMAL_DEGREES_PRECISION),
|
||||
},
|
||||
extent: {
|
||||
minLon: _.round(mbBounds.getWest(), DECIMAL_DEGREES_PRECISION),
|
||||
minLat: _.round(mbBounds.getSouth(), DECIMAL_DEGREES_PRECISION),
|
||||
maxLon: _.round(mbBounds.getEast(), DECIMAL_DEGREES_PRECISION),
|
||||
maxLat: _.round(mbBounds.getNorth(), DECIMAL_DEGREES_PRECISION)
|
||||
}
|
||||
maxLat: _.round(mbBounds.getNorth(), DECIMAL_DEGREES_PRECISION),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async _createMbMapInstance() {
|
||||
const initialView = this.props.goto ? this.props.goto.center : null;
|
||||
return new Promise((resolve) => {
|
||||
|
||||
return new Promise(resolve => {
|
||||
const mbStyle = {
|
||||
version: 8,
|
||||
sources: {},
|
||||
layers: []
|
||||
layers: [],
|
||||
};
|
||||
const glyphUrl = getGlyphUrl();
|
||||
if (glyphUrl) {
|
||||
|
@ -121,24 +119,25 @@ export class MBMapContainer extends React.Component {
|
|||
container: this.refs.mapContainer,
|
||||
style: mbStyle,
|
||||
scrollZoom: this.props.scrollZoom,
|
||||
preserveDrawingBuffer: chrome.getInjected('preserveDrawingBuffer', false)
|
||||
preserveDrawingBuffer: chrome.getInjected('preserveDrawingBuffer', false),
|
||||
interactive: !this.props.disableInteractive,
|
||||
};
|
||||
if (initialView) {
|
||||
options.zoom = initialView.zoom;
|
||||
options.center = {
|
||||
lng: initialView.lon,
|
||||
lat: initialView.lat
|
||||
lat: initialView.lat,
|
||||
};
|
||||
}
|
||||
const mbMap = new mapboxgl.Map(options);
|
||||
mbMap.dragRotate.disable();
|
||||
mbMap.touchZoomRotate.disableRotation();
|
||||
mbMap.addControl(
|
||||
new mapboxgl.NavigationControl({ showCompass: false }), 'top-left'
|
||||
);
|
||||
if (!this.props.disableInteractive) {
|
||||
mbMap.addControl(new mapboxgl.NavigationControl({ showCompass: false }), 'top-left');
|
||||
}
|
||||
|
||||
let emptyImage;
|
||||
mbMap.on('styleimagemissing', (e) => {
|
||||
mbMap.on('styleimagemissing', e => {
|
||||
if (emptyImage) {
|
||||
mbMap.addImage(e.id, emptyImage);
|
||||
}
|
||||
|
@ -146,7 +145,8 @@ export class MBMapContainer extends React.Component {
|
|||
mbMap.on('load', () => {
|
||||
emptyImage = new Image();
|
||||
// eslint-disable-next-line max-len
|
||||
emptyImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
|
||||
emptyImage.src =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
|
||||
emptyImage.crossOrigin = 'anonymous';
|
||||
resolve(mbMap);
|
||||
});
|
||||
|
@ -157,7 +157,7 @@ export class MBMapContainer extends React.Component {
|
|||
let mbMap;
|
||||
try {
|
||||
mbMap = await this._createMbMapInstance();
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
this.props.setMapInitError(error.message);
|
||||
return;
|
||||
}
|
||||
|
@ -166,14 +166,12 @@ export class MBMapContainer extends React.Component {
|
|||
return;
|
||||
}
|
||||
|
||||
this.setState(
|
||||
{ mbMap },
|
||||
() => {
|
||||
this._loadMakiSprites();
|
||||
this._initResizerChecker();
|
||||
this._registerMapEventListeners();
|
||||
this.props.onMapReady(this._getMapState());
|
||||
});
|
||||
this.setState({ mbMap }, () => {
|
||||
this._loadMakiSprites();
|
||||
this._initResizerChecker();
|
||||
this._registerMapEventListeners();
|
||||
this.props.onMapReady(this._getMapState());
|
||||
});
|
||||
}
|
||||
|
||||
_registerMapEventListeners() {
|
||||
|
@ -181,14 +179,17 @@ export class MBMapContainer extends React.Component {
|
|||
// moveend is fired while the map extent is still changing in the following scenarios
|
||||
// 1) During opening/closing of layer details panel, the EUI animation results in 8 moveend events
|
||||
// 2) Setting map zoom and center from goto is done in 2 API calls, resulting in 2 moveend events
|
||||
this.state.mbMap.on('moveend', _.debounce(() => {
|
||||
this.props.extentChanged(this._getMapState());
|
||||
}, 100));
|
||||
this.state.mbMap.on(
|
||||
'moveend',
|
||||
_.debounce(() => {
|
||||
this.props.extentChanged(this._getMapState());
|
||||
}, 100)
|
||||
);
|
||||
|
||||
const throttledSetMouseCoordinates = _.throttle(e => {
|
||||
this.props.setMouseCoordinates({
|
||||
lat: e.lngLat.lat,
|
||||
lon: e.lngLat.lng
|
||||
lon: e.lngLat.lng,
|
||||
});
|
||||
}, 100);
|
||||
this.state.mbMap.on('mousemove', throttledSetMouseCoordinates);
|
||||
|
@ -212,11 +213,7 @@ export class MBMapContainer extends React.Component {
|
|||
}
|
||||
|
||||
_syncMbMapWithMapState = () => {
|
||||
const {
|
||||
isMapReady,
|
||||
goto,
|
||||
clearGoto,
|
||||
} = this.props;
|
||||
const { isMapReady, goto, clearGoto } = this.props;
|
||||
|
||||
if (!isMapReady || !goto) {
|
||||
return;
|
||||
|
@ -227,8 +224,14 @@ export class MBMapContainer extends React.Component {
|
|||
if (goto.bounds) {
|
||||
//clamping ot -89/89 latitudes since Mapboxgl does not seem to handle bounds that contain the poles (logs errors to the console when using -90/90)
|
||||
const lnLatBounds = new mapboxgl.LngLatBounds(
|
||||
new mapboxgl.LngLat(clamp(goto.bounds.min_lon, -180, 180), clamp(goto.bounds.min_lat, -89, 89)),
|
||||
new mapboxgl.LngLat(clamp(goto.bounds.max_lon, -180, 180), clamp(goto.bounds.max_lat, -89, 89)),
|
||||
new mapboxgl.LngLat(
|
||||
clamp(goto.bounds.min_lon, -180, 180),
|
||||
clamp(goto.bounds.min_lat, -89, 89)
|
||||
),
|
||||
new mapboxgl.LngLat(
|
||||
clamp(goto.bounds.max_lon, -180, 180),
|
||||
clamp(goto.bounds.max_lat, -89, 89)
|
||||
)
|
||||
);
|
||||
//maxZoom ensure we're not zooming in too far on single points or small shapes
|
||||
//the padding is to avoid too tight of a fit around edges
|
||||
|
@ -237,7 +240,7 @@ export class MBMapContainer extends React.Component {
|
|||
this.state.mbMap.setZoom(goto.center.zoom);
|
||||
this.state.mbMap.setCenter({
|
||||
lng: goto.center.lon,
|
||||
lat: goto.center.lat
|
||||
lat: goto.center.lat,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -260,7 +263,6 @@ export class MBMapContainer extends React.Component {
|
|||
const stats = {
|
||||
center: this.state.mbMap.getCenter().toArray(),
|
||||
zoom: this.state.mbMap.getZoom(),
|
||||
|
||||
};
|
||||
this.props.inspectorAdapters.map.setMapState({
|
||||
stats,
|
||||
|
@ -272,20 +274,15 @@ export class MBMapContainer extends React.Component {
|
|||
let drawControl;
|
||||
let tooltipControl;
|
||||
if (this.state.mbMap) {
|
||||
drawControl = (
|
||||
<DrawControl
|
||||
mbMap={this.state.mbMap}
|
||||
addFilters={this.props.addFilters}
|
||||
/>
|
||||
);
|
||||
tooltipControl = (
|
||||
drawControl = <DrawControl mbMap={this.state.mbMap} addFilters={this.props.addFilters} />;
|
||||
tooltipControl = !this.props.disableTooltipControl ? (
|
||||
<TooltipControl
|
||||
mbMap={this.state.mbMap}
|
||||
addFilters={this.props.addFilters}
|
||||
geoFields={this.props.geoFields}
|
||||
renderTooltipContent={this.props.renderTooltipContent}
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
- **isLayerTOCOpen:** (Boolean) Set to false to render map with legend in collapsed state.
|
||||
- **openTOCDetails:** (Array of Strings) Array of layer ids. Add layer id to show layer details on initial render.
|
||||
- **mapCenter:** ({lat, lon, zoom }) Provide mapCenter to customize initial map location.
|
||||
- **disableInteractive:** (Boolean) Will disable map interactions, panning, zooming in the map.
|
||||
- **disableTooltipControl:** (Boolean) Will disable tooltip which shows relevant information on hover, like Continent name etc
|
||||
- **hideToolbarOverlay:** (Boolean) Will disable toolbar, which can be used to navigate to coordinate by entering lat/long and zoom values.
|
||||
|
||||
### Creating a Map embeddable from saved object
|
||||
```
|
||||
|
|
|
@ -10,7 +10,10 @@ import { Provider } from 'react-redux';
|
|||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||
|
||||
import { Embeddable, APPLY_FILTER_TRIGGER } from '../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public';
|
||||
import {
|
||||
Embeddable,
|
||||
APPLY_FILTER_TRIGGER,
|
||||
} from '../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public';
|
||||
import { onlyDisabledFiltersChanged } from '../../../../../../src/plugins/data/public';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
@ -24,12 +27,11 @@ import {
|
|||
setQuery,
|
||||
setRefreshConfig,
|
||||
disableScrollZoom,
|
||||
disableInteractive,
|
||||
disableTooltipControl,
|
||||
hideToolbarOverlay,
|
||||
} from '../actions/map_actions';
|
||||
import {
|
||||
setReadOnly,
|
||||
setIsLayerTOCOpen,
|
||||
setOpenTOCDetails,
|
||||
} from '../actions/ui_actions';
|
||||
import { setReadOnly, setIsLayerTOCOpen, setOpenTOCDetails } from '../actions/ui_actions';
|
||||
import { getIsLayerTOCOpen, getOpenTOCDetails } from '../selectors/ui_selectors';
|
||||
import { getInspectorAdapters, setEventHandlers } from '../reducers/non_serializable_instances';
|
||||
import { getMapCenter, getMapZoom } from '../selectors/map_selectors';
|
||||
|
@ -47,14 +49,15 @@ export class MapEmbeddable extends Embeddable {
|
|||
editable: config.editable,
|
||||
defaultTitle: config.title,
|
||||
},
|
||||
parent);
|
||||
parent
|
||||
);
|
||||
|
||||
this._renderTooltipContent = renderTooltipContent;
|
||||
this._eventHandlers = eventHandlers;
|
||||
this._layerList = config.layerList;
|
||||
this._store = createMapStore();
|
||||
|
||||
this._subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input));
|
||||
this._subscription = this.getInput$().subscribe(input => this.onContainerStateChanged(input));
|
||||
}
|
||||
|
||||
getInspectorAdapters() {
|
||||
|
@ -62,9 +65,11 @@ export class MapEmbeddable extends Embeddable {
|
|||
}
|
||||
|
||||
onContainerStateChanged(containerState) {
|
||||
if (!_.isEqual(containerState.timeRange, this._prevTimeRange) ||
|
||||
!_.isEqual(containerState.query, this._prevQuery) ||
|
||||
!onlyDisabledFiltersChanged(containerState.filters, this._prevFilters)) {
|
||||
if (
|
||||
!_.isEqual(containerState.timeRange, this._prevTimeRange) ||
|
||||
!_.isEqual(containerState.query, this._prevQuery) ||
|
||||
!onlyDisabledFiltersChanged(containerState.filters, this._prevFilters)
|
||||
) {
|
||||
this._dispatchSetQuery(containerState);
|
||||
}
|
||||
|
||||
|
@ -77,20 +82,24 @@ export class MapEmbeddable extends Embeddable {
|
|||
this._prevTimeRange = timeRange;
|
||||
this._prevQuery = query;
|
||||
this._prevFilters = filters;
|
||||
this._store.dispatch(setQuery({
|
||||
filters: filters.filter(filter => !filter.meta.disabled),
|
||||
query,
|
||||
timeFilters: timeRange,
|
||||
refresh,
|
||||
}));
|
||||
this._store.dispatch(
|
||||
setQuery({
|
||||
filters: filters.filter(filter => !filter.meta.disabled),
|
||||
query,
|
||||
timeFilters: timeRange,
|
||||
refresh,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
_dispatchSetRefreshConfig({ refreshConfig }) {
|
||||
this._prevRefreshConfig = refreshConfig;
|
||||
this._store.dispatch(setRefreshConfig({
|
||||
isPaused: refreshConfig.pause,
|
||||
interval: refreshConfig.value,
|
||||
}));
|
||||
this._store.dispatch(
|
||||
setRefreshConfig({
|
||||
isPaused: refreshConfig.pause,
|
||||
interval: refreshConfig.value,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,12 +120,26 @@ export class MapEmbeddable extends Embeddable {
|
|||
this._store.dispatch(setOpenTOCDetails(this.input.openTOCDetails));
|
||||
}
|
||||
|
||||
if (_.has(this.input, 'disableInteractive') && this.input.disableInteractive) {
|
||||
this._store.dispatch(disableInteractive(this.input.disableInteractive));
|
||||
}
|
||||
|
||||
if (_.has(this.input, 'disableTooltipControl') && this.input.disableTooltipControl) {
|
||||
this._store.dispatch(disableTooltipControl(this.input.disableTooltipControl));
|
||||
}
|
||||
|
||||
if (_.has(this.input, 'hideToolbarOverlay') && this.input.hideToolbarOverlay) {
|
||||
this._store.dispatch(hideToolbarOverlay(this.input.hideToolbarOverlay));
|
||||
}
|
||||
|
||||
if (this.input.mapCenter) {
|
||||
this._store.dispatch(setGotoWithCenter({
|
||||
lat: this.input.mapCenter.lat,
|
||||
lon: this.input.mapCenter.lon,
|
||||
zoom: this.input.mapCenter.zoom,
|
||||
}));
|
||||
this._store.dispatch(
|
||||
setGotoWithCenter({
|
||||
lat: this.input.mapCenter.lat,
|
||||
lon: this.input.mapCenter.lon,
|
||||
zoom: this.input.mapCenter.zoom,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this._store.dispatch(replaceLayerList(this._layerList));
|
||||
|
@ -147,7 +170,7 @@ export class MapEmbeddable extends Embeddable {
|
|||
embeddable: this,
|
||||
filters,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
destroy() {
|
||||
super.destroy();
|
||||
|
@ -169,41 +192,41 @@ export class MapEmbeddable extends Embeddable {
|
|||
query: this._prevQuery,
|
||||
timeRange: this._prevTimeRange,
|
||||
filters: this._prevFilters,
|
||||
refresh: true
|
||||
refresh: true,
|
||||
});
|
||||
}
|
||||
|
||||
_handleStoreChanges() {
|
||||
|
||||
const center = getMapCenter(this._store.getState());
|
||||
const zoom = getMapZoom(this._store.getState());
|
||||
|
||||
|
||||
const mapCenter = this.input.mapCenter || {};
|
||||
if (!mapCenter
|
||||
|| mapCenter.lat !== center.lat
|
||||
|| mapCenter.lon !== center.lon
|
||||
|| mapCenter.zoom !== zoom) {
|
||||
if (
|
||||
!mapCenter ||
|
||||
mapCenter.lat !== center.lat ||
|
||||
mapCenter.lon !== center.lon ||
|
||||
mapCenter.zoom !== zoom
|
||||
) {
|
||||
this.updateInput({
|
||||
mapCenter: {
|
||||
lat: center.lat,
|
||||
lon: center.lon,
|
||||
zoom: zoom,
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const isLayerTOCOpen = getIsLayerTOCOpen(this._store.getState());
|
||||
if (this.input.isLayerTOCOpen !== isLayerTOCOpen) {
|
||||
this.updateInput({
|
||||
isLayerTOCOpen
|
||||
isLayerTOCOpen,
|
||||
});
|
||||
}
|
||||
|
||||
const openTOCDetails = getOpenTOCDetails(this._store.getState());
|
||||
if (!_.isEqual(this.input.openTOCDetails, openTOCDetails)) {
|
||||
this.updateInput({
|
||||
openTOCDetails
|
||||
openTOCDetails,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ import {
|
|||
SET_SCROLL_ZOOM,
|
||||
SET_MAP_INIT_ERROR,
|
||||
UPDATE_DRAW_STATE,
|
||||
SET_INTERACTIVE,
|
||||
DISABLE_TOOLTIP_CONTROL,
|
||||
HIDE_TOOLBAR_OVERLAY,
|
||||
} from '../actions/map_actions';
|
||||
|
||||
import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from './util';
|
||||
|
@ -58,12 +61,13 @@ const updateLayerInList = (state, layerId, attribute, newValue) => {
|
|||
...layerList[layerIdx],
|
||||
// Update layer w/ new value. If no value provided, toggle boolean value
|
||||
// allow empty strings, 0-value
|
||||
[attribute]: (newValue || newValue === '' || newValue === 0) ? newValue : !layerList[layerIdx][attribute]
|
||||
[attribute]:
|
||||
newValue || newValue === '' || newValue === 0 ? newValue : !layerList[layerIdx][attribute],
|
||||
};
|
||||
const updatedList = [
|
||||
...layerList.slice(0, layerIdx),
|
||||
updatedLayer,
|
||||
...layerList.slice(layerIdx + 1)
|
||||
...layerList.slice(layerIdx + 1),
|
||||
];
|
||||
return { ...state, layerList: updatedList };
|
||||
};
|
||||
|
@ -76,12 +80,12 @@ const updateLayerSourceDescriptorProp = (state, layerId, propName, value) => {
|
|||
sourceDescriptor: {
|
||||
...layerList[layerIdx].sourceDescriptor,
|
||||
[propName]: value,
|
||||
}
|
||||
},
|
||||
};
|
||||
const updatedList = [
|
||||
...layerList.slice(0, layerIdx),
|
||||
updatedLayer,
|
||||
...layerList.slice(layerIdx + 1)
|
||||
...layerList.slice(layerIdx + 1),
|
||||
];
|
||||
return { ...state, layerList: updatedList };
|
||||
};
|
||||
|
@ -95,7 +99,7 @@ const INITIAL_STATE = {
|
|||
zoom: 4,
|
||||
center: {
|
||||
lon: -100.41,
|
||||
lat: 32.82
|
||||
lat: 32.82,
|
||||
},
|
||||
scrollZoom: true,
|
||||
extent: null,
|
||||
|
@ -105,7 +109,10 @@ const INITIAL_STATE = {
|
|||
filters: [],
|
||||
refreshConfig: null,
|
||||
refreshTimerLastTriggeredAt: null,
|
||||
drawState: null
|
||||
drawState: null,
|
||||
disableInteractive: false,
|
||||
disableTooltipControl: false,
|
||||
hideToolbarOverlay: false
|
||||
},
|
||||
selectedLayerId: null,
|
||||
__transientLayerId: null,
|
||||
|
@ -113,7 +120,6 @@ const INITIAL_STATE = {
|
|||
waitingForMapReadyLayerList: [],
|
||||
};
|
||||
|
||||
|
||||
export function map(state = INITIAL_STATE, action) {
|
||||
switch (action.type) {
|
||||
case UPDATE_DRAW_STATE:
|
||||
|
@ -121,8 +127,8 @@ export function map(state = INITIAL_STATE, action) {
|
|||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
drawState: action.drawState
|
||||
}
|
||||
drawState: action.drawState,
|
||||
},
|
||||
};
|
||||
case REMOVE_TRACKED_LAYER_STATE:
|
||||
return removeTrackedLayerState(state, action.layerId);
|
||||
|
@ -133,7 +139,7 @@ export function map(state = INITIAL_STATE, action) {
|
|||
case SET_TOOLTIP_STATE:
|
||||
return {
|
||||
...state,
|
||||
tooltipState: action.tooltipState
|
||||
tooltipState: action.tooltipState,
|
||||
};
|
||||
case SET_MOUSE_COORDINATES:
|
||||
return {
|
||||
|
@ -142,25 +148,25 @@ export function map(state = INITIAL_STATE, action) {
|
|||
...state.mapState,
|
||||
mouseCoordinates: {
|
||||
lat: action.lat,
|
||||
lon: action.lon
|
||||
}
|
||||
}
|
||||
lon: action.lon,
|
||||
},
|
||||
},
|
||||
};
|
||||
case CLEAR_MOUSE_COORDINATES:
|
||||
return {
|
||||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
mouseCoordinates: null
|
||||
}
|
||||
mouseCoordinates: null,
|
||||
},
|
||||
};
|
||||
case SET_GOTO:
|
||||
return {
|
||||
...state,
|
||||
goto: {
|
||||
center: action.center,
|
||||
bounds: action.bounds
|
||||
}
|
||||
bounds: action.bounds,
|
||||
},
|
||||
};
|
||||
case CLEAR_GOTO:
|
||||
return {
|
||||
|
@ -181,10 +187,10 @@ export function map(state = INITIAL_STATE, action) {
|
|||
{
|
||||
...layerList[layerIdx],
|
||||
__isInErrorState: action.isInErrorState,
|
||||
__errorMessage: action.errorMessage
|
||||
__errorMessage: action.errorMessage,
|
||||
},
|
||||
...layerList.slice(layerIdx + 1)
|
||||
]
|
||||
...layerList.slice(layerIdx + 1),
|
||||
],
|
||||
};
|
||||
case UPDATE_SOURCE_DATA_REQUEST:
|
||||
return updateSourceDataRequest(state, action);
|
||||
|
@ -226,7 +232,7 @@ export function map(state = INITIAL_STATE, action) {
|
|||
query,
|
||||
timeFilters,
|
||||
filters,
|
||||
}
|
||||
},
|
||||
};
|
||||
case SET_REFRESH_CONFIG:
|
||||
const { isPaused, interval } = action;
|
||||
|
@ -237,16 +243,16 @@ export function map(state = INITIAL_STATE, action) {
|
|||
refreshConfig: {
|
||||
isPaused,
|
||||
interval,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
case TRIGGER_REFRESH_TIMER:
|
||||
return {
|
||||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
refreshTimerLastTriggeredAt: (new Date()).toISOString(),
|
||||
}
|
||||
refreshTimerLastTriggeredAt: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
case SET_SELECTED_LAYER:
|
||||
const selectedMatch = state.layerList.find(layer => layer.id === action.selectedLayerId);
|
||||
|
@ -255,16 +261,23 @@ export function map(state = INITIAL_STATE, action) {
|
|||
const transientMatch = state.layerList.find(layer => layer.id === action.transientLayerId);
|
||||
return { ...state, __transientLayerId: transientMatch ? action.transientLayerId : null };
|
||||
case UPDATE_LAYER_ORDER:
|
||||
return { ...state, layerList: action.newLayerOrder.map(layerNumber => state.layerList[layerNumber]) };
|
||||
return {
|
||||
...state,
|
||||
layerList: action.newLayerOrder.map(layerNumber => state.layerList[layerNumber]),
|
||||
};
|
||||
case UPDATE_LAYER_PROP:
|
||||
return updateLayerInList(state, action.id, action.propName, action.newValue);
|
||||
case UPDATE_SOURCE_PROP:
|
||||
return updateLayerSourceDescriptorProp(state, action.layerId, action.propName, action.value);
|
||||
case SET_JOINS:
|
||||
const layerDescriptor = state.layerList.find(descriptor => descriptor.id === action.layer.getId());
|
||||
const layerDescriptor = state.layerList.find(
|
||||
descriptor => descriptor.id === action.layer.getId()
|
||||
);
|
||||
if (layerDescriptor) {
|
||||
const newLayerDescriptor = { ...layerDescriptor, joins: action.joins.slice() };
|
||||
const index = state.layerList.findIndex(descriptor => descriptor.id === action.layer.getId());
|
||||
const index = state.layerList.findIndex(
|
||||
descriptor => descriptor.id === action.layer.getId()
|
||||
);
|
||||
const newLayerList = state.layerList.slice();
|
||||
newLayerList[index] = newLayerDescriptor;
|
||||
return { ...state, layerList: newLayerList };
|
||||
|
@ -273,35 +286,28 @@ export function map(state = INITIAL_STATE, action) {
|
|||
case ADD_LAYER:
|
||||
return {
|
||||
...state,
|
||||
layerList: [
|
||||
...state.layerList,
|
||||
action.layer
|
||||
]
|
||||
layerList: [...state.layerList, action.layer],
|
||||
};
|
||||
case REMOVE_LAYER:
|
||||
return {
|
||||
...state, layerList: [...state.layerList.filter(
|
||||
({ id }) => id !== action.id)]
|
||||
...state,
|
||||
layerList: [...state.layerList.filter(({ id }) => id !== action.id)],
|
||||
};
|
||||
case ADD_WAITING_FOR_MAP_READY_LAYER:
|
||||
return {
|
||||
...state,
|
||||
waitingForMapReadyLayerList: [
|
||||
...state.waitingForMapReadyLayerList,
|
||||
action.layer
|
||||
]
|
||||
waitingForMapReadyLayerList: [...state.waitingForMapReadyLayerList, action.layer],
|
||||
};
|
||||
case CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST:
|
||||
return {
|
||||
...state,
|
||||
waitingForMapReadyLayerList: []
|
||||
waitingForMapReadyLayerList: [],
|
||||
};
|
||||
case TOGGLE_LAYER_VISIBLE:
|
||||
return updateLayerInList(state, action.layerId, 'visible');
|
||||
case UPDATE_LAYER_STYLE:
|
||||
const styleLayerId = action.layerId;
|
||||
return updateLayerInList(state, styleLayerId, 'style',
|
||||
{ ...action.style });
|
||||
return updateLayerInList(state, styleLayerId, 'style', { ...action.style });
|
||||
case SET_LAYER_STYLE_META:
|
||||
const { layerId, styleMeta } = action;
|
||||
const index = getLayerIndex(state.layerList, layerId);
|
||||
|
@ -309,19 +315,46 @@ export function map(state = INITIAL_STATE, action) {
|
|||
return state;
|
||||
}
|
||||
|
||||
return updateLayerInList(state, layerId, 'style', { ...state.layerList[index].style, __styleMeta: styleMeta });
|
||||
return updateLayerInList(state, layerId, 'style', {
|
||||
...state.layerList[index].style,
|
||||
__styleMeta: styleMeta,
|
||||
});
|
||||
case SET_SCROLL_ZOOM:
|
||||
return {
|
||||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
scrollZoom: action.scrollZoom,
|
||||
}
|
||||
},
|
||||
};
|
||||
case SET_MAP_INIT_ERROR:
|
||||
return {
|
||||
...state,
|
||||
mapInitError: action.errorMessage
|
||||
mapInitError: action.errorMessage,
|
||||
};
|
||||
case SET_INTERACTIVE:
|
||||
return {
|
||||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
disableInteractive: action.disableInteractive,
|
||||
},
|
||||
};
|
||||
case DISABLE_TOOLTIP_CONTROL:
|
||||
return {
|
||||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
disableTooltipControl: action.disableTooltipControl,
|
||||
},
|
||||
};
|
||||
case HIDE_TOOLBAR_OVERLAY:
|
||||
return {
|
||||
...state,
|
||||
mapState: {
|
||||
...state.mapState,
|
||||
hideToolbarOverlay: action.hideToolbarOverlay,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
|
@ -329,7 +362,6 @@ export function map(state = INITIAL_STATE, action) {
|
|||
}
|
||||
|
||||
function findDataRequest(layerDescriptor, dataRequestAction) {
|
||||
|
||||
if (!layerDescriptor.__dataRequests) {
|
||||
return;
|
||||
}
|
||||
|
@ -339,18 +371,18 @@ function findDataRequest(layerDescriptor, dataRequestAction) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
function updateWithDataRequest(state, action) {
|
||||
let dataRequest = getValidDataRequest(state, action, false);
|
||||
const layerRequestingData = findLayerById(state, action.layerId);
|
||||
|
||||
if (!dataRequest) {
|
||||
dataRequest = {
|
||||
dataId: action.dataId
|
||||
dataId: action.dataId,
|
||||
};
|
||||
layerRequestingData.__dataRequests = [
|
||||
...(layerRequestingData.__dataRequests
|
||||
? layerRequestingData.__dataRequests : []), dataRequest ];
|
||||
...(layerRequestingData.__dataRequests ? layerRequestingData.__dataRequests : []),
|
||||
dataRequest,
|
||||
];
|
||||
}
|
||||
dataRequest.dataMetaAtStart = action.meta;
|
||||
dataRequest.dataRequestToken = action.requestToken;
|
||||
|
@ -358,13 +390,12 @@ function updateWithDataRequest(state, action) {
|
|||
return { ...state, layerList };
|
||||
}
|
||||
|
||||
|
||||
function updateSourceDataRequest(state, action) {
|
||||
const layerDescriptor = findLayerById(state, action.layerId);
|
||||
if (!layerDescriptor) {
|
||||
return state;
|
||||
}
|
||||
const dataRequest = layerDescriptor.__dataRequests.find(dataRequest => {
|
||||
const dataRequest = layerDescriptor.__dataRequests.find(dataRequest => {
|
||||
return dataRequest.dataId === SOURCE_DATA_ID_ORIGIN;
|
||||
});
|
||||
if (!dataRequest) {
|
||||
|
@ -375,10 +406,11 @@ function updateSourceDataRequest(state, action) {
|
|||
return resetDataRequest(state, action, dataRequest);
|
||||
}
|
||||
|
||||
|
||||
function updateWithDataResponse(state, action) {
|
||||
const dataRequest = getValidDataRequest(state, action);
|
||||
if (!dataRequest) { return state; }
|
||||
if (!dataRequest) {
|
||||
return state;
|
||||
}
|
||||
|
||||
dataRequest.data = action.data;
|
||||
dataRequest.dataMeta = { ...dataRequest.dataMetaAtStart, ...action.meta };
|
||||
|
@ -388,7 +420,9 @@ function updateWithDataResponse(state, action) {
|
|||
|
||||
function resetDataRequest(state, action, request) {
|
||||
const dataRequest = request || getValidDataRequest(state, action);
|
||||
if (!dataRequest) { return state; }
|
||||
if (!dataRequest) {
|
||||
return state;
|
||||
}
|
||||
|
||||
dataRequest.dataRequestToken = null;
|
||||
dataRequest.dataId = action.dataId;
|
||||
|
@ -429,7 +463,7 @@ function trackCurrentLayerState(state, layerId) {
|
|||
}
|
||||
|
||||
function removeTrackedLayerState(state, layerId) {
|
||||
const layer = findLayerById(state, layerId);
|
||||
const layer = findLayerById(state, layerId);
|
||||
if (!layer) {
|
||||
return state;
|
||||
}
|
||||
|
@ -439,7 +473,7 @@ function removeTrackedLayerState(state, layerId) {
|
|||
|
||||
return {
|
||||
...state,
|
||||
layerList: replaceInLayerList(state.layerList, layerId, copyLayer)
|
||||
layerList: replaceInLayerList(state.layerList, layerId, copyLayer),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -459,7 +493,7 @@ function rollbackTrackedLayerState(state, layerId) {
|
|||
|
||||
return {
|
||||
...state,
|
||||
layerList: replaceInLayerList(state.layerList, layerId, rolledbackLayer)
|
||||
layerList: replaceInLayerList(state.layerList, layerId, rolledbackLayer),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,12 @@ export const getWaitingForMapReadyLayerListRaw = ({ map }) => map.waitingForMapR
|
|||
|
||||
export const getScrollZoom = ({ map }) => map.mapState.scrollZoom;
|
||||
|
||||
export const isInteractiveDisabled = ({ map }) => map.mapState.disableInteractive;
|
||||
|
||||
export const isTooltipControlDisabled = ({ map }) => map.mapState.disableTooltipControl;
|
||||
|
||||
export const isToolbarOverlayHidden = ({ map }) => map.mapState.hideToolbarOverlay;
|
||||
|
||||
export const getMapExtent = ({ map }) => map.mapState.extent ?
|
||||
map.mapState.extent : {};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue