Landmarks
A landmark is a predefined, permanent location that holds detailed information such as its name, address, description, geographic area, categories (e.g., Gas Station, Shopping), entrance locations, contact details, and sometimes associated multimedia (e.g., icons or images). It represents significant, categorized locations with rich metadata, providing structured context about a place.
Landmark Structure
Geographic Details
A landmark's position is defined by its coordinates, which represent the centroid, and its geographicArea, representing the full boundary (e.g., circle, rectangle, or polygon). Since landmarks can correspond to buildings, roads, settlements, or regions, the geographic area can be complex. For specific bounding areas, the getContourGeographicArea method is used.
To calculate the distance between two landmarks in meters, use the distance method from the Coordinates class, which computes the Haversine distance between the coordinates of the two landmarks:
import { Coordinates } from '@magiclane/maps-sdk';
const distanceInMeters: number = landmark1.coordinates.distance(landmark2.coordinates);
Check the Coordinates guide for more details about the distance method.
Waypoint Track Data
Some landmarks include a trackData attribute, which represents a sequence of geographic points (waypoints) that outline a path. The following operations are available for managing waypoint track data:
hasTrackData- returnstrueif the landmark contains track datatrackData(getter) - returns the track as aPathobject; returns an emptyPathwhen no track is presenttrackData(setter) - replace the landmark's track with a providedPathreverseTrackData()- reverses the sequence of points in the waypoint track
import { Landmark, Path } from '@magiclane/maps-sdk';
// Check if landmark has track data
if (landmark.hasTrackData) {
// Get the track
const track: Path = landmark.trackData;
// Reverse the track direction
landmark.reverseTrackData();
// Set new track data
const newTrack = new Path(/* waypoints */);
landmark.trackData = newTrack;
}
The waypoint track data is used for path-based routes. See the Compute path based route guide for more details.
Descriptive Information
Landmarks include attributes like name, description, and author. The name adapts to the SDK's language settings, ensuring localization where applicable.
const landmarkName: string = landmark.name;
const landmarkDescription: string | undefined = landmark.description;
const landmarkAuthor: string | undefined = landmark.author;
Metadata
Landmarks can belong to one or more categories, described by LandmarkCategory. Additional details like contactInfo (e.g., phone, email) and extraInfo (a structured hashmap) add flexibility for storing metadata.
import { LandmarkCategory, ContactInfo, ExtraInfo } from '@magiclane/maps-sdk';
// Get categories
const categories: LandmarkCategory[] = landmark.categories;
// Get contact information
const contactInfo: ContactInfo | undefined = landmark.contactInfo;
// Get extra metadata
const extraInfo: ExtraInfo | undefined = landmark.extraInfo;
Media and Imagery
Images associated with landmarks can be retrieved using getters like img (primary image) or extraImg (secondary images). Please note that these images might contain invalid data and it is the user's responsibility to check the validity of the objects using the provided methods.
import { Img, ImageFileFormat } from '@magiclane/maps-sdk';
// Get primary image
const primaryImage: Img | undefined = landmark.img;
// Get image data for display
if (primaryImage) {
const imageData = landmark.getImage(
{ width: 100, height: 100 },
ImageFileFormat.png
);
if (imageData && imageData.byteLength > 0) {
// Display image
const blob = new Blob([new Uint8Array(imageData.buffer as ArrayBuffer)], { type: 'image/png' });
const imageUrl = URL.createObjectURL(blob);
imgElement.src = imageUrl;
}
}
Advanced Metadata
Attributes such as landmarkStoreId, landmarkStoreType provide information about assigned landmark store, the landmark store type. The timeStamp records information about the time the landmark was inserted into a store.
const storeId: number = landmark.landmarkStoreId;
const storeType: LandmarkStoreType = landmark.landmarkStoreType;
const insertTime: number = landmark.timeStamp; // Unix timestamp
Address
The address attribute connects landmarks to AddressInfo, providing details about the physical address of the location.
import { AddressInfo, AddressField } from '@magiclane/maps-sdk';
const address: AddressInfo | undefined = landmark.address;
if (address) {
const street = address.getField(AddressField.streetName);
const city = address.getField(AddressField.city);
const country = address.getField(AddressField.country);
}
Unique Identifier
The id ensures every landmark is uniquely identifiable.
const landmarkId: number = landmark.id;
If the ContactInfo or ExtraInfo object retrieved from a landmark is modified, you must use the corresponding setter to update the value associated with the landmark.
For example:
let info: ContactInfo = landmark.contactInfo;
info.addField({
type: ContactInfoFieldType.phone,
value: '5555551234',
name: 'office phone'
});
// Must update the landmark with the modified info
landmark.contactInfo = info;
The ExtraInfo object also stores data relevant for the geographic area, contour geographic area and the Wikipedia-related information.
Modifying the extraInfo field of the landmark may lead to the loss of this information if the related fields are not preserved.
Instantiating Landmarks
Landmarks can be instantiated in multiple ways:
import { Landmark, Coordinates } from '@magiclane/maps-sdk';
// 1. Default initialization
const landmark1 = new Landmark();
// 2. Using latitude & longitude
const landmark2 = Landmark.withLatLng(37.7749, -122.4194);
// 3. With a Coordinates object
const coords = new Coordinates({ latitude: 37.7749, longitude: -122.4194 });
const landmark3 = Landmark.withCoordinates(coords);
Creating a new landmark does not automatically make it visible on the map. Refer to the Display landmarks guide for detailed instructions on how to display a landmark.
Interaction with Landmarks
Selecting Landmarks
Landmarks are selectable by default, meaning user interactions, such as taps or clicks, can identify specific landmarks programmatically (e.g., through the function cursorSelectionLandmarks()). Refer to the Landmark selection guide for more details.
import { GemMap } from '@magiclane/maps-sdk';
// Get landmarks at cursor position
const selectedLandmarks = map.cursorSelectionLandmarks();
selectedLandmarks.forEach(landmark => {
console.log('Selected:', landmark.name);
});
Highlighting Landmarks
A list of landmarks can be highlighted, enabling customization of their visual appearance. Highlighting also allows displaying a list of user-created landmarks on the map. When displaying them, we can also provide an identifier for the highlight. It is possible to deactivate that highlight or to update it - in this case the old highlight is overridden. Refer to the Highlight landmarks guide for more details.
import { HighlightRenderSettings } from '@magiclane/maps-sdk';
// Highlight landmarks on the map
const renderSettings = new HighlightRenderSettings();
map.activateHighlight([landmark1, landmark2], { renderSettings });
// Deactivate highlight
map.deactivateHighlight();
Searching Landmarks
Landmarks are searchable (both landmarks from map and user-created landmarks). Search can be performed based on name, geographic location, proximity to a given route, address, and more. Options to filter the search based on landmark categories are available. Refer to the Get started with Search guide for more details.
import { SearchService, SearchPreferences, GemError } from '@magiclane/maps-sdk';
const preferences = SearchPreferences.create({
maxMatches: 40,
searchAddresses: true,
searchMapPOIs: true
});
SearchService.search({
textFilter: 'restaurant',
referenceCoordinates: coordinates,
preferences: preferences,
onCompleteCallback: (err: GemError, results: Landmark[]) => {
if (err === GemError.success) {
console.log('Found landmarks:', results);
}
}
});
Calculating Route with Landmarks
Landmarks are the sole entities used for route calculations. For detailed guidance, refer to the Get started with Routing guide.
import { RoutingService, RoutePreferences } from '@magiclane/maps-sdk';
RoutingService.calculateRoute({
waypoints: [landmark1, landmark2, landmark3],
preferences: RoutePreferences.create(),
onCompleteCallback: (err, routes) => {
if (err === GemError.success && routes.length > 0) {
console.log('Route calculated:', routes[0]);
}
}
});
Get Notifications When Approaching Landmarks
Alarms can be configured to notify users when approaching specific landmarks that have been custom-selected.
Other Usages
- Most map POIs (such as settlements, roads, addresses, businesses, etc.) are landmarks
- Search results return a list of landmarks
- Intermediary points in a Route are landmarks
Landmark Categories
Landmarks are categorized based on their assigned categories. Each category is defined by a unique ID, an image (which can be used in various UI components created by the SDK user), and a name that is localized based on the language set for the SDK in the case of default categories. Additionally, a landmark may be associated with a parent landmark store if assigned to one.
A single landmark can belong to multiple categories simultaneously.
Predefined Generic Categories
The default landmark categories are presented below:
| Category | Description |
|---|---|
| gasStation | Locations where fuel is available for vehicles. |
| parking | Designated areas for vehicle parking, including public and private lots. |
| foodAndDrink | Places offering food and beverages, such as restaurants, cafes, or bars. |
| accommodation | Facilities providing lodging, including hotels, motels, and hostels. |
| medicalServices | Healthcare facilities like hospitals, clinics, and pharmacies. |
| shopping | Retail stores, shopping malls, and markets for purchasing goods. |
| carServices | Auto repair shops, car washes, and other vehicle maintenance services. |
| publicTransport | Locations associated with buses, trains, trams, and other public transit. |
| wikipedia | Points of interest with available Wikipedia information for added context. |
| education | Educational institutions such as schools, universities, and training centers. |
| entertainment | Places for leisure activities, such as cinemas, theaters, or amusement parks. |
| publicServices | Government or civic buildings like post offices and administrative offices. |
| geographicalArea | Specific geographical zones or regions of interest. |
| business | Office buildings, corporate headquarters, and other business establishments. |
| sightseeing | Tourist attractions, landmarks, and scenic points of interest. |
| religiousPlaces | Places of worship, such as churches, mosques, temples, or synagogues. |
| roadside | Features or amenities located along the side of roads, such as rest areas. |
| sports | Facilities for sports and fitness activities, like stadiums and gyms. |
| uncategorized | Landmarks that do not fall into any specific category. |
| hydrants | Locations of water hydrants, typically for firefighting purposes. |
| emergencyServicesSupport | Facilities supporting emergency services, such as dispatch centers. |
| civilEmergencyInfrastructure | Infrastructure related to emergency preparedness, such as shelters. |
| chargingStation | Stations for charging electric vehicles. |
| bicycleChargingStation | Locations where bicycles can be charged, typically for e-bikes. |
| bicycleParking | Designated parking areas for bicycles. |
The id for each category can be found in the GenericCategoriesId enum, each value having assigned an id. Use the getCategory static method from the GenericCategories class to get the LandmarkCategory class associated with a GenericCategoriesId value.
import { GenericCategories, GenericCategoriesId, LandmarkCategory } from '@magiclane/maps-sdk';
// Get category by ID
const parkingCategory: LandmarkCategory | null = GenericCategories.getCategory(
GenericCategoriesId.parking
);
if (parkingCategory) {
console.log('Category name:', parkingCategory.name);
console.log('Category ID:', parkingCategory.id);
}
In addition to the predefined categories, custom landmark categories can be created, offering flexibility to define tailored classifications for specific needs or applications.
Tree Structure
Each generic landmark category can include multiple POI subcategories. The LandmarkCategory is used both for generic categories and POI subcategories.
For example, the Parking generic category contains Park and Ride, Parking Garage, Parking Lot, RV Park, Truck Parking, Truck Stop and Parking meter POI subcategories.
// Get POI subcategories for a generic category
const parkingSubcategories: LandmarkCategory[] = GenericCategories.getPoiCategories(
GenericCategoriesId.parking
);
parkingSubcategories.forEach(subcategory => {
console.log('Subcategory:', subcategory.name);
});
// Get parent generic category of a POI subcategory
const parentCategory: LandmarkCategory | null = GenericCategories.getGenericCategory(
subcategoryId
);
Do not confuse the getCategory and getGenericCategory methods:
- The
getCategoryis used to get theLandmarkCategoryobject based on the id - The
getGenericCategoryis used to get the parent genericLandmarkCategoryobject of the POI subcategory with the provided id
Usage
- Can be used as a filter parameter within the various types of search
- Landmark visibility on the map can be toggled based on the categories
- Landmark organization within a store
Landmark Stores
Note: Landmark stores are not persistently saved in the TypeScript/browser environment. Unlike the Flutter SDK where stores are saved to SQLite databases on the device, the TypeScript SDK runs in a browser environment where landmarks and stores exist only during the session. Data will be lost when the page is refreshed or closed unless you implement your own persistence mechanism (e.g., using localStorage, IndexedDB, or a backend service).
Landmark stores are collections of landmarks used for multiple purposes through the Maps SDK for TypeScript. They are comprised of landmarks and landmark categories. Each store has a unique name and id.
Implementing Persistence (Optional)
If you need to persist landmarks across sessions, consider these approaches:
// Example: Save to localStorage
function saveLandmarkStore(store: LandmarkStore) {
const landmarks = store.getLandmarks();
const data = {
name: store.name,
landmarks: landmarks.map(lm => ({
name: lm.name,
lat: lm.coordinates.latitude,
lng: lm.coordinates.longitude,
// ... other properties
}))
};
localStorage.setItem(`landmarkStore_${store.name}`, JSON.stringify(data));
}
// Example: Load from localStorage
function loadLandmarkStore(storeName: string): LandmarkStore | null {
const data = localStorage.getItem(`landmarkStore_${storeName}`);
if (!data) return null;
const parsed = JSON.parse(data);
const store = LandmarkStoreService.createLandmarkStore(storeName);
parsed.landmarks.forEach((lmData: any) => {
const landmark = Landmark.withLatLng(lmData.lat, lmData.lng);
landmark.name = lmData.name;
store.addLandmark(landmark);
});
return store;
}
Manage Landmark Stores
The operations related to LandmarkStore management can be found within the LandmarkStoreService class.
Create a New Landmark Store
A new landmark store can be created in the following way:
import { LandmarkStoreService, LandmarkStore } from '@magiclane/maps-sdk';
const landmarkStore: LandmarkStore = LandmarkStoreService.createLandmarkStore('MyLandmarkStore');
The createLandmarkStore will create a new landmark store with the given name if it does not already exist or will return the existing landmark store if an instance with the given name already exists.
In the TypeScript SDK, since stores are not persistent, createLandmarkStore will create a fresh empty store each time the application loads, unlike the Flutter SDK where it may return an existing store from previous sessions.
Get Landmark Store by ID
A landmark store can be obtained by its id:
const landmarkStoreById: LandmarkStore | null = LandmarkStoreService.getLandmarkStoreById(12345);
if (landmarkStoreById) {
console.log('Found store:', landmarkStoreById.name);
}
The getLandmarkStoreById method retrieves a valid LandmarkStore object when provided with a valid ID. If the ID does not correspond to any LandmarkStore, the method returns null.
Get Landmark Store by Name
A landmark store can be obtained by its name:
const landmarkStoreByName: LandmarkStore | null = LandmarkStoreService.getLandmarkStoreByName('MyLandmarkStore');
if (landmarkStoreByName) {
console.log('Found store:', landmarkStoreByName.name);
}
The getLandmarkStoreByName method returns a valid LandmarkStore object if a landmark store exists with the given name and null if the given name does not correspond to any LandmarkStore.
Get All Landmark Stores
The list of landmark stores can be retrieved via the landmarkStores getter:
const landmarkStores: LandmarkStore[] = LandmarkStoreService.landmarkStores;
landmarkStores.forEach(store => {
console.log(`Store: ${store.name}, ID: ${store.id}`);
});
The landmarkStores getter returns both user-created landmark stores and predefined stores in the Maps SDK for TypeScript.
Remove Landmark Stores
A landmark store can be removed in the following way:
const landmarkStoreId: number = landmarkStore.id;
landmarkStore.dispose();
LandmarkStoreService.removeLandmarkStore(landmarkStoreId);
Disposing the LandmarkStore object is mandatory before calling the removeLandmarkStore method. If the store is not disposed then it will not be removed. Any operation called on a disposed LandmarkStore instance will result in an exception being thrown. Therefore, it is crucial to obtain the landmark store ID before it is disposed.
The removeLandmarkStore method will fail if the store is in use (for example, if it is displayed on the map). In this case, an error will be thrown.
Retrieving the Landmark Store Type
The type of a LandmarkStore can be returned by calling LandmarkStoreService.getLandmarkStoreType with the store ID:
import { LandmarkStoreType } from '@magiclane/maps-sdk';
const storeType: LandmarkStoreType = LandmarkStoreService.getLandmarkStoreType(landmarkStoreId);
Predefined Landmark Stores
The Maps SDK for TypeScript includes several predefined landmark stores, and their IDs can be retrieved as follows:
const mapPoisLandmarkStoreId: number = LandmarkStoreService.mapPoisLandmarkStoreId;
const mapAddressLandmarkStoreId: number = LandmarkStoreService.mapAddressLandmarkStoreId;
const mapCitiesLandmarkStoreId: number = LandmarkStoreService.mapCitiesLandmarkStoreId;
These values can be useful when determining whether a landmark originated from the default map elements. If its associated landmarkStoreId has one of these 3 values, it means it comes from the map rather than from other custom data.
These three landmark stores are not intended to be modified. They are only used for functionalities like:
- Filter the categories of landmarks displayed on the map
- Check whether a landmark comes from the map
- When searching, to filter the significant landmarks
Available Operations
The LandmarkStore instance provides the following operations for managing landmarks and categories:
| Operation | Description |
|---|---|
addCategory(category: LandmarkCategory) | Adds a new category to the store. The category must have a name. After addition, the category belongs to this store. |
addLandmark(landmark: Landmark, categoryId?: number) | Adds a copy of the landmark to a specified category in the store. Updates category info if the landmark already exists. Can specify a category. Defaults to uncategorized if no category is specified. |
getLandmark(landmarkId: number) | Retrieves the landmark with the specified landmarkId from the store. Returns null if the landmark does not exist in the store. |
updateLandmark(landmark: Landmark) | Updates information about a specific landmark in the store. This does not affect the landmark's category. The landmark must belong to this store. |
containsLandmark(landmarkId: number) | Checks if the store contains a specific landmark by its ID. Returns true if found, false otherwise. |
categories | Retrieves a list of all categories in the store. |
getCategoryById(categoryId: number) | Fetches a category by its ID. Returns null if not found. |
getLandmarks(categoryId?: number) | Retrieves a list of landmarks in a specified category. Defaults to all categories if none is specified. |
removeCategory(categoryId: number, removeLandmarks?: boolean) | Removes a category by its ID. Optionally removes landmarks in the category or marks them as uncategorized. |
removeLandmark(landmarkId: number) | Removes a specific landmark from the store. |
updateCategory(category: LandmarkCategory) | Updates a specific category's details. The category must belong to this store. |
removeAllLandmarks() | Removes all landmarks from the store. |
id | Retrieves the ID of the landmark store. |
name | Retrieves the name of the landmark store. |
type | Retrieves the type of the landmark store. Can be none, defaultType, mapAddress, mapPoi, mapCity, mapHighwayExit or mapCountry. |
Example: Working with Landmark Stores
import {
LandmarkStoreService,
LandmarkStore,
Landmark,
LandmarkCategory,
GenericCategories,
GenericCategoriesId
} from '@magiclane/maps-sdk';
// Create a landmark store
const myStore = LandmarkStoreService.createLandmarkStore('Favorites');
// Add a category
const customCategory = new LandmarkCategory();
customCategory.name = 'My Places';
myStore.addCategory(customCategory);
// Create and add landmarks
const landmark1 = Landmark.withLatLng(37.7749, -122.4194);
landmark1.name = 'San Francisco Office';
myStore.addLandmark(landmark1, customCategory.id);
const landmark2 = Landmark.withLatLng(34.0522, -118.2437);
landmark2.name = 'Los Angeles Office';
myStore.addLandmark(landmark2, customCategory.id);
// Get all landmarks in the category
const landmarks = myStore.getLandmarks(customCategory.id);
console.log(`Found ${landmarks.length} landmarks`);
// Update a landmark
landmark1.description = 'Main office location';
myStore.updateLandmark(landmark1);
// Remove a landmark
myStore.removeLandmark(landmark2.id);
// Clean up
myStore.dispose();
Usage
- Landmarks are displayed on the map through landmark stores
- Landmark stores are used to customize search functionality
- Landmark stores are used for organizing custom landmarks