make packages for dart and npm

This commit is contained in:
Hamza-Ayed
2026-04-16 17:48:43 +03:00
parent 9f2a03a979
commit 34dd9ee35a
21 changed files with 1292 additions and 56 deletions
+19
View File
@@ -0,0 +1,19 @@
/**
* Default Intaleq branding colors and stylings.
*/
export const IntaleqColors = {
/** The signature Intaleq Blue color. */
primaryBlue: '#0D47A1',
/** Cyan used for remaining route lines. */
routeCyan: '#00e5ff',
/** Gray used for traveled paths or alternatives. */
softGray: '#BDBDBD',
/** Semi-transparent gray for polygon fills. */
fillGray: '#BDBDBD33', // 20% opacity
/** Red for error or stop states. */
alertRed: '#ba1a1a',
} as const;
+163 -5
View File
@@ -1,9 +1,41 @@
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';
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;
}
/**
@@ -12,12 +44,11 @@ export interface IntaleqMapOptions extends Omit<maplibregl.MapOptions, 'containe
*/
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;
// Construct the Intaleq style URL
// In production, this points to our tile server with the API key
const styleUrl = `https://maps.intaleq.com/styles/${styleType}/style.json?key=${apiKey}`;
super({
@@ -27,7 +58,6 @@ export class IntaleqMap extends maplibregl.Map {
center: mapOptions.center ?? [35.9239, 31.9522], // Default to Amman
zoom: mapOptions.zoom ?? 12,
transformRequest: (url: string) => {
// Automatically append API key to all tile and asset requests
if (url.includes('intaleq.com')) {
const separator = url.includes('?') ? '&' : '?';
return {
@@ -56,6 +86,134 @@ export class IntaleqMap extends maplibregl.Map {
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 };
export { maplibregl, IntaleqColors, PolylineUtils };
+43
View File
@@ -0,0 +1,43 @@
/**
* Utilities for Intaleq Map SDK.
*/
export class PolylineUtils {
/**
* Decodes a Google-encoded polyline string into an array of [lng, lat] coordinates.
* Note: MapLibre and GeoJSON use [lng, lat] while Google/Flutter use [lat, lng].
*/
static decode(encoded: string): [number, number][] {
const points: [number, number][] = [];
let index = 0;
const len = encoded.length;
let lat = 0;
let lng = 0;
while (index < len) {
let b: number;
let shift = 0;
let result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
const dlat = ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
const dlng = ((result & 1) !== 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
// MapLibre uses [lng, lat]
points.push([lng / 1E5, lat / 1E5]);
}
return points;
}
}