Skip to content

Implement Idle Detection for Kiosk Mode

In kiosk deployments the map should return to a home state after a period of user inactivity — returning the camera to its default position, clearing any active selection or route, and optionally showing an attract-loop animation. The API provides built-in idle tracking via setIdleTime and the idleChange event so you can implement this without managing your own setTimeout chains.

Scope note — hard-reset vs soft-reset: A "hard reset" (full page reload triggered by the native kiosk runtime) is a kiosk-native feature that is not exposed through the JS API. It must be implemented at the native container level (e.g. Electron, Capacitor, or CEF). What the JS API does expose is a soft-reset path: listen for idleChange and drive your own state cleanup from the event handler.

Prerequisites

  • The library initialized and in the READY state (API lifecycle)
  • A defined "home" state — either a saved viewport, a selected building, or the property default

Setting the idle timeout

Call setIdleTime at any point after init resolves. Pass a duration in milliseconds as a positive integer:

CDN:

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });

  // Reset to home after 60 seconds of inactivity
  await mapsted.maps.setIdleTime(60_000);
</script>

npm:

js
import * as maps from '@mapsted/maps-js-api';

await maps.init({ element: '#map', propertyId: 1234 });

// Reset to home after 60 seconds of inactivity
await maps.setIdleTime(60_000);

setIdleTime accepts a positive integer in milliseconds. Passing 0 or a negative value throws a MAPSTED-1084 error. To disable idle detection, omit the call entirely or destroy and reinitialize the library without calling setIdleTime.

You can call setIdleTime again at any time to change the timeout dynamically — for example, to shorten it during off-peak hours.

Resetting the idle countdown without changing the duration

Use resetIdleTimer() when your app detects user activity outside the map iframe (e.g. a parent-level touchscreen wrapper, keyboard shortcut, or modal interaction) and you want to propagate that activity into the map's idle-detection loop without changing the configured idleTime duration:

js
// CDN
await mapsted.maps.resetIdleTimer();

// npm
await maps.resetIdleTimer();

resetIdleTimer() is idempotent — calling it when no idle timer has been configured (i.e. setIdleTime was never called) is a no-op on the iframe side. Throws MAPSTED-1090 if the API is not yet READY.

Listening for idle state changes

The idleChange event fires when the map transitions into or out of the idle state. The payload carries a single boolean field isUserActivefalse when the map has gone idle, true when the user has resumed interaction.

CDN:

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  await mapsted.maps.init({ element: '#map' });
  await mapsted.maps.setIdleTime(60_000);

  mapsted.maps.on('idleChange', ({ isUserActive }) => {
    if (!isUserActive) {
      console.log('Map entered idle state — soft-resetting to home view');
      softResetToHome();
    } else {
      console.log('User resumed interaction');
      hideAttractLoop();
    }
  });
</script>

npm:

js
import * as maps from '@mapsted/maps-js-api';

await maps.init({ element: '#map', propertyId: 1234 });
await maps.setIdleTime(60_000);

maps.on('idleChange', ({ isUserActive }) => {
  if (!isUserActive) {
    softResetToHome();
  } else {
    hideAttractLoop();
  }
});

Implementing a soft kiosk reset

The idleChange handler is responsible for your own state cleanup. Use clearRoute() to reset any active route, and setViewport to return the camera to the home position. There is no clearSelection() bulk-reset method for entity selection.

Current public-API scope: clearRoute() is available — call it on idle to clear the current route and reset the itinerary to your configured defaults. The API does not expose a clearSelection() method; to clear an entity selection re-call setEntityData with your defaults, or use setViewport to return the camera to the home position. A clearSelection() method is planned for a future release to simplify kiosk reset flows; contact info@mapsted.com if you need it on the roadmap.

CDN example — soft reset using setViewport:

html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=1234"></script>
<script>
  const HOME_VIEWPORT = { zoomLevel: 18, mapCenter: [-79.3832, 43.6532] };

  async function softResetToHome() {
    // Return the camera to the default property view
    await mapsted.maps.setViewport(HOME_VIEWPORT);

    // Show an attract-loop overlay managed by your own UI layer
    document.getElementById('attract-loop').classList.remove('hidden');
  }

  await mapsted.maps.init({ element: '#map' });
  await mapsted.maps.setIdleTime(60_000);

  mapsted.maps.on('idleChange', async ({ isUserActive }) => {
    if (!isUserActive) {
      await softResetToHome();
    } else {
      document.getElementById('attract-loop').classList.add('hidden');
    }
  });
</script>

npm equivalent:

js
import * as maps from '@mapsted/maps-js-api';

const HOME_VIEWPORT = { zoomLevel: 18, mapCenter: [-79.3832, 43.6532] };

async function softResetToHome() {
  await maps.setViewport(HOME_VIEWPORT);
  document.getElementById('attract-loop').classList.remove('hidden');
}

await maps.init({ element: '#map', propertyId: 1234 });
await maps.setIdleTime(60_000);

maps.on('idleChange', async ({ isUserActive }) => {
  if (!isUserActive) {
    await softResetToHome();
  } else {
    document.getElementById('attract-loop').classList.add('hidden');
  }
});

setViewport accepts { zoomLevel?: number; mapCenter?: [number, number] } where zoomLevel must be in the range 10–24 and mapCenter is [longitude, latitude] in WGS84 (EPSG:4326).

Extending the timeout in response to external events

If your kiosk has a touchscreen wrapper that captures events outside the map container, re-call setIdleTime with the same value to restart the internal countdown:

js
import * as maps from '@mapsted/maps-js-api';

const IDLE_MS = 60_000;

await maps.init({ element: '#map', propertyId: 1234 });
await maps.setIdleTime(IDLE_MS);

// Signal activity from outside the map container by re-setting the timeout
document.addEventListener('touchstart', async () => {
  await maps.setIdleTime(IDLE_MS);
}, { passive: true });

Note: This restarts the countdown but incurs an async round-trip on every touchstart. For high-frequency input consider debouncing before calling setIdleTime.

When a kiosk URL carries boost parameters (e.g. from a QR code scan), give users extra time to complete an interaction before the idle reset fires:

js
import * as maps from '@mapsted/maps-js-api';

const NORMAL_IDLE_MS  = 60_000;  // 60 s during normal operation
const BOOSTED_IDLE_MS = 120_000; // 120 s when arriving via deep link

await maps.init({ element: '#map', propertyId: 1234 });

// Inspect the URL yourself to detect a boost parameter
const hasBoost = new URLSearchParams(location.search).has('boost');
await maps.setIdleTime(hasBoost ? BOOSTED_IDLE_MS : NORMAL_IDLE_MS);

The API also emits a boostComplete event once a boost has finished applying, so you can extend the idle timeout in response to the boost landing rather than only inspecting the URL:

js
maps.on('boostComplete', () => {
  // The deep-link boost has finished applying — give the visitor extra time.
  maps.setIdleTime(BOOSTED_IDLE_MS);
});

Current public-API scope: The API does not expose a getBoostState() accessor for polling the current boost state; use the boostComplete event (or read the boost parameters from the URL) instead. See also Boost and deep-linking.