Explorar el Código

Implement auto-zoom in country-locked games

Kirk Trombley hace 4 años
padre
commit
984add576e

+ 4 - 1
client/src/components/screens/GamePanel/GuessPane/ClickMarkerMap.jsx

@@ -1,13 +1,16 @@
 import { useRef } from 'react';
 import useClickMarker from '../../../../hooks/useClickMarker';
+import { useGameConfig } from '../../../../hooks/useGameInfo';
 import useMap from '../../../../hooks/useMap';
+import useMapBounds from '../../../../hooks/useMapBounds';
 import styles from './GuessPane.module.css';
 
 const ClickMarkerMap = ({ onMarkerMoved }) => {
   const mapDivRef = useRef(null);
   const mapRef = useMap(mapDivRef);
   useClickMarker(mapRef, onMarkerMoved);
-  // TODO allow setting of map bounds for country locked games
+  const { countryLock } = useGameConfig();
+  useMapBounds(mapRef, countryLock);
   return <div className={styles.map} ref={mapDivRef} />;
 };
 

+ 19 - 2
client/src/domain/geocoding.js

@@ -1,3 +1,4 @@
+import iso from 'iso-3166-1';
 /* global google */
 
 const GEOCODER = new google.maps.Geocoder();
@@ -7,7 +8,7 @@ export const reverseGeocode = async location => {
     const { results } = await GEOCODER.geocode({ location });
     for (const { address_components } of results) {
       for (const { short_name, types } of address_components) {
-        if (types.indexOf("country") >= 0) {
+        if (types.indexOf('country') >= 0) {
           return short_name;
         }
       }
@@ -17,4 +18,20 @@ export const reverseGeocode = async location => {
     // TODO probably alert the user?
   }
   return null;
-};
+};
+
+export const getCountryBounds = async countryCode => {
+  const { country } = iso.whereAlpha2(countryCode);
+  try {
+    const { results } = await GEOCODER.geocode({ address: country });
+    for (const { geometry, types } of results) {
+      if (geometry.viewport && types.indexOf('country') >= 0) {
+        return geometry.viewport;
+      }
+    }
+  } catch (e) {
+    // ignore errors - just use null
+    // TODO is there really no recovery from this?
+  }
+  return null;
+}

+ 25 - 0
client/src/hooks/useMapBounds.jsx

@@ -0,0 +1,25 @@
+import { useEffect, useRef } from "react";
+import { getCountryBounds } from "../domain/geocoding";
+
+const useMapBounds = (mapRef, country) => {
+  const done = useRef(false);
+
+  useEffect(() => {
+    if (done.current || country === null || country === undefined) {
+      return;
+    }
+
+    const moveMap = async () => {
+      const bounds = await getCountryBounds(country);
+      if (bounds) {
+        mapRef.current.fitBounds(bounds);
+        mapRef.current.panToBounds(bounds);
+        mapRef.current.setZoom(2);
+        done.current = true;
+      }
+    }
+    moveMap();
+  }, [country, mapRef]);
+};
+
+export default useMapBounds;