From f0ca8caa3db00bedbf2b992d3d72b401bf353689 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 12 Jul 2023 11:16:33 +0200 Subject: [PATCH] store map position in history --- app/Http/Controllers/SitemapXmlController.php | 17 +++++--- resources/js/components/app/Header.js | 4 +- resources/js/components/app/index.js | 5 ++- resources/js/components/map/Item.js | 8 ++-- resources/js/components/map/OpenSeadragon.js | 42 ++++++++++++++++++- resources/js/components/map/Pin.js | 4 ++ resources/js/components/pages/Map.js | 4 +- resources/views/sitemap.blade.php | 4 +- 8 files changed, 71 insertions(+), 17 deletions(-) diff --git a/app/Http/Controllers/SitemapXmlController.php b/app/Http/Controllers/SitemapXmlController.php index 99e9092..4393a30 100644 --- a/app/Http/Controllers/SitemapXmlController.php +++ b/app/Http/Controllers/SitemapXmlController.php @@ -23,12 +23,17 @@ class SitemapXmlController extends Controller $urls[] = $url; } - $url = new SitemapUrl(); - $url->path = '/map'; - $url->lastmod = TechniqueMap::latest()->first()->created_at; - $url->changefreq = 'monthly'; - $url->priority = 0.9; - $urls[] = $url; + foreach (['lw', 'dw', 'sp', 'uw'] as $map) { + $tech = TechniqueMap::where('map', '=', $map)->latest()->first(); + $url = new SitemapUrl(); + $url->path = '/map/'.$map; + if ($tech) { + $url->lastmod = $tech->created_at; + } + $url->changefreq = 'monthly'; + $url->priority = 0.9; + $urls[] = $url; + } $url = new SitemapUrl(); $url->path = '/tech'; diff --git a/resources/js/components/app/Header.js b/resources/js/components/app/Header.js index db59b40..f806bbc 100644 --- a/resources/js/components/app/Header.js +++ b/resources/js/components/app/Header.js @@ -39,8 +39,8 @@ const Header = ({ doLogout, user }) => { {t('menu.tech')} - - + + {t('menu.map')} diff --git a/resources/js/components/app/index.js b/resources/js/components/app/index.js index e8a56e6..e7298d7 100644 --- a/resources/js/components/app/index.js +++ b/resources/js/components/app/index.js @@ -87,7 +87,10 @@ const App = () => { path="locations/:name" element={} /> - } /> + + } /> + } /> + } diff --git a/resources/js/components/map/Item.js b/resources/js/components/map/Item.js index 4bd209a..a29443b 100644 --- a/resources/js/components/map/Item.js +++ b/resources/js/components/map/Item.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Button } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; +import { Link, useSearchParams } from 'react-router-dom'; import { useOpenSeadragon } from './OpenSeadragon'; import Icon from '../common/Icon'; @@ -19,12 +19,12 @@ import i18n from '../../i18n'; const Item = ({ pin }) => { const { viewer } = useOpenSeadragon(); + const [, setSearchParams] = useSearchParams(); const { t } = useTranslation(); const goToLocation = React.useCallback(pin => { - if (viewer && viewer.viewport) { - viewer.viewport.panTo(new OpenSeadragon.Point(pin.x, pin.y)); - viewer.viewport.zoomTo(4); + setSearchParams({ x: pin.x, y: pin.y, z: 4 }); + if (viewer && viewer.element) { viewer.element.scrollIntoView(); } }, [viewer]); diff --git a/resources/js/components/map/OpenSeadragon.js b/resources/js/components/map/OpenSeadragon.js index b6158a5..52c0506 100644 --- a/resources/js/components/map/OpenSeadragon.js +++ b/resources/js/components/map/OpenSeadragon.js @@ -2,16 +2,54 @@ import axios from 'axios'; import OpenSeadragon from 'openseadragon'; import PropTypes from 'prop-types'; import React from 'react'; +import { useNavigate, useParams } from 'react-router'; +import { createSearchParams, useSearchParams } from 'react-router-dom'; export const Context = React.createContext({}); export const useOpenSeadragon = () => React.useContext(Context); export const Provider = React.forwardRef(({ children }, ref) => { - const [activeMap, setActiveMap] = React.useState('lw'); + const { activeMap } = useParams(); + const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); const [pins, setPins] = React.useState([]); const [viewer, setViewer] = React.useState(null); + const storePosition = React.useCallback(() => { + if (!viewer || !viewer.viewport) return; + const center = viewer.viewport.getCenter(); + const zoom = viewer.viewport.getZoom(); + setSearchParams({ x: center.x, y: center.y, z: zoom }, { replace: true }); + }, [setSearchParams, viewer]); + + const setActiveMap = React.useCallback(map => { + if (viewer && viewer.viewport) { + const center = viewer.viewport.getCenter(); + const zoom = viewer.viewport.getZoom(); + const params = { x: center.x, y: center.y, z: zoom }; + navigate( + { pathname: `../${map}`, search: `?${createSearchParams(params)}` }, + { replace: true }, + ); + } else { + navigate(`../${map}`, { replace: true }); + } + }, [navigate, viewer]); + + React.useEffect(() => { + if (!viewer || !viewer.viewport) return; + if (searchParams.has('x') && searchParams.has('y')) { + viewer.viewport.panTo(new OpenSeadragon.Point( + parseFloat(searchParams.get('x')), + parseFloat(searchParams.get('y')), + )); + } + if (searchParams.has('z')) { + viewer.viewport.zoomTo(parseFloat(searchParams.get('z'))); + } + }, [searchParams, viewer]); + React.useEffect(() => { if (!ref.current) return; @@ -99,7 +137,7 @@ export const Provider = React.forwardRef(({ children }, ref) => { }; }, [activeMap, viewer]); - return + return {children} ; }); diff --git a/resources/js/components/map/Pin.js b/resources/js/components/map/Pin.js index 69b6d77..442e16d 100644 --- a/resources/js/components/map/Pin.js +++ b/resources/js/components/map/Pin.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Link, useNavigate } from 'react-router-dom'; +import { useOpenSeadragon } from './OpenSeadragon'; import Overlay from './Overlay'; import Popover from './Popover'; import Icon from '../common/Icon'; @@ -9,6 +10,7 @@ import { getLink, getTranslation } from '../../helpers/Technique'; import i18n from '../../i18n'; const Pin = ({ pin }) => { + const { storePosition } = useOpenSeadragon(); const [showPopover, setShowPopover] = React.useState(false); const ref = React.useRef(); @@ -17,12 +19,14 @@ const Pin = ({ pin }) => { const onClick = React.useCallback((e) => { if (ref.current && ref.current.contains(e.originalTarget)) { if (e.originalTarget.tagName === 'A') { + storePosition(); navigate(new URL(e.originalTarget.href).pathname); } } else { if (pin.technique.type === 'location') { setShowPopover(s => !s); } else { + storePosition(); navigate(getLink(pin.technique)); } } diff --git a/resources/js/components/pages/Map.js b/resources/js/components/pages/Map.js index 09e381a..3cbd31f 100644 --- a/resources/js/components/pages/Map.js +++ b/resources/js/components/pages/Map.js @@ -2,6 +2,7 @@ import React from 'react'; import { Container } from 'react-bootstrap'; import { Helmet } from 'react-helmet'; import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router'; import CanonicalLinks from '../common/CanonicalLinks'; import Buttons from '../map/Buttons'; @@ -13,6 +14,7 @@ import UWSuperTiles from '../map/UWSuperTiles'; const Map = () => { const [uwOverlay, setUWOverlay] = React.useState(false); + const { activeMap } = useParams(); const container = React.useRef(); const { t } = useTranslation(); @@ -21,7 +23,7 @@ const Map = () => { {t('map.heading')} - +

{t('map.heading')}

diff --git a/resources/views/sitemap.blade.php b/resources/views/sitemap.blade.php index f9cf5bf..375be39 100644 --- a/resources/views/sitemap.blade.php +++ b/resources/views/sitemap.blade.php @@ -3,7 +3,9 @@ @foreach ($urls as $url) {{ url($url->path) }} - {{ $url->lastmod->tz('UTC')->toAtomString() }} + @if ($url->lastmod) + {{ $url->lastmod->tz('UTC')->toAtomString() }} + @endif {{ $url->changefreq }} {{ $url->priority }} -- 2.39.2