make packages for dart and npm
This commit is contained in:
@@ -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;
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user