make packages for dart and npm
This commit is contained in:
@@ -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';
|
||||
}
|
||||
@@ -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<List<dynamic>> 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<Map<String, dynamic>> 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<Symbol> addMarker(MarkerOptions options) async {
|
||||
return await mapController.addSymbol(options.toSymbolOptions());
|
||||
}
|
||||
|
||||
/// Add multiple markers
|
||||
Future<List<Symbol>> addMarkers(List<MarkerOptions> optionsList) async {
|
||||
final symbols = <Symbol>[];
|
||||
for (var options in optionsList) {
|
||||
symbols.add(await addMarker(options));
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
|
||||
/// Remove a marker
|
||||
Future<void> removeMarker(Symbol marker) async {
|
||||
await mapController.removeSymbol(marker);
|
||||
}
|
||||
|
||||
/// Add a polyline (friendly wrapper for addLine)
|
||||
Future<Line> addPolyline(PolylineOptions options) async {
|
||||
return await mapController.addLine(options.toLineOptions());
|
||||
}
|
||||
|
||||
/// Remove a polyline
|
||||
Future<void> removePolyline(Line polyline) async {
|
||||
await mapController.removeLine(polyline);
|
||||
}
|
||||
|
||||
/// Add a circle
|
||||
Future<Circle> addCircle(CircleOptions options) async {
|
||||
return await mapController.addCircle(options.toMapLibreOptions());
|
||||
}
|
||||
|
||||
/// Remove a circle
|
||||
Future<void> removeCircle(Circle circle) async {
|
||||
await mapController.removeCircle(circle);
|
||||
}
|
||||
|
||||
/// Add a polygon (Fill)
|
||||
Future<Fill> addPolygon(PolygonOptions options) async {
|
||||
return await mapController.addFill(options.toFillOptions());
|
||||
}
|
||||
|
||||
/// Remove a polygon
|
||||
Future<void> 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));
|
||||
}
|
||||
}
|
||||
@@ -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<IntaleqMap> createState() => _IntaleqMapState();
|
||||
}
|
||||
|
||||
class _IntaleqMapState extends State<IntaleqMap> {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<maplibre.LatLng> 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<List<maplibre.LatLng>> 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
@@ -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<LatLng> decode(String encoded) {
|
||||
List<LatLng> 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user