smap_flutter 1.0.5
smap_flutter: ^1.0.5 copied to clipboard
sMap for Flutter: maps from the sMap service in Flutter apps, with styles, labels in any language, clustered points, lines, areas and 3D buildings.
example/lib/main.dart
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:smap_flutter/smap_flutter.dart';
/// Pass a token at build time: `flutter run --dart-define=SMAP_TOKEN=sm1....`
/// (an app normally gets it from its own server through `getToken`).
const String token = String.fromEnvironment('SMAP_TOKEN');
/// Or a map key whose allowlist names this app: `--dart-define=SMAP_API_KEY=smk_...`.
const String apiKey = String.fromEnvironment('SMAP_API_KEY');
const String baseUrl = String.fromEnvironment('SMAP_BASE_URL', defaultValue: 'https://tile.srsr.ca');
void main() => runApp(const DemoApp());
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
title: 'sMap demo',
theme: ThemeData(colorSchemeSeed: const Color(0xFF2563EB), useMaterial3: true),
home: const DemoScreen(),
);
}
class DemoScreen extends StatefulWidget {
const DemoScreen({super.key});
@override
State<DemoScreen> createState() => _DemoScreenState();
}
class _DemoScreenState extends State<DemoScreen> {
static const center = LatLng(43.6532, -79.3832);
static const languages = ['en', 'fr', 'de', 'es', 'zh-Hans', 'ja'];
SMapController? _map;
SMapStyle _style = SMapStyle.light;
String _language = 'en';
bool _buildings = false;
/// 2,000 points scattered around the centre (same every run).
List<SMapPoint> _points() {
final random = math.Random(7);
return List.generate(2000, (i) {
final r = 0.25 * math.sqrt(random.nextDouble());
final a = random.nextDouble() * 2 * math.pi;
return SMapPoint(
center.latitude + r * math.sin(a) * 0.72,
center.longitude + r * math.cos(a),
properties: {'name': 'Stop ${i + 1}'},
);
});
}
Future<void> _onReady(SMapController map) async {
_map = map;
await map.addPolygons(
'block',
[
const SMapPolygon([
[LatLng(43.6418, -79.3871), LatLng(43.6418, -79.3833), LatLng(43.6440, -79.3833), LatLng(43.6440, -79.3871)],
], properties: {'name': 'Tower block', 'height': 180}),
],
const SMapPolygonOptions(fill: '#f97316', extrude: SMapExtrude(height: 'height')),
);
await map.addLines(
'route',
[
const SMapLine([
LatLng(43.6455, -79.3807),
LatLng(43.6532, -79.3832),
LatLng(43.6629, -79.3957),
LatLng(43.6677, -79.3948),
], properties: {'name': 'Route 1'}),
],
const SMapLineOptions(color: '#16a34a', width: 5),
);
await map.addPoints('stops', _points(), const SMapPointOptions(cluster: true, label: 'name', zIndex: 1));
map.onTap('stops', (properties, position) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${properties['name']}')));
});
map.onTap('route', (properties, position) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${properties['name']}')));
});
}
void _onError(Object error) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('$error')));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('sMap'),
actions: [
DropdownButton<String>(
value: _language,
underline: const SizedBox.shrink(),
items: [for (final l in languages) DropdownMenuItem(value: l, child: Text(l))],
onChanged: (l) {
if (l == null) return;
setState(() => _language = l);
_map?.setLanguage(l);
},
),
const SizedBox(width: 8),
Row(children: [
const Text('3D'),
Switch(
value: _buildings,
onChanged: (on) {
setState(() => _buildings = on);
_map?.setBuildings3D(on);
},
),
]),
],
),
body: Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: SegmentedButton<SMapStyle>(
segments: [for (final s in SMapStyle.values) ButtonSegment(value: s, label: Text(s.name))],
selected: {_style},
showSelectedIcon: false,
onSelectionChanged: (set) {
setState(() => _style = set.first);
_map?.setStyle(set.first);
},
),
),
Expanded(
child: SMap(
options: SMapOptions(
baseUrl: baseUrl,
token: token.isEmpty ? null : token,
apiKey: apiKey.isEmpty ? null : apiKey,
style: _style,
language: _language,
center: center,
zoom: 11,
),
onReady: _onReady,
onError: _onError,
),
),
],
),
floatingActionButton: FloatingActionButton.small(
onPressed: () => _map?.fitLayer('stops'),
tooltip: 'Show all stops',
child: const Icon(Icons.fit_screen),
),
);
}
}