> For the complete documentation index, see [llms.txt](https://docs.mapsindoors.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mapsindoors.com/academy/use-case-guides/parking-spot-mark-and-navigate-back.md).

# Parking Spot: Mark & Navigate Back

## Introduction

A common “last 200 meters” problem in large campuses, hospitals, airports, shopping centers, and multi-level parking garages is simply remembering where you parked and later finding your way back to that same location

This use case guide shows one recommended approach for implementing a “Mark my parking spot” feature in a MapsIndoors-powered application:

1. The user marks a parking spot on the map (using their live position or a dropped pin)
2. The app saves that spot (typically per-user)
3. Later, the user can request directions back to that exact spot using the same wayfinding experience already in your MapsIndoors app

## ParkingManager

A reusable ES Module for parking spot management that integrates with MapsIndoors SDK.

### Table of Contents

* Overview
* Summary
* Installation
* Quick Start
* API Reference
* Storage Adapters
* MapsIndoors Integration
* Examples

***

### Overview

ParkingManager provides a simple API to save, load, and manage parking spot locations. It's designed to work seamlessly with MapsIndoors SDK location objects and supports configurable storage backends.

#### MapsIndoors Features

* [Way finding](/sdks-and-frameworks/web/directions-and-routing.md)

#### Additional Features

* Save MapsIndoors locations as parking spots
* Persistent storage via localStorage or cookies
* Custom storage adapter support

#### Saved Data Structure

When a parking spot is saved, ParkingManager stores the following data:

```ts
{
  id: string,           // MapsIndoors location ID
  name: string,         // Location name
  description: string,  // Location description
  coordinates: {
    lat: number,        // Latitude
    lng: number         // Longitude
  },
  floorIndex: number,   // Floor level
  savedAt: number       // Unix timestamp (milliseconds)
}
```

***

### Summary

A “Mark & Navigate Back” parking workflow is a compact but high-impact MapsIndoors use case:

* Save a point (usually per user)
* Render it clearly
* Route back using MapsIndoors wayfinding components

Because the pattern is generic (save a coordinate + optional floor + navigate later), you can reuse the same architecture for many other use cases like “Find my desk”, “Return to entrance”, “Meet me here”, or “Remember this place”.

***

### Browser Support

ParkingManager requires ES6+ support and works in all modern browsers:

* Chrome 61+
* Firefox 60+
* Safari 11+
* Edge 16+

For localStorage adapter, ensure localStorage is available. For cookie adapter, ensure cookies are enabled.

***

### Installation

Include the module in your HTML file with ES module support:

```html
<script type="module" src="script.js"></script>
```

Import in your JavaScript:

```javascript
import { ParkingManager, LocalStorageAdapter, CookieStorageAdapter } from './parking.js';
```

***

### Quick Start

```javascript
import { ParkingManager } from './parking.js';

// Create a ParkingManager instance (uses localStorage by default)
const parking = new ParkingManager();

// Save a MapsIndoors location as parking
parking.saveParkingSpot(mapsIndoorsLocation);

// Check if parking exists
if (parking.hasSavedParking()) {
  // Load the saved parking data
  const savedParking = parking.loadParkingSpot();
  console.log('Parked at:', savedParking.name);
}

// Clear saved parking
parking.clearParkingSpot();
```

***

### API Reference

#### ParkingManager

**Constructor**

```javascript
new ParkingManager(options?)
```

| Option           | Type   | Default               | Description            |
| ---------------- | ------ | --------------------- | ---------------------- |
| `storageAdapter` | Object | `LocalStorageAdapter` | Storage backend to use |
| `storageKey`     | string | `'savedParkingSpot'`  | Key used for storage   |

**Methods**

**`saveParkingSpot(mapsIndoorsLocation)`**

Saves a MapsIndoors location as the parking spot.

```javascript
parking.saveParkingSpot(location);
```

| Parameter             | Type   | Description                 |
| --------------------- | ------ | --------------------------- |
| `mapsIndoorsLocation` | Object | MapsIndoors location object |

**Returns:** `boolean` - `true` if save was successful

**`loadParkingSpot()`**

Loads the saved parking spot data.

```javascript
const savedParking = parking.loadParkingSpot();
```

**Returns:** `Object | null` - Saved parking data or `null` if none exists

**`clearParkingSpot()`**

Clears the saved parking spot.

```javascript
parking.clearParkingSpot();
```

**Returns:** `boolean` - `true` if clear was successful

**`hasSavedParking()`**

Checks if a parking spot is saved.

```javascript
if (parking.hasSavedParking()) {
  // Parking spot exists
}
```

**Returns:** `boolean` - `true` if a parking spot exists

***

### Storage Adapters

#### LocalStorageAdapter (Default)

Uses browser localStorage for persistent storage.

```javascript
import { ParkingManager, LocalStorageAdapter } from './parking.js';

const parking = new ParkingManager({
  storageAdapter: new LocalStorageAdapter({
    prefix: 'myApp_'  // Optional key prefix
  })
});
```

| Option   | Type   | Default | Description             |
| -------- | ------ | ------- | ----------------------- |
| `prefix` | string | `''`    | Prefix for storage keys |

#### CookieStorageAdapter

Uses browser cookies with configurable expiration.

```javascript
import { ParkingManager, CookieStorageAdapter } from './parking.js';

const parking = new ParkingManager({
  storageAdapter: new CookieStorageAdapter({
    expireDays: 7,      // Cookie expiration in days
    path: '/',          // Cookie path
    secure: false,      // Secure flag (HTTPS only)
    sameSite: 'Lax'     // SameSite policy
  })
});
```

| Option       | Type    | Default | Description               |
| ------------ | ------- | ------- | ------------------------- |
| `expireDays` | number  | `7`     | Days until cookie expires |
| `path`       | string  | `'/'`   | Cookie path               |
| `secure`     | boolean | `false` | Require HTTPS             |
| `sameSite`   | string  | `'Lax'` | SameSite attribute        |

#### Custom Storage Adapter

Create your own adapter by implementing the storage interface:

```javascript
class MyCustomAdapter {
  get(key) {
    // Return parsed data or null
  }

  set(key, value) {
    // Store data, return true on success
  }

  remove(key) {
    // Remove data, return true on success
  }
}

const parking = new ParkingManager({
  storageAdapter: new MyCustomAdapter()
});
```

**Example: SessionStorage Adapter**

```javascript
class SessionStorageAdapter {
  get(key) {
    try {
      const value = sessionStorage.getItem(key);
      return value ? JSON.parse(value) : null;
    } catch (e) {
      return null;
    }
  }

  set(key, value) {
    try {
      sessionStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (e) {
      return false;
    }
  }

  remove(key) {
    try {
      sessionStorage.removeItem(key);
      return true;
    } catch (e) {
      return false;
    }
  }
}
```

***

### MapsIndoors Integration

#### Complete Setup Example

```javascript
import { ParkingManager, CookieStorageAdapter } from './parking.js';

// Initialize ParkingManager
const parkingManager = new ParkingManager({
  storageAdapter: new CookieStorageAdapter({ expireDays: 7 }),
  storageKey: 'venue_parking_spot'
});

// Initialize MapsIndoors
const mapViewOptions = {
  accessToken: 'YOUR_MAPBOX_TOKEN',
  element: document.getElementById('map'),
  center: { lat: 0, lng: 0 },
  zoom: 17
};

const mapView = new mapsindoors.mapView.MapboxV3View(mapViewOptions);
const mapsIndoors = new mapsindoors.MapsIndoors({
  mapView: mapView,
  venue: 'YOUR_VENUE_ID'
});

// Load saved parking on startup
let savedParkingSpot = parkingManager.loadParkingSpot();

// Center map on saved parking when ready
mapsIndoors.addListener('ready', () => {
  if (savedParkingSpot) {
    const map = mapView.getMap();
    map.setCenter({
      lat: savedParkingSpot.coordinates.lat,
      lng: savedParkingSpot.coordinates.lng
    });
    mapsIndoors.setFloor(savedParkingSpot.floorIndex);
  }
});
```

#### Saving Parking from Location Click

```javascript
// Handle location clicks
mapsIndoors.on('click', (location) => {
  if (location && isParkingLocation(location)) {
    showSaveParkingButton(location);
  }
});

// Check if location is a parking spot
function isParkingLocation(location) {
  const type = (location.properties.type || '').toLowerCase();
  const name = (location.properties.name || '').toLowerCase();
  return type.includes('parking') || name.includes('parking');
}

// Save parking button handler
function saveParkingHandler(location) {
  const success = parkingManager.saveParkingSpot(location);

  if (success) {
    savedParkingSpot = parkingManager.loadParkingSpot();
    showSuccessMessage('Parking spot saved!');
    updateParkingUI();
  } else {
    showErrorMessage('Failed to save parking spot');
  }
}
```

#### Navigating to Saved Parking

```javascript
function navigateToParking() {
  const parking = parkingManager.loadParkingSpot();

  if (!parking) {
    showErrorMessage('No parking spot saved');
    return;
  }

  // Center map on parking location
  const map = mapView.getMap();
  map.setCenter({
    lat: parking.coordinates.lat,
    lng: parking.coordinates.lng
  });
  mapsIndoors.setFloor(parking.floorIndex);

  // Create destination for directions
  const destination = {
    lat: parking.coordinates.lat,
    lng: parking.coordinates.lng,
    floor: parking.floorIndex
  };

  // Calculate route from current position
  calculateDirections(currentPosition, destination);
}
```

#### Getting Directions to Parking

```javascript
async function getDirectionsToParking(origin) {
  const parking = parkingManager.loadParkingSpot();

  if (!parking) {
    console.error('No parking spot saved');
    return;
  }

  // Setup directions service
  const externalProvider = new mapsindoors.directions.MapboxProvider('YOUR_MAPBOX_TOKEN');
  const directionsService = new mapsindoors.services.DirectionsService(externalProvider);
  const directionsRenderer = new mapsindoors.directions.DirectionsRenderer({
    mapsIndoors: mapsIndoors
  });

  // Calculate route
  const route = await directionsService.getRoute({
    origin: {
      lat: origin.lat,
      lng: origin.lng,
      floor: origin.floor
    },
    destination: {
      lat: parking.coordinates.lat,
      lng: parking.coordinates.lng,
      floor: parking.floorIndex
    },
    travelMode: 'WALKING'
  });

  // Display route on map
  directionsRenderer.setRoute(route);
}
```

***

### Examples

<details>

<summary>Example 1: Basic Usage with LocalStorage</summary>

```javascript
import { ParkingManager } from './parking.js';

const parking = new ParkingManager();

// Save when user clicks a parking location
document.getElementById('save-btn').addEventListener('click', () => {
  if (currentLocation) {
    parking.saveParkingSpot(currentLocation);
    alert('Parking saved!');
  }
});

// Load on page load
window.addEventListener('load', () => {
  if (parking.hasSavedParking()) {
    const saved = parking.loadParkingSpot();
    document.getElementById('parking-name').textContent = saved.name;
  }
});
```

</details>

<details>

<summary>Example 2: Cookie Storage with Custom Key</summary>

```javascript
import { ParkingManager, CookieStorageAdapter } from './parking.js';

const parking = new ParkingManager({
  storageAdapter: new CookieStorageAdapter({
    expireDays: 30,
    secure: true,
    sameSite: 'Strict'
  }),
  storageKey: 'stadium_parking_v1'
});
```

</details>

<details>

<summary>Example 3: Display Saved Parking Info</summary>

```javascript
function updateParkingDisplay() {
  const parking = parkingManager.loadParkingSpot();
  const container = document.getElementById('parking-info');

  if (parking) {
    // Format time since saved
    const savedDate = new Date(parking.savedAt);
    const minutesAgo = Math.floor((Date.now() - parking.savedAt) / 60000);

    let timeText;
    if (minutesAgo < 1) {
      timeText = 'Just now';
    } else if (minutesAgo < 60) {
      timeText = `${minutesAgo} minute${minutesAgo > 1 ? 's' : ''} ago`;
    } else {
      const hoursAgo = Math.floor(minutesAgo / 60);
      timeText = `${hoursAgo} hour${hoursAgo > 1 ? 's' : ''} ago`;
    }

    container.innerHTML = `
      <h3>${parking.name}</h3>
      <p>Floor: ${parking.floorIndex}</p>
      <p>Saved: ${timeText}</p>
      <button onclick="navigateToParking()">Navigate</button>
      <button onclick="clearParking()">Clear</button>
    `;
  } else {
    container.innerHTML = '<p>No parking spot saved</p>';
  }
}
```

</details>

<details>

<summary>Example 4: Search and Save Parking</summary>

```javascript
async function searchAndSaveParking(query) {
  // Search for parking locations
  const locations = await mapsindoors.services.LocationsService.getLocations({
    q: query,
    types: ['parking'],
    take: 10
  });

  if (locations.length > 0) {
    // Save the first result
    const parkingLocation = locations[0];
    parkingManager.saveParkingSpot(parkingLocation);

    console.log('Saved parking:', parkingLocation.properties.name);
    return true;
  }

  return false;
}

// Usage
searchAndSaveParking('North Parking Lot');
```

</details>
