import maplibregl from 'maplibre-gl'; import { IntaleqColors } from './constants'; import { PolylineUtils } from './utils'; export interface IntaleqMapOptions extends Omit { 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 = 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 };