From 777c143db052765a93ba44a109c459c0bc1a41ac Mon Sep 17 00:00:00 2001 From: esikkala <esko.ikkala@aalto.fi> Date: Mon, 31 May 2021 10:38:55 +0300 Subject: [PATCH] ClientFS maps: add zoom and center to app state --- src/client/actions/index.js | 6 ++- src/client/components/facet_results/Deck.js | 23 +++++++--- .../components/facet_results/LeafletMap.js | 28 +++++++++--- .../sampo/FacetedSearchPerspective.js | 4 -- .../perspectives/sampo/Perspective1.js | 43 ++++++++++--------- .../perspectives/sampo/Perspective2.js | 4 -- .../perspectives/sampo/Perspective3.js | 17 +++----- src/client/containers/SemanticPortal.js | 3 +- src/client/reducers/general/helpers.js | 16 +++++-- src/client/reducers/general/results.js | 4 +- src/client/reducers/sampo/perspective1.js | 25 ++++++++++- src/client/reducers/sampo/perspective2.js | 2 +- src/client/reducers/sampo/perspective3.js | 11 ++++- src/client/reducers/sampo/places.js | 10 +---- .../sparql/sampo/BackendSearchConfig.js | 6 +++ 15 files changed, 132 insertions(+), 70 deletions(-) diff --git a/src/client/actions/index.js b/src/client/actions/index.js index f56bcfc9..f634bee4 100644 --- a/src/client/actions/index.js +++ b/src/client/actions/index.js @@ -77,14 +77,16 @@ export const fetchResults = ({ facetClass, uri = null, limit = null, - optimize = null + optimize = null, + reason = null }) => ({ type: FETCH_RESULTS, resultClass, facetClass, uri, limit, - optimize + optimize, + reason }) export const fetchInstanceAnalysis = ({ resultClass, diff --git a/src/client/components/facet_results/Deck.js b/src/client/components/facet_results/Deck.js index 2996b023..ca5b4c8f 100644 --- a/src/client/components/facet_results/Deck.js +++ b/src/client/components/facet_results/Deck.js @@ -53,9 +53,9 @@ const styles = theme => ({ class Deck extends React.Component { state = { viewport: { - longitude: 10.37, - latitude: 22.43, - zoom: 2, + longitude: this.props.center[1], + latitude: this.props.center[0], + zoom: this.props.zoom, pitch: 0, bearing: 0, width: 100, @@ -95,6 +95,16 @@ class Deck extends React.Component { // } } + componentStateEqualsReduxState = () => { + const { viewport } = this.state + const { longitude, latitude, zoom } = viewport + return ( + zoom === this.props.zoom && + longitude === this.props.center[1] && + latitude === this.props.center[0] + ) + } + setDialog = info => { this.setState({ dialog: { @@ -119,8 +129,11 @@ class Deck extends React.Component { } }) - handleOnViewportChange = viewport => - this.state.mounted && this.setState({ viewport }); + handleOnViewportChange = viewport => { + if (this.state.mounted) { + this.setState({ viewport }) + } + } renderSpinner () { if (this.props.fetching || this.props.fetchingInstanceAnalysisData) { diff --git a/src/client/components/facet_results/LeafletMap.js b/src/client/components/facet_results/LeafletMap.js index d65b9299..a19f58b4 100644 --- a/src/client/components/facet_results/LeafletMap.js +++ b/src/client/components/facet_results/LeafletMap.js @@ -149,12 +149,18 @@ class LeafletMap extends React.Component { } serverFScomponentDidUpdate = (prevProps, prevState) => { + // check if map center or zoom was modified in Redux state + if (!this.componentStateEqualsReduxState()) { + this.leafletMap.setView(this.props.center, this.props.zoom) + } + // check if filters have changed if (has(prevProps, 'facetUpdateID') && prevProps.facetUpdateID !== this.props.facetUpdateID) { this.props.fetchResults({ resultClass: this.props.resultClass, facetClass: this.props.facetClass, - sortBy: null + sortBy: null, + reason: 'facetUpdate' }) } @@ -359,10 +365,22 @@ class LeafletMap extends React.Component { } updateMapBounds = () => { - this.props.updateMapBounds({ - resultClass: this.props.resultClass, - bounds: this.boundsToObject() - }) + if (!this.componentStateEqualsReduxState()) { + this.props.updateMapBounds({ + resultClass: this.props.resultClass, + bounds: this.boundsToObject() + }) + } + } + + componentStateEqualsReduxState = () => { + const currentZoom = this.leafletMap.getZoom() + const currentCenter = this.leafletMap.getCenter() + return ( + currentZoom === this.props.zoom && + currentCenter[0] === this.props.center[0] && + currentCenter[1] === this.props.center[1] + ) } setCustomMapControlVisibility = () => { diff --git a/src/client/components/perspectives/sampo/FacetedSearchPerspective.js b/src/client/components/perspectives/sampo/FacetedSearchPerspective.js index ebce6b6d..58059076 100644 --- a/src/client/components/perspectives/sampo/FacetedSearchPerspective.js +++ b/src/client/components/perspectives/sampo/FacetedSearchPerspective.js @@ -59,10 +59,6 @@ FacetedSearchPerspective.propTypes = { /** * Faceted search configs and results of places related to this perspective. */ - placesState: PropTypes.object.isRequired, - /** - * Facet configs and values. - */ facetState: PropTypes.object.isRequired, /** * Facet values where facets constrain themselves, used for statistics. diff --git a/src/client/components/perspectives/sampo/Perspective1.js b/src/client/components/perspectives/sampo/Perspective1.js index 96b31c65..4441a2c6 100644 --- a/src/client/components/perspectives/sampo/Perspective1.js +++ b/src/client/components/perspectives/sampo/Perspective1.js @@ -56,12 +56,12 @@ const Perspective1 = props => { path={`${rootUrl}/${perspective.id}/faceted-search/production_places`} render={() => <LeafletMap - center={[22.43, 10.37]} - zoom={2} + center={props.perspectiveState.maps.placesMsProduced.center} + zoom={props.perspectiveState.maps.placesMsProduced.zoom} // center={[60.187, 24.821]} // zoom={13} // locateUser - results={props.placesState.results} + results={props.perspectiveState.results} leafletMapState={props.leafletMapState} pageType='facetResults' facetUpdateID={props.facetState.facetUpdateID} @@ -70,7 +70,7 @@ const Perspective1 = props => { resultClass='placesMsProduced' facetClass='perspective1' mapMode='cluster' - instance={props.placesState.instanceTableData} + instance={props.perspectiveState.instanceTableData} createPopUpContent={createPopUpContentMMM} popupMaxHeight={320} popupMinWidth={280} @@ -78,9 +78,10 @@ const Perspective1 = props => { fetchGeoJSONLayers={props.fetchGeoJSONLayers} clearGeoJSONLayers={props.clearGeoJSONLayers} fetchByURI={props.fetchByURI} - fetching={props.placesState.fetching} + fetching={props.perspectiveState.fetching} showInstanceCountInClusters updateFacetOption={props.updateFacetOption} + updateMapBounds={props.updateMapBounds} showError={props.showError} showExternalLayers layerControlExpanded={layerControlExpanded} @@ -99,24 +100,27 @@ const Perspective1 = props => { path={`${rootUrl}/${perspective.id}/faceted-search/production_places_heatmap`} render={() => <Deck - results={props.placesState.results} + center={props.perspectiveState.maps.placesMsProducedHeatmap.center} + zoom={props.perspectiveState.maps.placesMsProducedHeatmap.zoom} + results={props.perspectiveState.results} facetUpdateID={props.facetState.facetUpdateID} - resultClass='placesMsProduced' + resultClass='placesMsProducedHeatmap' facetClass='perspective1' fetchResults={props.fetchResults} - fetching={props.placesState.fetching} + fetching={props.perspectiveState.fetching} layerType='heatmapLayer' mapBoxAccessToken={MAPBOX_ACCESS_TOKEN} mapBoxStyle={MAPBOX_STYLE} + updateMapBounds={props.updateMapBounds} />} /> <Route path={`${rootUrl}/${perspective.id}/faceted-search/last_known_locations`} render={() => <LeafletMap - center={[22.43, 10.37]} - zoom={2} - results={props.placesState.results} + center={props.perspectiveState.maps.lastKnownLocations.center} + zoom={props.perspectiveState.maps.lastKnownLocations.zoom} + results={props.perspectiveState.results} leafletMapState={props.leafletMapState} pageType='facetResults' facetUpdateID={props.facetState.facetUpdateID} @@ -126,7 +130,7 @@ const Perspective1 = props => { facetClass='perspective1' mapMode='cluster' showMapModeControl={false} - instance={props.placesState.instanceTableData} + instance={props.perspectiveState.instanceTableData} createPopUpContent={createPopUpContentMMM} popupMaxHeight={320} popupMinWidth={280} @@ -134,9 +138,10 @@ const Perspective1 = props => { fetchGeoJSONLayers={props.fetchGeoJSONLayers} clearGeoJSONLayers={props.clearGeoJSONLayers} fetchByURI={props.fetchByURI} - fetching={props.placesState.fetching} + fetching={props.perspectiveState.fetching} showInstanceCountInClusters updateFacetOption={props.updateFacetOption} + updateMapBounds={props.updateMapBounds} showError={props.showError} showExternalLayers layerControlExpanded={layerControlExpanded} @@ -150,14 +155,14 @@ const Perspective1 = props => { <Deck results={props.placesState.results} facetUpdateID={props.facetState.facetUpdateID} - instanceAnalysisData={props.placesState.instanceAnalysisData} - instanceAnalysisDataUpdateID={props.placesState.instanceAnalysisDataUpdateID} + instanceAnalysisData={props.perspectiveState.instanceAnalysisData} + instanceAnalysisDataUpdateID={props.perspectiveState.instanceAnalysisDataUpdateID} resultClass='placesMsMigrations' facetClass='perspective1' fetchResults={props.fetchResults} fetchInstanceAnalysis={props.fetchInstanceAnalysis} - fetching={props.placesState.fetching} - fetchingInstanceAnalysisData={props.placesState.fetchingInstanceAnalysisData} + fetching={props.perspectiveState.fetching} + fetchingInstanceAnalysisData={props.perspectiveState.fetchingInstanceAnalysisData} layerType='arcLayer' getArcWidth={d => d.instanceCountScaled} fromText={intl.get('deckGlMap.manuscriptMigrations.from')} @@ -272,10 +277,6 @@ Perspective1.propTypes = { * Faceted search configs and results of this perspective. */ perspectiveState: PropTypes.object.isRequired, - /** - * Faceted search configs and results of places related to this perspective. - */ - placesState: PropTypes.object.isRequired, /** * Facet configs and values. */ diff --git a/src/client/components/perspectives/sampo/Perspective2.js b/src/client/components/perspectives/sampo/Perspective2.js index 6e04ed19..119eaac1 100644 --- a/src/client/components/perspectives/sampo/Perspective2.js +++ b/src/client/components/perspectives/sampo/Perspective2.js @@ -58,10 +58,6 @@ Perspective2.propTypes = { /** * Faceted search configs and results of places related to this perspective. */ - placesState: PropTypes.object.isRequired, - /** - * Facet configs and values. - */ facetState: PropTypes.object.isRequired, /** * Facet values where facets constrain themselves, used for statistics. diff --git a/src/client/components/perspectives/sampo/Perspective3.js b/src/client/components/perspectives/sampo/Perspective3.js index 1fd21321..3fa7f134 100644 --- a/src/client/components/perspectives/sampo/Perspective3.js +++ b/src/client/components/perspectives/sampo/Perspective3.js @@ -43,10 +43,10 @@ const Perspective3 = props => { path={`${rootUrl}/${perspective.id}/faceted-search/map`} render={() => <LeafletMap - center={[22.43, 10.37]} - zoom={2} - results={props.placesState.results} - layers={props.leafletMapLayers} + center={props.perspectiveState.maps.placesEvents.center} + zoom={props.perspectiveState.maps.placesEvents.zoom} + results={props.perspectiveState.results} + leafletMapState={props.leafletMapState} pageType='facetResults' facetUpdateID={props.facetState.facetUpdateID} facet={props.facetState.facets.place} @@ -54,7 +54,7 @@ const Perspective3 = props => { resultClass='placesEvents' facetClass='perspective3' mapMode='cluster' - instance={props.placesState.instanceTableData} + instance={props.perspectiveState.instanceTableData} createPopUpContent={createPopUpContentMMM} popupMaxHeight={320} popupMinWidth={280} @@ -62,9 +62,10 @@ const Perspective3 = props => { fetchGeoJSONLayers={props.fetchGeoJSONLayers} clearGeoJSONLayers={props.clearGeoJSONLayers} fetchByURI={props.fetchByURI} - fetching={props.placesState.fetching} + fetching={props.perspectiveState.fetching} showInstanceCountInClusters updateFacetOption={props.updateFacetOption} + updateMapBounds={props.updateMapBounds} showError={props.showError} showExternalLayers layerControlExpanded={layerControlExpanded} @@ -96,10 +97,6 @@ Perspective3.propTypes = { /** * Faceted search configs and results of places related to this perspective. */ - placesState: PropTypes.object.isRequired, - /** - * Facet configs and values. - */ facetState: PropTypes.object.isRequired, /** * Facet values where facets constrain themselves, used for statistics. diff --git a/src/client/containers/SemanticPortal.js b/src/client/containers/SemanticPortal.js index 8c21861d..1ecf54a8 100644 --- a/src/client/containers/SemanticPortal.js +++ b/src/client/containers/SemanticPortal.js @@ -385,7 +385,6 @@ const SemanticPortal = props => { <Grid item xs={12} md={9} className={classes.resultsContainer}> <FacetedSearchPerspective perspectiveState={props[`${perspective.id}`]} - placesState={props.places} facetState={props[`${perspective.id}Facets`]} facetConstrainSelfState={has(props, `${perspective.id}FacetsConstrainSelf`) ? props[`${perspective.id}FacetsConstrainSelf`] @@ -402,6 +401,7 @@ const SemanticPortal = props => { updatePage={props.updatePage} updateRowsPerPage={props.updateRowsPerPage} updateFacetOption={props.updateFacetOption} + updateMapBounds={props.updateMapBounds} sortResults={props.sortResults} showError={props.showError} routeProps={routeProps} @@ -462,6 +462,7 @@ const SemanticPortal = props => { clearGeoJSONLayers={props.clearGeoJSONLayers} leafletMap={props.leafletMap} showError={props.showError} + updateMapBounds={props.updateMapBounds} /> </Grid> </Grid> diff --git a/src/client/reducers/general/helpers.js b/src/client/reducers/general/helpers.js index 56a2a4ae..7dfb9b52 100644 --- a/src/client/reducers/general/helpers.js +++ b/src/client/reducers/general/helpers.js @@ -1,12 +1,22 @@ import { has, isEmpty } from 'lodash' import { UPDATE_FACET_VALUES_CONSTRAIN_SELF } from '../../actions' -export const fetchResults = (state, action) => { +export const fetchResults = (state, action, initialState) => { + const { reason } = action + let resetMapBounds = false + if ( + reason && + reason === 'facetUpdate' && + initialState.maps + ) { + resetMapBounds = true + } return { ...state, instance: null, instanceTableExternalData: null, - fetching: true + fetching: true, + ...(resetMapBounds && { maps: initialState.maps }) } } @@ -203,7 +213,7 @@ export const updateResultCount = (state, action) => { } } -export const updateResults = (state, action) => { +export const updateResults = (state, action, initialState) => { return { ...state, results: action.data, diff --git a/src/client/reducers/general/results.js b/src/client/reducers/general/results.js index 6b798d23..8bd1f3eb 100644 --- a/src/client/reducers/general/results.js +++ b/src/client/reducers/general/results.js @@ -38,12 +38,12 @@ import { updateMapBounds } from './helpers' -export const handleDataFetchingAction = (state, action) => { +export const handleDataFetchingAction = (state, action, initialState) => { switch (action.type) { case FETCH_RESULTS: case FETCH_PAGINATED_RESULTS: case FETCH_BY_URI: - return fetchResults(state, action) + return fetchResults(state, action, initialState) case FETCH_RESULT_COUNT: return fetchResultCount(state) case FETCH_INSTANCE_ANALYSIS: diff --git a/src/client/reducers/sampo/perspective1.js b/src/client/reducers/sampo/perspective1.js index 60cc633c..bbc3cb18 100644 --- a/src/client/reducers/sampo/perspective1.js +++ b/src/client/reducers/sampo/perspective1.js @@ -21,6 +21,24 @@ export const INITIAL_STATE = { instanceAnalysisData: null, instanceAnalysisDataUpdateID: 0, instanceSparqlQuery: null, + maps: { + placesMsProduced: { + center: [22.43, 10.37], + zoom: 2 + }, + placesMsProducedHeatmap: { + center: [22.43, 10.37], + zoom: 2 + }, + lastKnownLocations: { + center: [22.43, 10.37], + zoom: 2 + }, + placesMsMigrations: { + center: [22.43, 10.37], + zoom: 2 + } + }, properties: [ { id: 'uri', @@ -260,6 +278,11 @@ export const INITIAL_STATE = { const resultClasses = new Set([ 'perspective1', + 'placesMsProduced', + 'placesMsProducedHeatmap', + 'lastKnownLocations', + 'placesMsMigrations', + 'placesMsMigrationsDialog', 'productionTimespanLineChart', 'eventLineChart', 'manuscriptInstancePageNetwork', @@ -269,7 +292,7 @@ const resultClasses = new Set([ const perspective1 = (state = INITIAL_STATE, action) => { if (resultClasses.has(action.resultClass)) { - return handleDataFetchingAction(state, action) + return handleDataFetchingAction(state, action, INITIAL_STATE) } else return state } diff --git a/src/client/reducers/sampo/perspective2.js b/src/client/reducers/sampo/perspective2.js index 34df248a..487dc2c0 100644 --- a/src/client/reducers/sampo/perspective2.js +++ b/src/client/reducers/sampo/perspective2.js @@ -112,7 +112,7 @@ const resultClasses = new Set([ const perspective2 = (state = INITIAL_STATE, action) => { if (resultClasses.has(action.resultClass)) { - return handleDataFetchingAction(state, action) + return handleDataFetchingAction(state, action, INITIAL_STATE) } else return state } diff --git a/src/client/reducers/sampo/perspective3.js b/src/client/reducers/sampo/perspective3.js index f79c4f06..b0ae522d 100644 --- a/src/client/reducers/sampo/perspective3.js +++ b/src/client/reducers/sampo/perspective3.js @@ -20,6 +20,12 @@ export const INITIAL_STATE = { instanceAnalysisData: null, instanceAnalysisDataUpdateID: 0, instanceSparqlQuery: null, + maps: { + placesEvents: { + center: [22.43, 10.37], + zoom: 2 + } + }, properties: [ { id: 'uri', @@ -123,12 +129,13 @@ export const INITIAL_STATE = { } const resultClasses = new Set([ - 'perspective3' + 'perspective3', + 'placesEvents' ]) const perspective3 = (state = INITIAL_STATE, action) => { if (resultClasses.has(action.resultClass)) { - return handleDataFetchingAction(state, action) + return handleDataFetchingAction(state, action, INITIAL_STATE) } else return state } diff --git a/src/client/reducers/sampo/places.js b/src/client/reducers/sampo/places.js index c6b3e64e..f39668c2 100644 --- a/src/client/reducers/sampo/places.js +++ b/src/client/reducers/sampo/places.js @@ -110,15 +110,7 @@ export const INITIAL_STATE = { } const resultClasses = new Set([ - 'places', - 'placesAll', - 'placesActors', - 'placesMsProduced', - 'lastKnownLocations', - 'placesMsMigrations', - 'placesMsMigrationsDialog', - 'placesEvents', - 'findsPlaces' + 'places' ]) const places = (state = INITIAL_STATE, action) => { diff --git a/src/server/sparql/sampo/BackendSearchConfig.js b/src/server/sparql/sampo/BackendSearchConfig.js index 95665447..43e86292 100644 --- a/src/server/sparql/sampo/BackendSearchConfig.js +++ b/src/server/sparql/sampo/BackendSearchConfig.js @@ -131,6 +131,12 @@ export const backendSearchConfig = { relatedInstances: manuscriptsProducedAt } }, + placesMsProducedHeatmap: { + perspectiveID: 'perspective1', + q: productionPlacesQuery, + filterTarget: 'manuscripts', + resultMapper: mapPlaces + }, lastKnownLocations: { perspectiveID: 'perspective1', q: lastKnownLocationsQuery, -- GitLab