Files
maps-saas/packages/js-sdk/src/index.ts
T

220 lines
6.4 KiB
TypeScript

import maplibregl from 'maplibre-gl';
import { IntaleqColors } from './constants';
import { PolylineUtils } from './utils';
export interface IntaleqMapOptions extends Omit<maplibregl.MapOptions, 'container'> {
container: string | HTMLElement;
apiKey: string;
styleType?: 'obsidian' | 'light' | 'hybrid' | 'satellite';
}
export interface MarkerOptions extends maplibregl.MarkerOptions {
position: [number, number];
}
export interface PolylineOptions {
id: string;
coordinates: [number, number][];
color?: string;
width?: number;
opacity?: number;
}
export interface PolygonOptions {
id: string;
rings: [number, number][][]; // First is outer, others are holes
fillColor?: string;
fillOpacity?: number;
outlineColor?: string;
}
export interface CircleOptions {
id: string;
position: [number, number];
radiusMetres: number;
color?: string;
opacity?: number;
strokeColor?: string;
strokeWidth?: number;
}
/**
* Intaleq Maps JS SDK
* Optimized for Jordan & Syria mapping services.
*/
export class IntaleqMap extends maplibregl.Map {
private readonly intaleqApiKey: string;
private addedIntaleqIds: Set<string> = new Set();
constructor(options: IntaleqMapOptions) {
const { apiKey, styleType = 'obsidian', ...mapOptions } = options;
const styleUrl = `https://maps.intaleq.com/styles/${styleType}/style.json?key=${apiKey}`;
super({
...mapOptions,
style: styleUrl,
hash: mapOptions.hash ?? true,
center: mapOptions.center ?? [35.9239, 31.9522], // Default to Amman
zoom: mapOptions.zoom ?? 12,
transformRequest: (url: string) => {
if (url.includes('intaleq.com')) {
const separator = url.includes('?') ? '&' : '?';
return {
url: `${url}${separator}key=${apiKey}`
};
}
return { url };
}
});
this.intaleqApiKey = apiKey;
}
/**
* Helper to search for places using Intaleq Geocoding API
*/
async search(query: string) {
const response = await fetch(`https://map-saas.intaleq.com/v1/geocoding/search?q=${encodeURIComponent(query)}&key=${this.intaleqApiKey}`);
return response.json();
}
/**
* Helper to get routes using Intaleq Routing API
*/
async getRoute(start: [number, number], end: [number, number], profile: 'car' | 'bike' | 'foot' = 'car') {
const response = await fetch(`https://map-saas.intaleq.com/v1/routing/route?start=${start.join(',')}&end=${end.join(',')}&profile=${profile}&key=${this.intaleqApiKey}`);
return response.json();
}
// --- Friendly Abstractions (Transformation Layer) ---
/**
* Add a high-quality marker to the map (HTML-based).
*/
addIntaleqMarker(options: MarkerOptions): maplibregl.Marker {
const marker = new maplibregl.Marker(options)
.setLngLat(options.position)
.addTo(this);
return marker;
}
/**
* Add a polyline (route line) to the map.
*/
addIntaleqPolyline(options: PolylineOptions) {
const { id, coordinates, color, width, opacity } = options;
this.addSource(id, {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: coordinates
}
}
});
this.addLayer({
id: id,
type: 'line',
source: id,
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': color ?? IntaleqColors.primaryBlue,
'line-width': width ?? 5,
'line-opacity': opacity ?? 1.0
}
});
this.addedIntaleqIds.add(id);
}
/**
* Add a polygon (with hole support) to the map.
*/
addIntaleqPolygon(options: PolygonOptions) {
const { id, rings, fillColor, fillOpacity, outlineColor } = options;
this.addSource(id, {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'Polygon',
coordinates: rings
}
}
});
this.addLayer({
id: id,
type: 'fill',
source: id,
paint: {
'fill-color': fillColor ?? IntaleqColors.fillGray,
'fill-opacity': fillOpacity ?? 0.4,
'fill-outline-color': outlineColor ?? IntaleqColors.primaryBlue
}
});
this.addedIntaleqIds.add(id);
}
/**
* Add a circle to the map.
* Note: radius is in pixels for standard GL circles.
* For geographic circles, consider using polygon buffers.
*/
addIntaleqCircle(options: CircleOptions) {
const { id, position, radiusMetres, color, opacity, strokeColor, strokeWidth } = options;
this.addSource(id, {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: position
}
}
});
this.addLayer({
id: id,
type: 'circle',
source: id,
paint: {
'circle-radius': radiusMetres / 10, // Rough pixel approximation for demo
'circle-color': color ?? IntaleqColors.primaryBlue,
'circle-opacity': opacity ?? 0.6,
'circle-stroke-color': strokeColor ?? '#ffffff',
'circle-stroke-width': strokeWidth ?? 2
}
});
this.addedIntaleqIds.add(id);
}
/**
* Remove an object added via Intaleq helpers.
*/
removeIntaleqObject(id: string) {
if (this.getLayer(id)) this.removeLayer(id);
if (this.getSource(id)) this.removeSource(id);
this.addedIntaleqIds.delete(id);
}
/**
* Clear all objects added via Intaleq helpers.
*/
clearAll() {
this.addedIntaleqIds.forEach(id => this.removeIntaleqObject(id));
this.addedIntaleqIds.clear();
}
}
export { maplibregl, IntaleqColors, PolylineUtils };