All files / lib/components/Game/Screen/GPSMap/AddMarker index.ts

0% Statements 0/30
0% Branches 0/8
0% Functions 0/10
0% Lines 0/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                                                                                                                                                                                                                                                       
import LocationButton from '../LocationButton';
import LocationMarker from '../LocationMarker';
import { ButtonStyle, MarkerStyle } from './type';
 
type WatchPositionFnType = (
  successCallback: PositionCallback,
  errorCallback?: PositionErrorCallback | null,
  options?: PositionOptions
) => number | Promise<number | string>;
 
export type Options = {
  buttonStyle?: ButtonStyle;
  markerStyle?: MarkerStyle;
  showAccuracyRadius?: boolean;
  watchPositionFn?: WatchPositionFnType;
};
 
/**
 * Adds a button to the toolbar for user to click and see their current position
 * on the map with a marker.
 */
class CurrentLocation {
  controlUI: LocationButton;
 
  locationMarker: LocationMarker;
 
  map: google.maps.Map;
 
  positionCount: number;
 
  positionOptions: PositionOptions;
 
  watchId?: number | string;
 
  watchPositionFn: WatchPositionFnType;
 
  constructor(map: google.maps.Map, options: Options = {}) {
    this.map = map;
 
    this.positionOptions = {
      enableHighAccuracy: true
    };
 
    this.locationMarker = new LocationMarker(map, options);
    this.controlUI = new LocationButton(map, options);
 
    this.positionCount = 0;
    this.watchId = 0;
 
    const defaultWatchPositionFn = (
      successCallback: PositionCallback,
      errorCallback?: PositionErrorCallback | null,
      options?: PositionOptions
    ): number => {
      return navigator.geolocation.watchPosition(successCallback, errorCallback, options);
    };
 
    this.watchPositionFn = options.watchPositionFn || defaultWatchPositionFn;
 
    this.controlUI.setOnClickListener(() => {
      if (!this.watchId) {
        this.controlUI.setEnabled(false);
        this.controlUI.animate(true);
 
        this.startWatchPosition();
      } else {
        this.locationMarker.center();
      }
    });
  }
 
  /**
   * Starts watching for the user position.
   * This will be called automatically each time the position changes.
   * */
  startWatchPosition(): void {
    const id = this.watchPositionFn(
      (pos) => {
        this.updatePosition(pos);
      },
      (err: GeolocationPositionError) => {
        this.setError(err);
      },
      this.positionOptions
    );
 
    if (id instanceof Promise) {
      // eslint-disable-next-line no-return-assign
      id.then((id) => (this.watchId = id));
    } else {
      this.watchId = id;
    }
  }
 
  /**
   * Everytime the position changes, the location of the marker also changes
   * as well as some ControlUI settings
   * */
  updatePosition(pos: GeolocationPosition): void {
    // eslint-disable-next-line no-plusplus
    this.locationMarker.update(pos);
    this.controlUI.setEnabled(true);
    this.controlUI.animate(false);
  }
 
  /**
   * When an error occurs during the watchPosition (e.g. PERMISSION_DENIED) an alert is showed,
   * the watchId is set to undefined (to allow a re-watching) and the ControlUI settings are set to default
   * */
  setError(err: GeolocationPositionError): void {
    this.watchId = undefined;
    this.controlUI.setEnabled(true);
    this.controlUI.animate(false);
    alert(err.message);
  }
}
 
export default function addMapCurrentMarker(
  map: google.maps.Map,
  options: Options = {}
): CurrentLocation {
  return new CurrentLocation(map, options);
}