From 34dd9ee35a81b94ec63ac9e6a5856e3ce8c63270 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Thu, 16 Apr 2026 17:48:43 +0300 Subject: [PATCH] make packages for dart and npm --- .../flutter-sdk/.flutter-plugins-dependencies | 1 + packages/flutter-sdk/CHANGELOG.md | 7 + packages/flutter-sdk/LICENSE | 21 + packages/flutter-sdk/README.md | 59 +++ packages/flutter-sdk/lib/intaleq_maps.dart | 55 +-- .../flutter-sdk/lib/src/constants/colors.dart | 16 + .../lib/src/intaleq_map_controller.dart | 105 +++++ .../lib/src/intaleq_map_widget.dart | 57 +++ .../flutter-sdk/lib/src/models/geometry.dart | 110 +++++ packages/flutter-sdk/lib/src/styles.dart | 13 + .../lib/src/utils/polyline_utils.dart | 34 ++ packages/flutter-sdk/pubspec.lock | 418 ++++++++++++++++++ packages/flutter-sdk/pubspec.yaml | 10 +- packages/js-sdk/CHANGELOG.md | 8 + packages/js-sdk/LICENSE | 21 + packages/js-sdk/README.md | 70 +++ packages/js-sdk/examples/index.html | 104 +++++ packages/js-sdk/package.json | 9 +- packages/js-sdk/src/constants.ts | 19 + packages/js-sdk/src/index.ts | 168 ++++++- packages/js-sdk/src/utils.ts | 43 ++ 21 files changed, 1292 insertions(+), 56 deletions(-) create mode 100644 packages/flutter-sdk/.flutter-plugins-dependencies create mode 100644 packages/flutter-sdk/CHANGELOG.md create mode 100644 packages/flutter-sdk/LICENSE create mode 100644 packages/flutter-sdk/README.md create mode 100644 packages/flutter-sdk/lib/src/constants/colors.dart create mode 100644 packages/flutter-sdk/lib/src/intaleq_map_controller.dart create mode 100644 packages/flutter-sdk/lib/src/intaleq_map_widget.dart create mode 100644 packages/flutter-sdk/lib/src/models/geometry.dart create mode 100644 packages/flutter-sdk/lib/src/styles.dart create mode 100644 packages/flutter-sdk/lib/src/utils/polyline_utils.dart create mode 100644 packages/flutter-sdk/pubspec.lock create mode 100644 packages/js-sdk/CHANGELOG.md create mode 100644 packages/js-sdk/LICENSE create mode 100644 packages/js-sdk/README.md create mode 100644 packages/js-sdk/examples/index.html create mode 100644 packages/js-sdk/src/constants.ts create mode 100644 packages/js-sdk/src/utils.ts diff --git a/packages/flutter-sdk/.flutter-plugins-dependencies b/packages/flutter-sdk/.flutter-plugins-dependencies new file mode 100644 index 0000000..e90c5c1 --- /dev/null +++ b/packages/flutter-sdk/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"geolocator_apple","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.13/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"maplibre_gl","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/maplibre_gl-0.19.0+2/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"geolocator_android","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/geolocator_android-4.6.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"maplibre_gl","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/maplibre_gl-0.19.0+2/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"geolocator_apple","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.13/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[],"windows":[{"name":"geolocator_windows","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"geolocator_web","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/geolocator_web-2.2.1/","dependencies":[],"dev_dependency":false},{"name":"maplibre_gl_web","path":"/Users/hamzaaleghwairyeen/.pub-cache/hosted/pub.dev/maplibre_gl_web-0.19.0+2/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"maplibre_gl","dependencies":["maplibre_gl_web"]},{"name":"maplibre_gl_web","dependencies":[]}],"date_created":"2026-04-16 16:50:12.143766","version":"3.32.8","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/packages/flutter-sdk/CHANGELOG.md b/packages/flutter-sdk/CHANGELOG.md new file mode 100644 index 0000000..24c558b --- /dev/null +++ b/packages/flutter-sdk/CHANGELOG.md @@ -0,0 +1,7 @@ +## 1.0.0 + +* Initial release of the Intaleq Maps Foundation SDK. +* Support for Markers, Polylines, Circles, and Polygons (with holes). +* Integrated Intaleq Routing and Geocoding APIs. +* Built-in premium map styles (Obsidian, Light, Satellite). +* Integrated Polyline decoding utility. diff --git a/packages/flutter-sdk/LICENSE b/packages/flutter-sdk/LICENSE new file mode 100644 index 0000000..e4aff3e --- /dev/null +++ b/packages/flutter-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Intaleq + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/flutter-sdk/README.md b/packages/flutter-sdk/README.md new file mode 100644 index 0000000..b156886 --- /dev/null +++ b/packages/flutter-sdk/README.md @@ -0,0 +1,59 @@ +# Intaleq Maps SDK for Flutter + +A premium Flutter SDK for the Intaleq Map Platform, optimized for Jordan, Syria, and the broader region. This SDK provides a simplified, developer-friendly interface over MapLibre GL, with built-in support for Intaleq's Routing and Geocoding APIs. + +## Features + +- **Simplified Geometry**: Use `Marker`, `Polyline`, `Circle`, and `Polygon` (with hole support) instead of complex low-level types. +- **Intaleq Routing**: Integrated multi-profile routing API. +- **Intaleq Geocoding**: High-performance place search and reverse geocoding. +- **Branding-Ready**: Built-in Intaleq branding colors and premium map styles (Obsidian, Light, Satellite). +- **Standalone**: No external dependencies required for route decoding. + +## Getting Started + +Add the following to your `pubspec.yaml`: + +```yaml +dependencies: + intaleq_maps: ^1.0.0 +``` + +## Usage + +### Initialize the Map + +```dart +IntaleqMap( + apiKey: "YOUR_INTALEQ_API_KEY", + onMapCreated: (controller) { + // Access the controller here + }, +) +``` + +### Add a Marker + +```dart +await controller.addMarker(MarkerOptions( + position: LatLng(33.5138, 36.2765), + iconImage: "marker-icon", +)); +``` + +### Get a Route + +```dart +final routeData = await controller.getRoute( + LatLng(33.5138, 36.2765), + LatLng(33.5, 36.3), +); +``` + +## Documentation + +For full documentation and API reference, visit the [Intaleq Documentation](https://map-dashbord.intaleqapp.com/dashboard.html#docs). + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/packages/flutter-sdk/lib/intaleq_maps.dart b/packages/flutter-sdk/lib/intaleq_maps.dart index cf30cf5..53a68b0 100644 --- a/packages/flutter-sdk/lib/intaleq_maps.dart +++ b/packages/flutter-sdk/lib/intaleq_maps.dart @@ -1,49 +1,10 @@ -import 'package:maplibre_gl/maplibre_gl.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; +library intaleq_maps; -class IntaleqMapController { - final MapLibreMapController mapController; - final String apiKey; +export 'package:maplibre_gl/maplibre_gl.dart' show LatLng, LatLngBounds, CameraUpdate, CameraPosition, Symbol, Line, Circle, Fill; - IntaleqMapController({ - required this.mapController, - required this.apiKey, - }); - - /// Search for places using Intaleq Geocoding API - Future> search(String query) async { - final response = await http.get( - Uri.parse( - 'https://map-saas.intaleq.com/v1/geocoding/search?q=$query&key=$apiKey'), - ); - if (response.statusCode == 200) { - return json.decode(response.body); - } - throw Exception('Failed to search'); - } - - /// Get route using Intaleq Routing API - Future> getRoute( - LatLng start, - LatLng end, { - String profile = 'car', - }) async { - final response = await http.get( - Uri.parse( - 'https://map-saas.intaleq.com/v1/routing/route?start=${start.longitude},${start.latitude}&end=${end.longitude},${end.latitude}&profile=$profile&key=$apiKey', - ), - ); - if (response.statusCode == 200) { - return json.decode(response.body); - } - throw Exception('Failed to fetch route'); - } -} - -class IntaleqStyles { - static String obsidian(String apiKey) => - 'https://maps.intaleq.com/styles/obsidian/style.json?key=$apiKey'; - static String light(String apiKey) => - 'https://maps.intaleq.com/styles/light/style.json?key=$apiKey'; -} +export 'src/intaleq_map_controller.dart'; +export 'src/intaleq_map_widget.dart'; +export 'src/styles.dart'; +export 'src/models/geometry.dart'; +export 'src/utils/polyline_utils.dart'; +export 'src/constants/colors.dart'; diff --git a/packages/flutter-sdk/lib/src/constants/colors.dart b/packages/flutter-sdk/lib/src/constants/colors.dart new file mode 100644 index 0000000..ef47394 --- /dev/null +++ b/packages/flutter-sdk/lib/src/constants/colors.dart @@ -0,0 +1,16 @@ +class IntaleqColors { + /// The signature Intaleq Blue color. + static const String primaryBlue = '#0D47A1'; + + /// Cyan used for remaining route lines. + static const String routeCyan = '#00e5ff'; + + /// Gray used for traveled paths or alternatives. + static const String softGray = '#BDBDBD'; + + /// Semi-transparent gray for polygon fills. + static const String fillGray = '#BDBDBD33'; // 20% opacity + + /// Red for error or stop states. + static const String alertRed = '#ba1a1a'; +} diff --git a/packages/flutter-sdk/lib/src/intaleq_map_controller.dart b/packages/flutter-sdk/lib/src/intaleq_map_controller.dart new file mode 100644 index 0000000..2382728 --- /dev/null +++ b/packages/flutter-sdk/lib/src/intaleq_map_controller.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:maplibre_gl/maplibre_gl.dart' hide CircleOptions; +import 'models/geometry.dart'; + +class IntaleqMapController { + final MaplibreMapController mapController; + final String apiKey; + + IntaleqMapController({ + required this.mapController, + required this.apiKey, + }); + + // --- API Integrations --- + + /// Search for places using Intaleq Geocoding API + Future> search(String query) async { + final response = await http.get( + Uri.parse('https://map-saas.intaleq.com/v1/geocoding/search?q=$query&key=$apiKey'), + ); + if (response.statusCode == 200) { + return json.decode(response.body); + } + throw Exception('Failed to search'); + } + + /// Get route using Intaleq Routing API + Future> getRoute(LatLng start, LatLng end, {String profile = 'driving'}) async { + final response = await http.get( + Uri.parse( + 'https://map-saas.intaleq.com/v1/routing/route?start=${start.longitude},${start.latitude}&end=${end.longitude},${end.latitude}&profile=$profile&key=$apiKey', + ), + ); + if (response.statusCode == 200) { + return json.decode(response.body); + } + throw Exception('Failed to fetch route'); + } + + // --- Friendly Abstractions (Transformation Layer) --- + + /// Add a marker (friendly wrapper for addSymbol) + Future addMarker(MarkerOptions options) async { + return await mapController.addSymbol(options.toSymbolOptions()); + } + + /// Add multiple markers + Future> addMarkers(List optionsList) async { + final symbols = []; + for (var options in optionsList) { + symbols.add(await addMarker(options)); + } + return symbols; + } + + /// Remove a marker + Future removeMarker(Symbol marker) async { + await mapController.removeSymbol(marker); + } + + /// Add a polyline (friendly wrapper for addLine) + Future addPolyline(PolylineOptions options) async { + return await mapController.addLine(options.toLineOptions()); + } + + /// Remove a polyline + Future removePolyline(Line polyline) async { + await mapController.removeLine(polyline); + } + + /// Add a circle + Future addCircle(CircleOptions options) async { + return await mapController.addCircle(options.toMapLibreOptions()); + } + + /// Remove a circle + Future removeCircle(Circle circle) async { + await mapController.removeCircle(circle); + } + + /// Add a polygon (Fill) + Future addPolygon(PolygonOptions options) async { + return await mapController.addFill(options.toFillOptions()); + } + + /// Remove a polygon + Future removePolygon(Fill polygon) async { + await mapController.removeFill(polygon); + } + + /// Clear all map objects + void clearAll() { + mapController.clearSymbols(); + mapController.clearLines(); + mapController.clearCircles(); + mapController.clearFills(); + } + + // --- Camera Controls --- + + void animateCameraTo(LatLng position, {double? zoom}) { + mapController.animateCamera(CameraUpdate.newLatLngZoom(position, zoom ?? mapController.cameraPosition?.zoom ?? 14.0)); + } +} diff --git a/packages/flutter-sdk/lib/src/intaleq_map_widget.dart b/packages/flutter-sdk/lib/src/intaleq_map_widget.dart new file mode 100644 index 0000000..e422901 --- /dev/null +++ b/packages/flutter-sdk/lib/src/intaleq_map_widget.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; +import 'intaleq_map_controller.dart'; +import 'styles.dart'; + +typedef MapCreatedCallback = void Function(IntaleqMapController controller); + +class IntaleqMap extends StatefulWidget { + final String apiKey; + final String? styleUrl; + final LatLng initialPosition; + final double initialZoom; + final MapCreatedCallback? onMapCreated; + final bool myLocationEnabled; + + const IntaleqMap({ + super.key, + required this.apiKey, + this.styleUrl, + this.initialPosition = const LatLng(33.5138, 36.2765), + this.initialZoom = 14.0, + this.onMapCreated, + this.myLocationEnabled = false, + }); + + @override + State createState() => _IntaleqMapState(); +} + +class _IntaleqMapState extends State { + IntaleqMapController? _intaleqController; + + @override + Widget build(BuildContext context) { + final style = widget.styleUrl ?? IntaleqStyles.obsidian(widget.apiKey); + + return MaplibreMap( + onMapCreated: (MaplibreMapController controller) { + _intaleqController = IntaleqMapController( + mapController: controller, + apiKey: widget.apiKey, + ); + if (widget.onMapCreated != null) { + widget.onMapCreated!(_intaleqController!); + } + }, + styleString: style, + initialCameraPosition: CameraPosition( + target: widget.initialPosition, + zoom: widget.initialZoom, + ), + myLocationEnabled: widget.myLocationEnabled, + compassEnabled: false, + trackCameraPosition: true, + ); + } +} diff --git a/packages/flutter-sdk/lib/src/models/geometry.dart b/packages/flutter-sdk/lib/src/models/geometry.dart new file mode 100644 index 0000000..454327c --- /dev/null +++ b/packages/flutter-sdk/lib/src/models/geometry.dart @@ -0,0 +1,110 @@ +import 'dart:ui'; +import 'package:maplibre_gl/maplibre_gl.dart' as maplibre; +import '../constants/colors.dart'; + +class MarkerOptions { + final maplibre.LatLng position; + final String? iconImage; + final double? iconSize; + final double? iconRotate; + final String? textField; + final double? textOffset; + + MarkerOptions({ + required this.position, + this.iconImage, + this.iconSize, + this.iconRotate, + this.textField, + this.textOffset, + }); + + maplibre.SymbolOptions toSymbolOptions() { + return maplibre.SymbolOptions( + geometry: position, + iconImage: iconImage, + iconSize: iconSize, + iconRotate: iconRotate, + textField: textField, + textOffset: textOffset != null ? Offset(0, textOffset!) : null, + ); + } +} + +class PolylineOptions { + final List coordinates; + final String? color; + final double? width; + final double? opacity; + + PolylineOptions({ + required this.coordinates, + this.color, + this.width, + this.opacity, + }); + + maplibre.LineOptions toLineOptions() { + return maplibre.LineOptions( + geometry: coordinates, + lineColor: color ?? IntaleqColors.primaryBlue, + lineWidth: width ?? 5.0, + lineOpacity: opacity ?? 1.0, + lineJoin: 'round', + ); + } +} + +class CircleOptions { + final maplibre.LatLng position; + final double radius; + final String? color; + final double? opacity; + final String? strokeColor; + final double? strokeWidth; + + CircleOptions({ + required this.position, + required this.radius, + this.color, + this.opacity, + this.strokeColor, + this.strokeWidth, + }); + + maplibre.CircleOptions toMapLibreOptions() { + return maplibre.CircleOptions( + geometry: position, + circleRadius: radius, + circleColor: color ?? IntaleqColors.primaryBlue, + circleOpacity: opacity ?? 0.6, + circleStrokeColor: strokeColor, + circleStrokeWidth: strokeWidth, + ); + } +} + +class PolygonOptions { + /// The list of rings. The first ring is the outer boundary, + /// and subsequent rings are holes. + final List> rings; + final String? fillColor; + final double? fillOpacity; + final String? outlineColor; + + PolygonOptions({ + required this.rings, + this.fillColor, + this.fillOpacity, + this.outlineColor, + }); + + maplibre.FillOptions toFillOptions() { + return maplibre.FillOptions( + geometry: rings, + fillColor: fillColor ?? IntaleqColors.fillGray, + fillOpacity: fillOpacity ?? 0.4, + fillOutlineColor: outlineColor ?? IntaleqColors.primaryBlue, + ); + } +} diff --git a/packages/flutter-sdk/lib/src/styles.dart b/packages/flutter-sdk/lib/src/styles.dart new file mode 100644 index 0000000..8d297a8 --- /dev/null +++ b/packages/flutter-sdk/lib/src/styles.dart @@ -0,0 +1,13 @@ +class IntaleqStyles { + /// Dark premium map style (The default for Intaleq) + static String obsidian(String apiKey) => + 'https://maps.intaleq.com/styles/obsidian/style.json?key=$apiKey'; + + /// Light premium map style + static String light(String apiKey) => + 'https://maps.intaleq.com/styles/light/style.json?key=$apiKey'; + + /// Satellite hybrid style + static String satellite(String apiKey) => + 'https://maps.intaleq.com/styles/satellite/style.json?key=$apiKey'; +} diff --git a/packages/flutter-sdk/lib/src/utils/polyline_utils.dart b/packages/flutter-sdk/lib/src/utils/polyline_utils.dart new file mode 100644 index 0000000..4349659 --- /dev/null +++ b/packages/flutter-sdk/lib/src/utils/polyline_utils.dart @@ -0,0 +1,34 @@ +import 'package:maplibre_gl/maplibre_gl.dart'; + +class PolylineUtils { + /// Decode a Google-encoded polyline string into a list of LatLng coordinates. + static List decode(String encoded) { + List points = []; + int index = 0, len = encoded.length; + int lat = 0, lng = 0; + + while (index < len) { + int b, shift = 0, result = 0; + do { + b = encoded.codeUnitAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); + lat += dlat; + + shift = 0; + result = 0; + do { + b = encoded.codeUnitAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); + lng += dlng; + + points.add(LatLng(lat / 1E5, lng / 1E5)); + } + return points; + } +} diff --git a/packages/flutter-sdk/pubspec.lock b/packages/flutter-sdk/pubspec.lock new file mode 100644 index 0000000..5fe4bf4 --- /dev/null +++ b/packages/flutter-sdk/pubspec.lock @@ -0,0 +1,418 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + url: "https://pub.dev" + source: hosted + version: "4.0.9" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: f4efb8d3c4cdcad2e226af9661eb1a0dd38c71a9494b22526f9da80ab79520e5 + url: "https://pub.dev" + source: hosted + version: "10.1.1" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d + url: "https://pub.dev" + source: hosted + version: "4.6.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + url: "https://pub.dev" + source: hosted + version: "2.3.13" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + url: "https://pub.dev" + source: hosted + version: "4.2.6" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" + url: "https://pub.dev" + source: hosted + version: "0.2.5" + get: + dependency: "direct main" + description: + name: get + sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a" + url: "https://pub.dev" + source: hosted + version: "4.7.3" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + image: + dependency: transitive + description: + name: image + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + url: "https://pub.dev" + source: hosted + version: "4.8.0" + intl: + dependency: transitive + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + latlong2: + dependency: "direct main" + description: + name: latlong2 + sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" + url: "https://pub.dev" + source: hosted + version: "0.9.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + maplibre_gl: + dependency: "direct main" + description: + name: maplibre_gl + sha256: "9dd9eebee52f42a45aaa9cdb912afa47845c37007b26a799aa482ecd368804c8" + url: "https://pub.dev" + source: hosted + version: "0.19.0+2" + maplibre_gl_platform_interface: + dependency: transitive + description: + name: maplibre_gl_platform_interface + sha256: a95fa38a3532253f32dfe181389adfe9f402773e58ac902d9c4efad3209e0903 + url: "https://pub.dev" + source: hosted + version: "0.19.0+2" + maplibre_gl_web: + dependency: transitive + description: + name: maplibre_gl_web + sha256: "7f1540b384f16f3c9bc8b4ebdfca96fb07f6dab5d9ef4dd0e102985dba238691" + url: "https://pub.dev" + source: hosted + version: "0.19.0+2" + matcher: + dependency: transitive + description: + name: matcher + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + url: "https://pub.dev" + source: hosted + version: "0.12.18" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.dev" + source: hosted + version: "7.0.2" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.dev" + source: hosted + version: "6.5.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + url: "https://pub.dev" + source: hosted + version: "0.7.9" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" +sdks: + dart: ">=3.9.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/flutter-sdk/pubspec.yaml b/packages/flutter-sdk/pubspec.yaml index ee9c2f9..2c32af6 100644 --- a/packages/flutter-sdk/pubspec.yaml +++ b/packages/flutter-sdk/pubspec.yaml @@ -1,7 +1,7 @@ name: intaleq_maps description: Premium Flutter SDK for Intaleq Map Platform (Jordan & Syria). version: 1.0.0 -homepage: https://intaleq.com +homepage: https://intaleqapp.com environment: sdk: ">=3.0.0 <4.0.0" @@ -10,8 +10,14 @@ environment: dependencies: flutter: sdk: flutter - maplibre_gl: ^0.19.0 # Use standard MapLibre plugin + maplibre_gl: ^0.19.0 http: ^1.1.0 + geolocator: ^10.1.0 + get: ^4.6.6 + latlong2: ^0.9.0 + +repository: https://github.com/Hamza-Ayed/intaleq_maps +issue_tracker: https://github.com/Hamza-Ayed/intaleq_maps/issues dev_dependencies: flutter_test: diff --git a/packages/js-sdk/CHANGELOG.md b/packages/js-sdk/CHANGELOG.md new file mode 100644 index 0000000..c270444 --- /dev/null +++ b/packages/js-sdk/CHANGELOG.md @@ -0,0 +1,8 @@ +## 1.0.0 + +* Initial release of the Intaleq Maps JS SDK (`intaleq-maps-gl`). +* Full feature parity with the Flutter SDK. +* Friendly methods for Markers, Polylines, Polygons, and Circles. +* Integrated search and routing API helpers. +* Built-in Intaleq branding palette. +* Built-in Polyline decoding utility. diff --git a/packages/js-sdk/LICENSE b/packages/js-sdk/LICENSE new file mode 100644 index 0000000..e4aff3e --- /dev/null +++ b/packages/js-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Intaleq + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/js-sdk/README.md b/packages/js-sdk/README.md new file mode 100644 index 0000000..efb50f5 --- /dev/null +++ b/packages/js-sdk/README.md @@ -0,0 +1,70 @@ +# Intaleq Maps JS SDK (`intaleq-maps-gl`) + +A premium JavaScript/TypeScript SDK for the Intaleq Map Platform, built on top of MapLibre GL. Optimized for high-performance mapping in Jordan, Syria, and the broader region. + +## Features + +- **Simplified Geometry**: Use `addIntaleqMarker`, `addIntaleqPolyline`, `addIntaleqPolygon`, and `addIntaleqCircle` for rapid development. +- **Intaleq Routing**: Integrated multi-profile routing API. +- **Intaleq Geocoding**: High-performance place search and reverse geocoding. +- **Branding-Ready**: Built-in Intaleq branding colors and premium map styles (Obsidian, Light, Satellite). +- **Polyline decoding**: Built-in support for decoding server-side encoded routes. + +## Installation + +```bash +npm install intaleq-maps-gl +``` + +Or via CDN: + +```html + +``` + +## Quick Start + +### Initialize the Map + +```javascript +import { IntaleqMap } from 'intaleq-maps-gl'; + +const map = new IntaleqMap({ + container: 'map', + apiKey: 'YOUR_INTALEQ_API_KEY', + styleType: 'obsidian' +}); + +map.on('load', () => { + // Add a marker + map.addIntaleqMarker({ + position: [36.2765, 33.5138], // [lng, lat] + color: '#0D47A1' + }); +}); +``` + +### Search for Places + +```javascript +const results = await map.search('Amman'); +console.log(results); +``` + +### Get a Route + +```javascript +const route = await map.getRoute([36.2, 33.5], [36.3, 33.6]); +map.addIntaleqPolyline({ + id: 'route-line', + coordinates: route.geometry.coordinates +}); +``` + +## Documentation + +For full documentation and API reference, visit the [Intaleq Documentation](https://map-dashbord.intaleqapp.com/dashboard.html#docs). + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/packages/js-sdk/examples/index.html b/packages/js-sdk/examples/index.html new file mode 100644 index 0000000..e0d918e --- /dev/null +++ b/packages/js-sdk/examples/index.html @@ -0,0 +1,104 @@ + + + + + + Intaleq Maps JS SDK - Live Demo + + + + + +
+

Intaleq SDK Demo

+

This demo showcases the Intaleq Maps JS SDK in action. It utilizes our premium Obsidian style and simplified geometry API.

+ +
+
+ +
+ + + + + + + + + diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index 67198e0..262bdf0 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -1,10 +1,15 @@ { - "name": "@intaleq/maps-gl", + "name": "intaleq-maps-gl", "version": "1.0.0", - "description": "Premium JavaScript SDK for Intaleq Map Platform", + "description": "Premium JavaScript SDK for Intaleq Map Platform (Jordan & Syria)", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/Hamza-Ayed/intaleq_maps_gl_js.git" + }, + "homepage": "https://intaleqapp.com", "scripts": { "build": "tsup src/index.ts --format cjs,esm --dts", "dev": "tsup src/index.ts --format cjs,esm --watch --dts", diff --git a/packages/js-sdk/src/constants.ts b/packages/js-sdk/src/constants.ts new file mode 100644 index 0000000..41c8beb --- /dev/null +++ b/packages/js-sdk/src/constants.ts @@ -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; diff --git a/packages/js-sdk/src/index.ts b/packages/js-sdk/src/index.ts index cbe630e..cdf3cde 100644 --- a/packages/js-sdk/src/index.ts +++ b/packages/js-sdk/src/index.ts @@ -1,9 +1,41 @@ 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'; + 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 = 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 }; diff --git a/packages/js-sdk/src/utils.ts b/packages/js-sdk/src/utils.ts new file mode 100644 index 0000000..78bd45d --- /dev/null +++ b/packages/js-sdk/src/utils.ts @@ -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; + } +}