Files
flutterApp/lib/features/home/presentation/widgets/map/testmap_pages.dart
2026-02-25 18:39:09 +08:00

279 lines
8.3 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
import 'package:maibu_satabot_v2/features/home/presentation/widgets/common/enum.dart';
import 'package:maibu_satabot_v2/features/home/presentation/widgets/startpoint_area.dart';
import '../path_list_pages.dart';
class MapPageEnterprise extends StatefulWidget {
const MapPageEnterprise({Key? key}) : super(key: key);
@override
State<MapPageEnterprise> createState() => _MapPageEnterpriseState();
}
class _MapPageEnterpriseState extends State<MapPageEnterprise> {
final MapController _mapController = MapController();
LatLng? _currentLatLng;
StreamSubscription<Position>? _positionSub;
bool _hasMovedOnce = false;
bool _isPanelOpen = false; // 控制面板显示/隐藏
RobotMode _currentRobotMode = RobotMode.point;
AreaMode _currentAreaMode = AreaMode.work;
@override
void initState() {
super.initState();
_initLocationEnterprise();
}
/// ===============================
/// 企业级定位初始化(已修复坐标系)
/// ===============================
Future<void> _initLocationEnterprise() async {
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) return;
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
}
if (permission != LocationPermission.whileInUse &&
permission != LocationPermission.always) {
return;
}
// 1️⃣ 首次强制获取定位
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.bestForNavigation,
);
final gcj = wgs84ToGcj02(position.latitude, position.longitude);
_updateLocation(gcj, moveMap: true);
// 2️⃣ 实时监听(不再强制移动地图)
_positionSub = Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.bestForNavigation,
distanceFilter: 2,
),
).listen((pos) {
final gcj = wgs84ToGcj02(pos.latitude, pos.longitude);
_updateLocation(gcj, moveMap: false);
});
}
/// ===============================
/// 更新位置
/// ===============================
void _updateLocation(LatLng latLng, {bool moveMap = false}) {
setState(() {
_currentLatLng = latLng;
});
if (moveMap && !_hasMovedOnce) {
_hasMovedOnce = true;
_mapController.move(latLng, 17);
}
}
/// 手动回到当前位置
void _moveToCurrentLocation() {
if (_currentLatLng == null) return;
_mapController.move(_currentLatLng!, 17);
}
@override
void dispose() {
_positionSub?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final menuHeight = 16 * 6; // 假设 VerticalFloatMenu 有 6 个选项,每个高度为 56
final maxTop = screenHeight - menuHeight;
return Scaffold(
body:
SafeArea(
child: Stack(
children: [
FlutterMap(
mapController: _mapController,
options: MapOptions(
initialCenter:
_currentLatLng ?? const LatLng(39.9042, 116.4074),
initialZoom: 15,
maxZoom: 18,
),
children: [
/// 高德瓦片(GCJ-02)
TileLayer(
urlTemplate:
'https://webrd02.is.autonavi.com/appmaptile'
'?style=8&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1'
'&key=bbb1f0f20eed6bf679eddf2625630aba',
),
/// 当前定位 Marker
if (_currentLatLng != null)
MarkerLayer(
markers: [
Marker(
point: _currentLatLng!,
width: 40,
height: 40,
child: const Icon(
Icons.my_location,
color: Colors.blue,
size: 30,
),
),
],
),
],
),
Positioned(
height: 336,
right: 16,
top: maxTop > 10 ? 11 : maxTop, // 确保不超出屏幕范围
child: FloatingActionButton(
onPressed: _moveToCurrentLocation,
child: new VerticalFloatMenu(
onEditTap: (bool isOpen) {
// 关键:接收子组件的回调,修改外部的_isPanelOpen
setState(() {
_isPanelOpen = isOpen;
});
},),
),
),
if (_isPanelOpen)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: BottomOperationPanel(
// 传入初始值
initialRobotMode:RobotMode.point ,
initialAreaMode: AreaMode.work,
// 接收面板的事件回调
onComplete: () {
// 完成按钮点击:关闭面板
setState(() => _isPanelOpen = false);
},
onRobotModeChanged: (mode) {
// 接收机器人模式变更
setState(() => _currentRobotMode = mode);
debugPrint('外部收到机器人模式:$mode');
},
onAreaModeChanged: (mode) {
// 接收作业区域模式变更
setState(() => _currentAreaMode = mode);
debugPrint('外部收到区域模式:$mode');
},
onAddTap: () {
// 加号按钮自定义逻辑
debugPrint('外部处理加号按钮点击');
},
onLandTap: () {
// 地块标签自定义逻辑
debugPrint('外部处理地块标签点击');
},
onRouteTap: () {
// 航线标签自定义逻辑
debugPrint('外部处理航线标签点击');
},
),
),
],
),
));
}
}
/// =======================================================
/// 坐标转换:WGS84 -> GCJ02(国内高德/腾讯通用)
/// =======================================================
const double _pi = 3.14159265358979324;
const double _a = 6378245.0;
const double _ee = 0.00669342162296594323;
LatLng wgs84ToGcj02(double lat, double lon) {
if (_outOfChina(lat, lon)) {
return LatLng(lat, lon);
}
double dLat = _transformLat(lon - 105.0, lat - 35.0);
double dLon = _transformLon(lon - 105.0, lat - 35.0);
double radLat = lat / 180.0 * _pi;
double magic = sin(radLat);
magic = 1 - _ee * magic * magic;
double sqrtMagic = sqrt(magic);
dLat = (dLat * 180.0) /
((_a * (1 - _ee)) / (magic * sqrtMagic) * _pi);
dLon = (dLon * 180.0) / (_a / sqrtMagic * cos(radLat) * _pi);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return LatLng(mgLat, mgLon);
}
bool _outOfChina(double lat, double lon) {
return lon < 72.004 ||
lon > 137.8347 ||
lat < 0.8293 ||
lat > 55.8271;
}
double _transformLat(double x, double y) {
double ret = -100.0 +
2.0 * x +
3.0 * y +
0.2 * y * y +
0.1 * x * y +
0.2 * sqrt(x.abs());
ret += (20.0 * sin(6.0 * x * _pi) +
20.0 * sin(2.0 * x * _pi)) *
2.0 /
3.0;
ret += (20.0 * sin(y * _pi) +
40.0 * sin(y / 3.0 * _pi)) *
2.0 /
3.0;
ret += (160.0 * sin(y / 12.0 * _pi) +
320 * sin(y * _pi / 30.0)) *
2.0 /
3.0;
return ret;
}
double _transformLon(double x, double y) {
double ret = 300.0 +
x +
2.0 * y +
0.1 * x * x +
0.1 * x * y +
0.1 * sqrt(x.abs());
ret += (20.0 * sin(6.0 * x * _pi) +
20.0 * sin(2.0 * x * _pi)) *
2.0 /
3.0;
ret += (20.0 * sin(x * _pi) +
40.0 * sin(x / 3.0 * _pi)) *
2.0 /
3.0;
ret += (150.0 * sin(x / 12.0 * _pi) +
300.0 * sin(x / 30.0 * _pi)) *
2.0 /
3.0;
return ret;
}