Skip to content

Commit

Permalink
Merge pull request #1351 from jolevesq/1328-store-ol
Browse files Browse the repository at this point in the history
refactor(store): Moved OL events in the store (#1351)

Co-Authored-By: Johann Levesque <[email protected]>
  • Loading branch information
jolevesq and Johann Levesque authored Sep 28, 2023
2 parents 57be5af + 93b6839 commit da0b3f6
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 194 deletions.
2 changes: 1 addition & 1 deletion packages/geoview-core/public/templates/default-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ <h4 id="HLCONF7">7. Load config from function call</h4>

if (cgpv.api.maps['CONF7']) {
setTimeout(() => {
cgpv.api.maps['CONF7'].loadMapConfig(`{
cgpv.api.maps['CONF7'].loadMapFromJsonStringConfig (`{
'map': {
'interaction': 'dynamic',
'viewSettings': {
Expand Down
4 changes: 2 additions & 2 deletions packages/geoview-core/public/templates/languages.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ <h4 id="HLNG3">3. English</h4>
cgpv.api.createMapFromConfig('LNG1', config);

// loads config in blank map
// cgpv.api.maps['LNG2'].loadMapConfig(config);
// cgpv.api.maps['LNG2'].loadMapFromJsonStringConfig (config);
// TODO: Investigate part of #1118, if we remove the calss on div it works by passing with getValidMapConfig
// if using the loadMapConfig (when cass exist) it fails for the second map. This whole start from function must be refactor.
// if using the loadMapFromJsonStringConfig (when cass exist) it fails for the second map. This whole start from function must be refactor.
setTimeout(() => {
cgpv.api.createMapFromConfig('LNG2', config);
cgpv.api.createMapFromConfig('LNG3', config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ <h4 id="HUC2">2. Layer Panel with layers in config</h4>
<script src="codedoc.js"></script>
<script>
function reloadMap() {
cgpv.api.maps['mapWM'].loadMapConfig(`{
cgpv.api.maps['mapWM'].loadMapFromJsonStringConfig (`{
'map': {
'interaction': 'dynamic',
'viewSettings': {
Expand Down
4 changes: 2 additions & 2 deletions packages/geoview-core/public/templates/theme-switching.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ <h1><strong>Theme Switching</strong></h1>
}

function reloadMap(theme) {
cgpv.api.maps['mapWM1'].loadMapConfig(JSON.stringify({ ...config, theme: theme }))
cgpv.api.maps['mapWM1'].loadMapFromJsonStringConfig (JSON.stringify({ ...config, theme: theme }))
}

// initialize cgpv and api events, a callback is optional, used if calling api's after the rendering is ready
Expand All @@ -132,7 +132,7 @@ <h1><strong>Theme Switching</strong></h1>
// !put a timeout to show the problem.... map is loaded with default configt then the function trigger
// !basemap good, one secondlater bad bassemap. After using the droopdown to set, everything is good
// TODO: Refactor loading, related to language as well #1118
setTimeout(() => cgpv.api.maps['mapWM1'].loadMapConfig(JSON.stringify(config)), 2000);
setTimeout(() => cgpv.api.maps['mapWM1'].loadMapFromJsonStringConfig (JSON.stringify(config)), 2000);

//create snippets
createConfigSnippet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import { EVENT_NAMES } from '../events/event-types';

export class AppBarEventProcessor extends AbstractEventProcessor {
onInitialize(store: GeoViewStoreType) {
const unsub = store.subscribe((curState, prevState) => {
if (curState.appBarState.geoLocatorActive !== prevState.appBarState.geoLocatorActive) {
api.event.emit(
booleanPayload(EVENT_NAMES.GEOLOCATOR.EVENT_GEOLOCATOR_TOGGLE, curState.mapId, curState.appBarState.geoLocatorActive)
);
const { mapId } = store.getState();

const unsubGeolocatorToggle = store.subscribe(
(state) => state.appBarState.geoLocatorActive,
(cur, prev) => {
if (cur !== prev) api.event.emit(booleanPayload(EVENT_NAMES.GEOLOCATOR.EVENT_GEOLOCATOR_TOGGLE, mapId, cur));
}
});
);

// add to arr of subscriptions so it can be destroyed later
this.subscriptionArr.push(unsub);
this.subscriptionArr.push(unsubGeolocatorToggle);
}
}
57 changes: 45 additions & 12 deletions packages/geoview-core/src/api/eventProcessors/map-event-process.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,61 @@
import { GeoViewStoreType } from '@/core/stores/geoview-store';
import { AbstractEventProcessor } from './abstract-event-processor';
import { api } from '@/app';
import { mapPayload, lngLatPayload, mapMouseEventPayload } from '@/api/events/payloads';
import { mapPayload, lngLatPayload, mapMouseEventPayload, numberPayload } from '@/api/events/payloads';
import { EVENT_NAMES } from '@/api/events/event-types';

export class MapEventProcessor extends AbstractEventProcessor {
onInitialize(store: GeoViewStoreType) {
const unsub = store.subscribe((curState, prevState) => {
if (curState.mapState.mapLoaded && prevState.mapState.mapLoaded === false && curState.mapState.mapElement) {
api.event.emit(mapPayload(EVENT_NAMES.MAP.EVENT_MAP_LOADED, curState.mapId, curState.mapState.mapElement));
const { mapId } = store.getState();

const unsubMapLoaded = store.subscribe(
(state) => state.mapState.mapLoaded,
(cur, prev) => {
if (cur !== prev) api.event.emit(mapPayload(EVENT_NAMES.MAP.EVENT_MAP_LOADED, mapId, store.getState().mapState.mapElement!));
}
);

const unsubMapCenterCoord = store.subscribe(
(state) => state.mapState.mapCenterCoordinates,
(cur, prev) => {
if (cur !== prev) {
api.maps[mapId].mapCenterCoordinates = cur;
api.event.emit(lngLatPayload(EVENT_NAMES.MAP.EVENT_MAP_MOVE_END, mapId, cur));
}
}
);

const unsubMapPointerPosition = store.subscribe(
(state) => state.mapState.pointerPosition,
(cur, prev) => {
if (cur !== prev) {
api.maps[mapId].pointerPosition = cur!;
api.event.emit(mapMouseEventPayload(EVENT_NAMES.MAP.EVENT_MAP_POINTER_MOVE, mapId, cur!));
}
}
);

if (curState.mapState.mapCenterCoordinates !== prevState.mapState.mapCenterCoordinates) {
api.maps[curState.mapId].mapCenterCoordinates = curState.mapState.mapCenterCoordinates;
api.event.emit(lngLatPayload(EVENT_NAMES.MAP.EVENT_MAP_MOVE_END, curState.mapId, curState.mapState.mapCenterCoordinates));
const unsubMapZoom = store.subscribe(
(state) => state.mapState.zoom,
(cur, prev) => {
if (cur !== prev) {
api.maps[mapId].currentZoom = cur!;
api.event.emit(numberPayload(EVENT_NAMES.MAP.EVENT_MAP_ZOOM_END, mapId, cur!));
}
}
);

if (curState.mapState.pointerPosition !== prevState.mapState.pointerPosition) {
api.maps[curState.mapId].pointerPosition = curState.mapState.pointerPosition!;
api.event.emit(mapMouseEventPayload(EVENT_NAMES.MAP.EVENT_MAP_POINTER_MOVE, curState.mapId, curState.mapState.pointerPosition!));
const unsubMapSingleClick = store.subscribe(
(state) => state.mapState.mapClickCoordinates,
(cur, prev) => {
if (cur !== prev) {
api.maps[mapId].singleClickedPosition = cur!;
api.event.emit(mapMouseEventPayload(EVENT_NAMES.MAP.EVENT_MAP_SINGLE_CLICK, mapId, cur!));
}
}
});
);

// add to arr of subscriptions so it can be destroyed later
this.subscriptionArr.push(unsub);
this.subscriptionArr.push(unsubMapLoaded, unsubMapCenterCoord, unsubMapPointerPosition, unsubMapZoom, unsubMapSingleClick);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import CircleStyle from 'ol/style/Circle';
import { getUid } from 'ol';
import { MapContext } from '@/core/app-start';

import { getGeoViewStore } from '@/core/stores/stores-managers';

import { PayloadBaseClass, TypeFeatureInfoEntry, api, payloadIsAllQueriesDone } from '@/app';
import { EVENT_NAMES } from '@/api/events/event-types';
import { ClickMapMarker } from '@/ui';

import {
payloadIsAMarkerDefinition,
payloadIsAMapMouseEvent,
featureHighlightPayload,
payloadIsAFeatureHighlight,
clearHighlightsPayload,
Expand All @@ -34,7 +35,7 @@ import {
*/
export function ClickMarker(): JSX.Element {
const [showMarker, setShowMarker] = useState(false);
const markerCoordinates = useRef<Coordinate>([0, 0]);
const markerCoordinates = useRef<Coordinate>();
const clickMarkerRef = useRef<HTMLDivElement>(null);

const mapConfig = useContext(MapContext);
Expand All @@ -46,7 +47,7 @@ export function ClickMarker(): JSX.Element {
id: clickMarkerId,
position: [-1, -1],
positioning: 'center-center',
offset: [0, -8],
offset: [-18, -32],
element: document.getElementById(clickMarkerId) as HTMLElement,
stopEvent: false,
});
Expand Down Expand Up @@ -79,9 +80,14 @@ export function ClickMarker(): JSX.Element {
* @param {Coordinate} lnglat the coordinate where to show the marker
*/
function showMarkerIcon(lnglat: Coordinate) {
// toggle the marker icon
setShowMarker(false); // to restart the opacity animation
// if not in timeout, it is always set back to center
setTimeout(() => {
api.maps[mapId].map
.getOverlayById(`${mapId}-clickmarker`)
.setPosition(fromLonLat(lnglat, `EPSG:${api.maps[mapId].currentProjection}`));
}, 0);
setShowMarker(true);
api.maps[mapId].map.getOverlayById(`${mapId}-clickmarker`).setPosition(fromLonLat(lnglat, `EPSG:${api.maps[mapId].currentProjection}`));
}

/**
Expand Down Expand Up @@ -315,44 +321,50 @@ export function ClickMarker(): JSX.Element {

if (feature) {
api.event.emit(featureHighlightPayload(EVENT_NAMES.FEATURE_HIGHLIGHT.EVENT_HIGHLIGHT_FEATURE, mapId, feature));
} else showMarkerIcon(markerCoordinates.current);
setShowMarker(false);
} else showMarkerIcon(markerCoordinates.current!);
}
};

const eventMarkerIconHideListenerFunction = () => setShowMarker(false);
const eventMarkerIconShowListenerFunction = (payload: PayloadBaseClass) => {
if (payloadIsAMarkerDefinition(payload)) {
// TODO: Also implement a symbology define by the payload for feature details item selection.
showMarkerIcon(payload.lnglat);
}
};

const eventMapSingleClickListenerFunction = (payload: PayloadBaseClass) => {
if (payloadIsAMapMouseEvent(payload)) {
removeIcon();
markerCoordinates.current = payload.coordinates.lnglat;
api.event.emit(clearHighlightsPayload(EVENT_NAMES.FEATURE_HIGHLIGHT.EVENT_HIGHLIGHT_CLEAR, mapId, 'all'));
}
};

const eventMarkerIconHideListenerFunction = () => setShowMarker(false);

useEffect(() => {
const { map } = api.maps[mapId];
// if mapClickCoordinates changed, single click event has been triggered
const unsubMapSingleClick = getGeoViewStore(mapId).subscribe(
(state) => state.mapState.mapClickCoordinates,
(curClick, prevClick) => {
if (curClick !== prevClick) {
showMarkerIcon(curClick!.lnglat);
markerCoordinates.current = curClick!.lnglat;
api.event.emit(clearHighlightsPayload(EVENT_NAMES.FEATURE_HIGHLIGHT.EVENT_HIGHLIGHT_CLEAR, mapId, 'all'));
}
}
);

// remove the marker on map zoom and move
map.getView().on('change:resolution', removeIcon);
map.on('movestart', removeIcon);
// if mapCenterCoordinates changed, map move end event has been triggered
const unsubMapCenterCoord = getGeoViewStore(mapId).subscribe(
(state) => state.mapState.mapCenterCoordinates,
(curCenterCoord, prevCenterCoord) => {
if (curCenterCoord !== prevCenterCoord) setShowMarker(false);
}
);

api.event.on(EVENT_NAMES.MAP.EVENT_MAP_SINGLE_CLICK, eventMapSingleClickListenerFunction, mapId);
api.event.on(EVENT_NAMES.GET_FEATURE_INFO.ALL_QUERIES_DONE, allQueriesDoneListenerFunction, `${mapId}/$FeatureInfoLayerSet$`);
api.event.on(EVENT_NAMES.MARKER_ICON.EVENT_MARKER_ICON_SHOW, eventMarkerIconShowListenerFunction, mapId);
api.event.on(EVENT_NAMES.MARKER_ICON.EVENT_MARKER_ICON_HIDE, eventMarkerIconHideListenerFunction, mapId);
api.event.on(EVENT_NAMES.FEATURE_HIGHLIGHT.EVENT_HIGHLIGHT_FEATURE, highlightCallbackFunction, mapId);
api.event.on(EVENT_NAMES.FEATURE_HIGHLIGHT.EVENT_HIGHLIGHT_CLEAR, clearHighlightCallbackFunction, mapId);

return () => {
unsubMapSingleClick();
unsubMapCenterCoord();
api.event.off(EVENT_NAMES.GET_FEATURE_INFO.ALL_QUERIES_DONE, mapId, allQueriesDoneListenerFunction);
api.event.off(EVENT_NAMES.MAP.EVENT_MAP_SINGLE_CLICK, mapId, eventMapSingleClickListenerFunction);
api.event.off(EVENT_NAMES.MARKER_ICON.EVENT_MARKER_ICON_SHOW, mapId, eventMarkerIconShowListenerFunction);
api.event.off(EVENT_NAMES.MARKER_ICON.EVENT_MARKER_ICON_HIDE, mapId, eventMarkerIconHideListenerFunction);
api.event.off(EVENT_NAMES.FEATURE_HIGHLIGHT.EVENT_HIGHLIGHT_FEATURE, mapId, highlightCallbackFunction);
Expand All @@ -363,7 +375,21 @@ export function ClickMarker(): JSX.Element {

return (
<div ref={clickMarkerRef} id={clickMarkerId} style={{ position: 'absolute', visibility: showMarker ? 'visible' : 'hidden' }}>
<ClickMapMarker fontSize="medium" color="action" />
<ClickMapMarker
sx={{
animation: 'opacity 1s ease-in',
'@keyframes opacity': {
from: {
opacity: 0,
},
to: {
opacity: 1,
},
},
}}
fontSize="large"
color="warning"
/>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,6 @@ export function FeatureInfo(props: TypeFeatureProps): JSX.Element {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

// todo keep the marker to be showing up
/* useEffect(() => {
api.event.emit(markerDefinitionPayload(api.eventNames.MARKER_ICON.EVENT_MARKER_ICON_SHOW, handlerName, location, {} as TypeJsonObject));
}, [currentZoom, location, handlerName]);
*/

/**
* Parse the content of the field to see if we need to create an image, a string element or a link
* @param {TypeFieldEntry} featureInfoItem the field item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getUid } from 'ol/util';
import { getGeoViewStore } from '@/core/stores/stores-managers';

import { Box } from '@/ui';
import { api, payloadIsAMapMouseEvent } from '@/app';
import { api } from '@/app';
import { MapContext } from '@/core/app-start';
import { EVENT_NAMES } from '@/api/events/event-types';
import { PayloadBaseClass, TypeFeatureInfoEntry, payloadIsAllQueriesDone, payloadIsHoverQueryDone } from '@/api/events/payloads';
Expand Down Expand Up @@ -101,16 +101,9 @@ export function HoverTooltip(): JSX.Element {
}
};

const mapSingleClickListenerFunction = (payload: PayloadBaseClass) => {
if (payloadIsAMapMouseEvent(payload)) {
selectedFeature.current = undefined;
setShowTooltip(false);
setTooltipValue('');
}
};

useEffect(() => {
const unsubA = getGeoViewStore(mapId).subscribe(
// if pointerPosition changed, map pointer event has been triggered
const unsubMapPointer = getGeoViewStore(mapId).subscribe(
(state) => state.mapState.pointerPosition,
(curPos, prevPos) => {
if (curPos !== prevPos) {
Expand All @@ -121,20 +114,29 @@ export function HoverTooltip(): JSX.Element {
}
);

// if mapClickCoordinates changed, single click event has been triggered
const unsubMapSingleClick = getGeoViewStore(mapId).subscribe(
(state) => state.mapState.mapClickCoordinates,
(curClick, prevClick) => {
if (curClick !== prevClick) {
selectedFeature.current = undefined;
setShowTooltip(false);
setTooltipValue('');
}
}
);

// listen to hover query done event
api.event.on(EVENT_NAMES.GET_FEATURE_INFO.HOVER_QUERY_DONE, hoverQueryDoneListenerFunction, `${mapId}/$FeatureInfoLayerSet$`);

// Get a feature when it is selected
api.event.on(EVENT_NAMES.GET_FEATURE_INFO.ALL_QUERIES_DONE, allQueriesDoneListenerFunciton, `${mapId}/$FeatureInfoLayerSet$`);

// Hide tooltip on map click, and clear selected feature
api.event.on(EVENT_NAMES.MAP.EVENT_MAP_SINGLE_CLICK, mapSingleClickListenerFunction, mapId);

return () => {
api.event.off(EVENT_NAMES.GET_FEATURE_INFO.HOVER_QUERY_DONE, mapId, hoverQueryDoneListenerFunction);
api.event.off(EVENT_NAMES.GET_FEATURE_INFO.ALL_QUERIES_DONE, mapId, allQueriesDoneListenerFunciton);
api.event.off(EVENT_NAMES.MAP.EVENT_MAP_SINGLE_CLICK, mapId, mapSingleClickListenerFunction);
unsubA();
unsubMapPointer();
unsubMapSingleClick();
};

// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
Loading

0 comments on commit da0b3f6

Please sign in to comment.