"localforage": "^1.10.0",
"moment": "^2.29.1",
"numeral": "^2.0.6",
+ "openseadragon": "^4.0.0",
"pusher-js": "^7.0.6",
"qs": "^6.10.3",
"react-bootstrap": "^2.2.0",
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/openseadragon": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.0.0.tgz",
+ "integrity": "sha512-HsjSgqiiPwLkW5576GxDJ7Rax96iLUET8fnTsJvu7uYYkd+qzen3bflxHyph0OVVgZBKP9SpGH1nPdU4Mz0Z2A==",
+ "funding": {
+ "url": "https://opencollective.com/openseadragon"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
"is-wsl": "^2.2.0"
}
},
+ "openseadragon": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.0.0.tgz",
+ "integrity": "sha512-HsjSgqiiPwLkW5576GxDJ7Rax96iLUET8fnTsJvu7uYYkd+qzen3bflxHyph0OVVgZBKP9SpGH1nPdU4Mz0Z2A=="
+ },
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
"localforage": "^1.10.0",
"moment": "^2.29.1",
"numeral": "^2.0.6",
+ "openseadragon": "^4.0.0",
"pusher-js": "^7.0.6",
"qs": "^6.10.3",
"react-bootstrap": "^2.2.0",
import Header from './common/Header';
import AlttpSeed from './pages/AlttpSeed';
import Front from './pages/Front';
+import Map from './pages/Map';
import Technique from './pages/Technique';
import Techniques from './pages/Techniques';
import Tournament from './pages/Tournament';
<Header doLogout={doLogout} />
<Routes>
<Route path="h/:hash" element={<AlttpSeed />} />
+ <Route path="map" element={<Map />} />
<Route
path="modes"
element={<Techniques namespace="modes" type="mode" />}
--- /dev/null
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import { useOpenSeadragon } from './OpenSeadragon';
+
+const Buttons = () => {
+ const { viewer } = useOpenSeadragon();
+ const { t } = useTranslation();
+
+ const goToPage = React.useCallback((p) => {
+ if (viewer) viewer.goToPage(p);
+ }, [viewer]);
+
+ return <div className="button-bar">
+ <Button
+ onClick={() => goToPage(0)}
+ title={t('map.lwLong')}
+ variant="outline-secondary"
+ >
+ {t('map.lwShort')}
+ </Button>
+ <Button
+ onClick={() => goToPage(1)}
+ title={t('map.dwLong')}
+ variant="outline-secondary"
+ >
+ {t('map.dwShort')}
+ </Button>
+ <Button
+ onClick={() => goToPage(2)}
+ title={t('map.spLong')}
+ variant="outline-secondary"
+ >
+ {t('map.spShort')}
+ </Button>
+ <Button
+ onClick={() => goToPage(3)}
+ title={t('map.uwLong')}
+ variant="outline-secondary"
+ >
+ {t('map.uwShort')}
+ </Button>
+ </div>;
+};
+
+export default Buttons;
--- /dev/null
+import OpenSeadragon from 'openseadragon';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+export const Context = React.createContext({});
+
+export const useOpenSeadragon = () => React.useContext(Context);
+
+export const Provider = React.forwardRef(({ children }, ref) => {
+ const [viewer, setViewer] = React.useState(null);
+
+ React.useEffect(() => {
+ if (!ref.current) return;
+
+ const v = OpenSeadragon({
+ element: ref.current,
+ preserveViewport: true,
+ sequenceMode: true,
+ showNavigator: true,
+ showNavigationControl: false,
+ showSequenceControl: false,
+ tileSources: [
+ new OpenSeadragon.DziTileSource({
+ width: 8192,
+ height: 8192,
+ tileSize: 256,
+ tileOverlap: 0,
+ minLevel: 8,
+ maxLevel: 13,
+ tilesUrl: '/media/alttp/map/lw_files/',
+ fileFormat: 'png',
+ }), new OpenSeadragon.DziTileSource({
+ width: 8192,
+ height: 8192,
+ tileSize: 256,
+ tileOverlap: 0,
+ minLevel: 8,
+ maxLevel: 13,
+ tilesUrl: '/media/alttp/map/dw_files/',
+ fileFormat: 'png',
+ }), new OpenSeadragon.DziTileSource({
+ width: 8192,
+ height: 4096,
+ tileSize: 256,
+ tileOverlap: 0,
+ minLevel: 8,
+ maxLevel: 13,
+ tilesUrl: '/media/alttp/map/sp_files/',
+ fileFormat: 'png',
+ }), new OpenSeadragon.DziTileSource({
+ width: 16384,
+ height: 16384,
+ tileSize: 256,
+ tileOverlap: 0,
+ minLevel: 8,
+ maxLevel: 14,
+ tilesUrl: '/media/alttp/map/uw_files/',
+ fileFormat: 'png',
+ }),
+ ],
+ });
+ setViewer(v);
+ return () => {
+ v.destroy();
+ };
+ }, [ref.current]);
+
+ return <Context.Provider value={{ viewer }}>
+ {children}
+ </Context.Provider>;
+});
+
+Provider.displayName = 'OpenSeadragonProvider';
+
+Provider.propTypes = {
+ children: PropTypes.node,
+};
+
+export default Provider;
--- /dev/null
+import OpenSeadragon from 'openseadragon';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const Viewer = () => {
+ const [viewer, setViewer] = React.useState(null);
+
+ const container = React.useRef();
+ const { t } = useTranslation();
+
+ React.useEffect(() => {
+ if (!container.current) return;
+
+ const v = OpenSeadragon({
+ element: container.current,
+ preserveViewport: true,
+ sequenceMode: true,
+ showNavigator: true,
+ showNavigationControl: false,
+ showSequenceControl: false,
+ //tileSources: [
+ // new OpenSeadragon.DziTileSource({
+ // width: 8192,
+ // height: 8192,
+ // tileSize: 256,
+ // tileOverlap: 0,
+ // minLevel: 8,
+ // maxLevel: 13,
+ // tilesUrl: '/media/alttp/map/lw_files/',
+ // fileFormat: 'png',
+ // }), new OpenSeadragon.DziTileSource({
+ // width: 8192,
+ // height: 8192,
+ // tileSize: 256,
+ // tileOverlap: 0,
+ // minLevel: 8,
+ // maxLevel: 13,
+ // tilesUrl: '/media/alttp/map/dw_files/',
+ // fileFormat: 'png',
+ // }), new OpenSeadragon.DziTileSource({
+ // width: 8192,
+ // height: 8192,
+ // tileSize: 256,
+ // tileOverlap: 0,
+ // minLevel: 8,
+ // maxLevel: 13,
+ // tilesUrl: '/media/alttp/map/sp_files/',
+ // fileFormat: 'png',
+ // }), new OpenSeadragon.DziTileSource({
+ // width: 16384,
+ // height: 16384,
+ // tileSize: 256,
+ // tileOverlap: 0,
+ // minLevel: 8,
+ // maxLevel: 14,
+ // tilesUrl: '/media/alttp/map/uw_files/',
+ // fileFormat: 'png',
+ // }),
+ //],
+ });
+ setViewer(v);
+ return () => {
+ v.destroy();
+ };
+ }, [container.current]);
+
+ const goToPage = React.useCallback((p) => {
+ if (viewer) viewer.goToPage(p);
+ }, [viewer]);
+
+ return <>
+ <div className="d-flex align-items-center justify-content-between">
+ <div className="button-bar">
+ <Button
+ onClick={() => goToPage(0)}
+ title={t('map.lwLong')}
+ variant="outline-secondary"
+ >
+ {t('map.lwShort')}
+ </Button>
+ <Button
+ onClick={() => goToPage(1)}
+ title={t('map.dwLong')}
+ variant="outline-secondary"
+ >
+ {t('map.dwShort')}
+ </Button>
+ <Button
+ onClick={() => goToPage(2)}
+ title={t('map.spLong')}
+ variant="outline-secondary"
+ >
+ {t('map.spShort')}
+ </Button>
+ <Button
+ onClick={() => goToPage(3)}
+ title={t('map.uwLong')}
+ variant="outline-secondary"
+ >
+ {t('map.uwShort')}
+ </Button>
+ </div>
+ </div>
+ <div ref={container} style={{ height: '80vh' }} />
+ </>;
+};
+
+export default Viewer;
--- /dev/null
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Buttons from '../map/Buttons';
+import OpenSeadragon from '../map/OpenSeadragon';
+
+const Map = () => {
+ const container = React.useRef();
+ const { t } = useTranslation();
+
+ return <Container fluid>
+ <OpenSeadragon ref={container}>
+ <div className="d-flex align-items-center justify-content-between">
+ <h1>{t('map.heading')}</h1>
+ <Buttons />
+ </div>
+ <div ref={container} style={{ height: '80vh' }} />
+ </OpenSeadragon>
+ </Container>;
+};
+
+export default Map;
somaria: 'Cane of Somaria',
},
},
+ map: {
+ dwLong: 'Dark World',
+ dwShort: 'DW',
+ heading: 'Karte',
+ lwLong: 'Light World',
+ lwShort: 'LW',
+ spLong: 'Spezielle Gebiete',
+ spShort: 'SP',
+ uwLong: 'Underworld',
+ uwShort: 'UW',
+ },
modes: {
heading: 'Modi',
},
somaria: 'Cane of Somaria',
},
},
+ map: {
+ dwLong: 'Dark World',
+ dwShort: 'DW',
+ heading: 'Map',
+ lwLong: 'Light World',
+ lwShort: 'LW',
+ spLong: 'Special Areas',
+ spShort: 'SP',
+ uwLong: 'Underworld',
+ uwShort: 'UW',
+ },
modes: {
heading: 'Modes',
},
'nanoclone',
'object-assign',
'object-inspect',
+ 'openseadragon',
'performance-now',
'process',
'prop-types',