[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:
Shahzad 2019-11-27 19:41:26 +01:00 committed by GitHub
parent 03d08c3d79
commit 328ae2b0d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 265 additions and 194 deletions

View file

@ -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 };
}

View file

@ -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),
};
}

View file

@ -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>

View file

@ -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)
};
}

View file

@ -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

View file

@ -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
```

View file

@ -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,
});
}
}

View file

@ -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),
};
}

View file

@ -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 : {};