]> git.localhorst.tv Git - alttp.git/blob - resources/js/components/map/OpenSeadragon.js
second underworld map
[alttp.git] / resources / js / components / map / OpenSeadragon.js
1 import axios from 'axios';
2 import OpenSeadragon from 'openseadragon';
3 import PropTypes from 'prop-types';
4 import React from 'react';
5 import { useNavigate, useParams } from 'react-router';
6 import { createSearchParams, useSearchParams } from 'react-router-dom';
7
8 export const Context = React.createContext({});
9
10 export const useOpenSeadragon = () => React.useContext(Context);
11
12 export const Provider = React.forwardRef(({ children }, ref) => {
13         const { activeMap } = useParams();
14         const navigate = useNavigate();
15         const [searchParams, setSearchParams] = useSearchParams();
16         const [pins, setPins] = React.useState([]);
17         const [viewer, setViewer] = React.useState(null);
18
19         const storePosition = React.useCallback(() => {
20                 if (!viewer || !viewer.viewport) return;
21                 const center = viewer.viewport.getCenter();
22                 const zoom = viewer.viewport.getZoom();
23                 setSearchParams({ x: center.x, y: center.y, z: zoom }, { replace: true });
24         }, [setSearchParams, viewer]);
25
26         const setActiveMap = React.useCallback(map => {
27                 if (viewer && viewer.viewport) {
28                         const center = viewer.viewport.getCenter();
29                         const zoom = viewer.viewport.getZoom();
30                         const params = { x: center.x, y: center.y, z: zoom };
31                         navigate(
32                                 { pathname: `../${map}`, search: `?${createSearchParams(params)}` },
33                                 { replace: true },
34                         );
35                 } else {
36                         navigate(`../${map}`, { replace: true });
37                 }
38         }, [navigate, viewer]);
39
40         React.useEffect(() => {
41                 if (!viewer || !viewer.viewport) return;
42                 if (searchParams.has('x') && searchParams.has('y')) {
43                         viewer.viewport.panTo(new OpenSeadragon.Point(
44                                 parseFloat(searchParams.get('x')),
45                                 parseFloat(searchParams.get('y')),
46                         ));
47                 }
48                 if (searchParams.has('z')) {
49                         viewer.viewport.zoomTo(parseFloat(searchParams.get('z')));
50                 }
51         }, [searchParams, viewer]);
52
53         React.useEffect(() => {
54                 if (!ref.current) return;
55
56                 const v = OpenSeadragon({
57                         element: ref.current,
58                         preserveViewport: true,
59                         sequenceMode: true,
60                         showNavigator: true,
61                         showNavigationControl: false,
62                         showSequenceControl: false,
63                         tileSources: [
64                                 new OpenSeadragon.DziTileSource({
65                                         width: 8192,
66                                         height: 8192,
67                                         tileSize: 256,
68                                         tileOverlap: 0,
69                                         minLevel: 8,
70                                         maxLevel: 13,
71                                         tilesUrl: '/media/alttp/map/lw_files/',
72                                         fileFormat: 'png',
73                                 }), new OpenSeadragon.DziTileSource({
74                                         width: 8192,
75                                         height: 8192,
76                                         tileSize: 256,
77                                         tileOverlap: 0,
78                                         minLevel: 8,
79                                         maxLevel: 13,
80                                         tilesUrl: '/media/alttp/map/dw_files/',
81                                         fileFormat: 'png',
82                                 }), new OpenSeadragon.DziTileSource({
83                                         width: 8192,
84                                         height: 4096,
85                                         tileSize: 256,
86                                         tileOverlap: 0,
87                                         minLevel: 8,
88                                         maxLevel: 13,
89                                         tilesUrl: '/media/alttp/map/sp_files/',
90                                         fileFormat: 'png',
91                                 }), new OpenSeadragon.DziTileSource({
92                                         width: 16384,
93                                         height: 16384,
94                                         tileSize: 256,
95                                         tileOverlap: 0,
96                                         minLevel: 8,
97                                         maxLevel: 14,
98                                         tilesUrl: '/media/alttp/map/uw_files/',
99                                         fileFormat: 'png',
100                                 }), new OpenSeadragon.DziTileSource({
101                                         width: 16384,
102                                         height: 3072,
103                                         tileSize: 256,
104                                         tileOverlap: 0,
105                                         minLevel: 8,
106                                         maxLevel: 14,
107                                         tilesUrl: '/media/alttp/map/uw2_files/',
108                                         fileFormat: 'png',
109                                 }),
110                         ],
111                 });
112                 setViewer(v);
113                 return () => {
114                         v.destroy();
115                 };
116         }, [ref.current]);
117
118         React.useEffect(() => {
119                 if (!viewer) return;
120                 switch (activeMap) {
121                         case 'lw':
122                                 viewer.goToPage(0);
123                                 break;
124                         case 'dw':
125                                 viewer.goToPage(1);
126                                 break;
127                         case 'sp':
128                                 viewer.goToPage(2);
129                                 break;
130                         case 'uw':
131                                 viewer.goToPage(3);
132                                 break;
133                         case 'uw2':
134                                 viewer.goToPage(4);
135                                 break;
136                 }
137                 const controller = new AbortController();
138                 axios.get(`/api/markers/${activeMap}`, {
139                         signal: controller.signal,
140                 }).then(response => {
141                         setPins(response.data || []);
142                 }).catch(e => {
143                         if (!axios.isCancel(e)) {
144                                 console.error(e);
145                         }
146                 });
147                 return () => {
148                         controller.abort();
149                 };
150         }, [activeMap, viewer]);
151
152         return <Context.Provider value={{ activeMap, pins, setActiveMap, storePosition, viewer }}>
153                 {children}
154         </Context.Provider>;
155 });
156
157 Provider.displayName = 'OpenSeadragonProvider';
158
159 Provider.propTypes = {
160         children: PropTypes.node,
161 };
162
163 export default Provider;