import { EmitterSubscription, NativeEventEmitter, NativeModules } from 'react-native'; import { MPCameraViewFitMode, MPError, MPRoute, OnLegSelectedListener } from "../../index"; import { EventNames } from './EventNames'; import { RouteStopIconConfig } from './RouteStopIconConfig'; const { DirectionsRenderer } = NativeModules; /** * Renders a {@link MPRoute} on the map. * * @export * @class MPDirectionsRenderer * @typedef {MPDirectionsRenderer} */ export default class MPDirectionsRenderer { private _defaultRouteStopIcon?: RouteStopIconConfig get defaultRouteStopIcon(): RouteStopIconConfig { return this._defaultRouteStopIcon; } /** * Listener for leg selection events. * * @private * @type {?EmitterSubscription} */ private onLegSelectedSub?: EmitterSubscription; /** * Event handler. * * @private * @type {?NativeEventEmitter} */ private eventEmitter?: NativeEventEmitter; /** * Creates an instance of MPDirectionsRenderer. * * @constructor * @public * @param {typeof NativeEventEmitter} nativeEventEmitter */ public constructor(nativeEventEmitter: typeof NativeEventEmitter) { this.eventEmitter = new nativeEventEmitter(DirectionsRenderer); } /** * Clears the route from the map. * * @public * @async * @returns {Promise} */ public async clear(): Promise { await DirectionsRenderer.clear(); } /** * Selects the next leg if possible. * * Has no effect if the last leg is selected. * * @public * @async * @returns {Promise} */ public async nextLeg(): Promise { await DirectionsRenderer.nextLeg(); } /** * Selects the previous leg if possible. * * Has no effect if the first leg is selected. * * @public * @async * @returns {Promise} */ public async previousLeg(): Promise { await DirectionsRenderer.previousLeg(); } /** * Set a route to be rendered. This also resets the selected leg and step indices to 0. * * @public * @async * @param {?MPRoute} [route] * @param {RouteStopIconConfig[]} [stopIcons] * @param {?number} [legIndex] Overwrites the starting leg index, when rendering the route * @returns {Promise} */ public async setRoute(route: MPRoute, stopIcons: Map = null, legIndex: number = 0): Promise { var iconsAsString = new Map(); if (stopIcons !== null) { stopIcons.forEach((icon, index) => { iconsAsString.set(index, icon.getImage().toString()); }); } await DirectionsRenderer.setRoute(JSON.stringify(route), JSON.stringify(Object.fromEntries(iconsAsString.entries())), legIndex); } /** * Set the default icon for route stops. * * @public * @async * @param {RouteStopIconConfig} icon * @returns {Promise} */ public async setDefaultRouteStopIcon(icon: RouteStopIconConfig): Promise { this._defaultRouteStopIcon = icon; await DirectionsRenderer.setDefaultRouteStopIcon(icon.getImage().toString()); } /** * Enable/Disable the polyline animation when displaying a route element on the map. * * @public * @async * @param {boolean} animated * @param {boolean} repeating * @param {number} durationMs * @returns {Promise} */ public async setAnimatedPolyline(animated: boolean, repeating: boolean, durationMs: number): Promise { await DirectionsRenderer.setAnimatedPolyline(animated, repeating, durationMs); } /** * Enable/Disable the route end/start label buttons from showing on the route. Default is true * * @public * @async * @param {boolean} show * @returns {Promise} */ public async showRouteLegButtons(show: boolean): Promise { await DirectionsRenderer.showRouteLegButtons(show); } /** * Manually set the selected leg index on the route. * * This may reject if the resulting internal state is invalid (parsed index is out of bounds). * * @public * @async * @param {number} legIndex * @returns {Promise} */ public async selectLegIndex(legIndex: number): Promise { await DirectionsRenderer.selectLegIndex(legIndex).catch((err: Error) => { return Promise.reject(MPError.create(JSON.parse(err.message))); }); } /** * Gets the currently selected leg's floor index. * * @public * @async * @returns {Promise} */ public async getSelectedLegFloorIndex(): Promise { return DirectionsRenderer.getSelectedLegFloorIndex(); } /** * Set the duration of camera animations in ms. * * If the duration < 0 then camera animations are disabled, and the camera will move instantly. * * The value is 1000 ms by default * * @public * @async * @param {number} durationMs * @returns {Promise} */ public async setCameraAnimationDuration(durationMs: number): Promise { await DirectionsRenderer.setCameraAnimationDuration(durationMs); } /** * Set the fitmode of the camera, when displaying route elements on the map. * * @public * @async * @param {MPCameraViewFitMode} fitMode * @returns {Promise} */ public async setCameraViewFitMode(fitMode: MPCameraViewFitMode): Promise { let cameraFitMode: number; switch (fitMode) { case MPCameraViewFitMode.northAligned: { cameraFitMode = 0; break; } case MPCameraViewFitMode.firstStepAligned: { cameraFitMode = 1; break; } case MPCameraViewFitMode.startToEndAligned: { cameraFitMode = 2; break; } case MPCameraViewFitMode.none: { cameraFitMode = 3; break; } } return await DirectionsRenderer.setCameraViewFitMode(cameraFitMode); } /** * Set a listener, which will be invoked when a new leg has been selected. * * This is used for when the forward/back markers are selected on the map. * * @public * @async * @param {?OnLegSelectedListener} [listener] * @returns {Promise} */ public async setOnLegSelectedListener(listener?: OnLegSelectedListener): Promise { await DirectionsRenderer.setOnLegSelectedListener(); this.onLegSelectedSub?.remove(); if (listener !== undefined) { this.onLegSelectedSub = this.eventEmitter?.addListener(EventNames.onLegSelected, event => { const leg = event.leg; listener(leg); }); } } }