SWMAPS DocumentationAPI portal

Offline and mobile

Offline search and nearby places

Use the pack’s small point-name dataset for local lookups and distance descriptions.

On this page

Load place names #

Prerequisites: a complete pack whose manifest lists places.json. The file is a GeoJSON FeatureCollection of named points from the same Nominatim build used for search. It is not a routable network or a full address index.

javascript
const entry = manifest.files.find(f => f.path === 'places.json');
if (!entry) throw new Error('This older pack has no offline place names');
const response = await fetch(localPackBase + '/places.json');
if (!response.ok) throw new Error('Local places file missing');
const places = (await response.json()).features;
const normalize = text => text.normalize('NFKD').replace(/\p{M}/gu, '').toLocaleLowerCase();
function findPlaces(query, limit = 20) {
  const term = normalize(query.trim());
  if (!term) return [];
  return places.filter(f => [f.properties.name, ...(f.properties.alt ?? [])]
    .some(name => normalize(name).includes(term)))
    .sort((a, b) => a.properties.rank - b.properties.rank ||
      (b.properties.importance ?? 0) - (a.properties.importance ?? 0))
    .slice(0, limit);
}
console.log(findPlaces('Iloilo'));

Expected result: local matching names and coordinates, without calling /search. Properties include name, kind, optional type, rank, optional importance, optional alt names (up to four), and osm identity. The manifest’s places metadata gives file, count and counts by kind.

Describe a position by distance and bearing #

javascript
function relativeTo(at, feature) {
  const radians = value => value * Math.PI / 180;
  const [lon1, lat1] = feature.geometry.coordinates.map(radians);
  const [lon2, lat2] = at.map(radians);
  const dLon = lon2 - lon1, dLat = lat2 - lat1;
  const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
  const nm = 2 * 6371008.8 * Math.asin(Math.min(1, Math.sqrt(a))) / 1852;
  const bearing = (Math.atan2(Math.sin(dLon) * Math.cos(lat2),
    Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon)) * 180 / Math.PI + 360) % 360;
  const compass = ['N','NE','E','SE','S','SW','W','NW'][Math.round(bearing / 45) % 8];
  return { feature, nm, bearing, label: nm.toFixed(1) + ' NM ' + compass + ' of ' + feature.properties.name };
}
const nearest = places.map(f => relativeTo([120.7, 13.8], f)).sort((a,b) => a.nm - b.nm)[0];
console.log(nearest?.label ?? 'No named place in this pack');

This recipe calculates the bearing from the named place to the sighting, so “NE of Cape…” describes the sighting. It is a straight-line geographic estimate, not a navigable distance. For large datasets use a local spatial index; let users choose a useful landmark instead of always taking the nearest minor feature.

Kinds, boundaries and missing data #

  • Kinds include city, town, district, barangay, island/islet, cape, bay, strait, sea, reef, harbour and landmark. Handle new kinds generically.
  • The national overview contains larger cities/towns and geographic features; detailed packs contain all supported kinds.
  • Points belong to a half-open box: west/south included, east/north excluded. Adjacent cells do not duplicate their shared edge points.
  • Some offshore cells have an empty features array. Only Philippine-attributed places are listed; lack of a local result does not mean a feature is absent in the world.
  • Older downloaded packs may not list places.json. Disable offline place lookup or offer a fresh download instead of silently attempting the online service.
Online address search/reverse geocoding, routes and isochrones remain service features. Local place matching and local DEM sampling are application recipes built from pack data.