]> git.localhorst.tv Git - alttp.git/blobdiff - resources/js/components/map/OpenSeadragon.js
clean up manual tracking
[alttp.git] / resources / js / components / map / OpenSeadragon.js
index f8543189e18c3b71ea4344be4e3ba0634d58fbc1..36ddec1ce4c0685ba471ce101b4913c04f503cf3 100644 (file)
@@ -1,14 +1,55 @@
+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 } = 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;
 
@@ -56,16 +97,66 @@ export const Provider = React.forwardRef(({ children }, ref) => {
                                        maxLevel: 14,
                                        tilesUrl: '/media/alttp/map/uw_files/',
                                        fileFormat: 'png',
+                               }), new OpenSeadragon.DziTileSource({
+                                       width: 16384,
+                                       height: 3072,
+                                       tileSize: 256,
+                                       tileOverlap: 0,
+                                       minLevel: 8,
+                                       maxLevel: 14,
+                                       tilesUrl: '/media/alttp/map/uw2_files/',
+                                       fileFormat: 'png',
                                }),
                        ],
                });
+               v.addHandler('canvas-nonprimary-press', e => {
+                       if (e.button === 3) {
+                               navigate(-1);
+                       } else if (e.button === 4) {
+                               navigate(1);
+                       }
+               });
                setViewer(v);
                return () => {
                        v.destroy();
                };
        }, [ref.current]);
 
-       return <Context.Provider value={{ viewer }}>
+       React.useEffect(() => {
+               if (!viewer) return;
+               switch (activeMap) {
+                       case 'lw':
+                               viewer.goToPage(0);
+                               break;
+                       case 'dw':
+                               viewer.goToPage(1);
+                               break;
+                       case 'sp':
+                               viewer.goToPage(2);
+                               break;
+                       case 'uw':
+                               viewer.goToPage(3);
+                               break;
+                       case 'uw2':
+                               viewer.goToPage(4);
+                               break;
+               }
+               const controller = new AbortController();
+               axios.get(`/api/markers/${activeMap}`, {
+                       signal: controller.signal,
+               }).then(response => {
+                       setPins(response.data || []);
+               }).catch(e => {
+                       if (!axios.isCancel(e)) {
+                               console.error(e);
+                       }
+               });
+               return () => {
+                       controller.abort();
+               };
+       }, [activeMap, viewer]);
+
+       return <Context.Provider value={{ activeMap, pins, setActiveMap, storePosition, viewer }}>
                {children}
        </Context.Provider>;
 });