import 'dart:convert';
|
import 'dart:typed_data';
|
import 'dart:ui';
|
import 'dart:io';
|
|
import 'dart:math' as Math;
|
|
import 'package:flutter/material.dart';
|
import 'package:flutter/services.dart';
|
import 'package:locations/model/map/location_model.dart';
|
import 'package:locations/model/map/map_model.dart';
|
import 'package:locations/utils/ui_constant.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:path_provider/path_provider.dart';
|
|
import 'event_bus_util.dart';
|
|
int getLocationDistance(Coordinate p1, Coordinate p2) {
|
double EARTH_RADIUS = 6378137;
|
int distance = 0;
|
double startLongitude = p1.longitude;
|
double startLatitude = p1.latitude;
|
double endLongitude = p2.longitude;
|
double endLatitude = p2.latitude;
|
double radLatitude1 = startLatitude * Math.pi / 180.0;
|
double radLatitude2 = endLatitude * Math.pi / 180.0;
|
double a = (radLatitude1 - radLatitude2).abs();
|
double b =
|
(startLongitude * Math.pi / 180.0 - endLongitude * Math.pi / 180.0).abs();
|
double s = 2 *
|
Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
|
Math.cos(radLatitude1) *
|
Math.cos(radLatitude2) *
|
Math.pow(Math.sin(b / 2), 2)));
|
s = s * EARTH_RADIUS;
|
distance = s.toInt(); // 返回距离单位是米
|
return distance;
|
}
|
|
typedef OnWebViewController = void Function(WebViewController controller);
|
|
typedef OnPageFinish = void Function(String url);
|
|
getMapWebView(BuildContext context, OnWebViewController? controller,
|
{OnPageFinish? pageFinish}) {
|
return WebView(
|
//http://192.168.3.122:8848/test/JsTest.html
|
initialUrl: Constant.MAP_LINK,
|
onWebViewCreated: (WebViewController webViewController) {
|
if (controller != null) {
|
controller(webViewController);
|
}
|
},
|
javascriptChannels: {
|
JavascriptChannel(
|
name: 'mapClick',
|
onMessageReceived: (JavascriptMessage message) {
|
Map<String, dynamic> map = jsonDecode(message.message);
|
eventBus.fire(MapClickEventBus(SimpleLocation(
|
latitude: map["lat"] as double,
|
longitude: map["lng"] as double)));
|
}),
|
JavascriptChannel(
|
name: 'capture',
|
onMessageReceived: (JavascriptMessage message) {
|
print("地图截图:${message.message.length}");
|
|
Uint8List list =
|
base64.decode(message.message.split(";base64,")[1]);
|
getTemporaryDirectory().then((tempDir) {
|
String tempPath = tempDir.path;
|
String captureImgPath = "$tempPath/capture.jpg";
|
if (File(captureImgPath).existsSync()) {
|
File(captureImgPath).deleteSync();
|
}
|
File(captureImgPath).createSync();
|
File(captureImgPath).writeAsBytesSync(list);
|
eventBus.fire(CaptureEventBus(captureImgPath));
|
});
|
|
//保存base64图片
|
|
// //截屏数据
|
// message.message;
|
//
|
// eventBus.fire(MapClickEventBus(SimpleLocation(
|
// latitude: map["lat"] as double,
|
// longitude: map["lng"] as double)));
|
}),
|
},
|
javascriptMode: JavascriptMode.unrestricted,
|
navigationDelegate: (NavigationRequest request) {
|
print("链接:${request.url}");
|
if (!request.url.startsWith("http")) {
|
// launch(request.url);
|
return NavigationDecision.prevent;
|
}
|
return NavigationDecision.navigate;
|
},
|
onPageFinished: (String url) {
|
if (pageFinish != null) {
|
pageFinish(url);
|
}
|
},
|
);
|
}
|
|
///地图工具类
|
class MapUtil {
|
static Future setStarLayer(WebViewController? _webViewController) async {
|
_webViewController!.runJavascript("mapUtil.setBaseLayer(map,3)");
|
}
|
|
static Future setCommonLayer(WebViewController? _webViewController) async {
|
_webViewController!.runJavascript("mapUtil.setBaseLayer(map,1)");
|
}
|
|
static Future capture(WebViewController? _webViewController) async {
|
_webViewController!.runJavascript("mapUtil.capture(map)");
|
}
|
|
static Future<String> drawLine(List<SimpleLocation> points, Color lineColor,
|
WebViewController? _webViewController,
|
{int width = 16, bool showPoint = false}) async {
|
List pointList = [];
|
points.forEach((element) {
|
pointList.add([element.longitude, element.latitude]);
|
});
|
|
String js = "lineManager.init(map,$showPoint,${jsonEncode(pointList)})";
|
print("js:$js");
|
String result = await _webViewController!.runJavascriptReturningResult(js);
|
print("返回结果:" + result);
|
return "line";
|
}
|
|
static Future removeLine(
|
WebViewController? _webViewController, String id) async {
|
String js = "map.removeLayer('$id')";
|
print("js:$js");
|
return await _webViewController!.runJavascript(js);
|
}
|
|
//获取地图的显示参数
|
static Future<MapShowInfo> getMapShowParams(
|
List<SimpleLocation> points) async {
|
if (points.length == 1) {
|
return MapShowInfo(points[0], 18);
|
} else {
|
List<double?> outSides = _getOutSidePoint(points);
|
Coordinate center = Coordinate(
|
(outSides[0]! + outSides[1]!) / 2, (outSides[2]! + outSides[3]!) / 2);
|
//留1/20的边界
|
int zoom =
|
await _getZoom(outSides[0], outSides[1], outSides[2], outSides[3]);
|
return MapShowInfo(
|
SimpleLocation(
|
latitude: center.latitude, longitude: center.longitude),
|
zoom);
|
}
|
}
|
|
//
|
|
///获取地图的中心点
|
static List<double?> _getOutSidePoint(List<SimpleLocation> points) {
|
double? maxLat = points[0].latitude;
|
double? minLat = points[0].latitude;
|
double? maxLng = points[0].longitude;
|
double? minLng = points[0].longitude;
|
|
//获取东南西北四个点
|
points.forEach((element) {
|
if (maxLat! < element.latitude!) {
|
maxLat = element.latitude;
|
}
|
if (minLat! > element.latitude!) {
|
minLat = element.latitude;
|
}
|
|
if (maxLng! < element.longitude!) {
|
maxLng = element.longitude;
|
}
|
|
if (minLng! > element.longitude!) {
|
minLng = element.longitude;
|
}
|
});
|
|
return [maxLat, minLat, maxLng, minLng];
|
}
|
|
static Future<int> _getZoom(
|
double? maxLat, double? minLat, double? maxLng, double? minLng) async {
|
List<double> zoom = [
|
50,
|
100,
|
200,
|
500,
|
1000,
|
2000,
|
5000,
|
10000,
|
20000,
|
25000,
|
50000,
|
100000,
|
200000,
|
500000,
|
1000000,
|
2000000
|
]; //级别18到3。
|
var pointA = Coordinate(maxLat!, maxLng!); // 创建点坐标A
|
var pointB = Coordinate(minLat!, minLng!); // 创建点坐标B
|
//留1/20的边界
|
int? distance = await getLocationDistance(pointA, pointB);
|
distance = (distance / 10).toInt() + distance;
|
for (var i = 0, zoomLen = zoom.length; i < zoomLen; i++) {
|
if (zoom[i] - distance > 0) {
|
return 18 - i + 3; //之所以会多3,是因为地图范围常常是比例尺距离的10倍以上。所以级别会增加3。
|
}
|
}
|
return 18;
|
}
|
|
static Future<Marker> addMarker(WebViewController? _webViewController,
|
SimpleLocation position, String icon,
|
{String? identifier,
|
int zIndex = 0,
|
Offset? offset,
|
double? height,
|
double? width}) async {
|
Marker marker = Marker(
|
position: position,
|
id: identifier,
|
icon: "data:image/png;base64," + icon,
|
zIndex: zIndex,
|
width: width,
|
height: height,
|
centerOffset: offset);
|
|
String js = "markerUtil.addMarker(map, ${jsonEncode(marker.toMap())})";
|
|
print("addMarker:$js");
|
|
/// 添加Marker
|
await _webViewController?.runJavascriptReturningResult(js);
|
return marker;
|
}
|
|
static Future setCenter(
|
WebViewController? _webViewController, SimpleLocation location) async {
|
await _webViewController!.runJavascript(
|
"mapUtil.setCenter(map,[${location.longitude},${location.latitude}])");
|
}
|
|
static Future setZoom(WebViewController? _webViewController, int zoom) async {
|
await _webViewController!.runJavascript("mapUtil.setCenter(map,$zoom)");
|
}
|
|
static removeMarker(WebViewController? _webViewController, Marker marker) {
|
String js = "markerUtil.removeMarker(${marker.Id})";
|
_webViewController!.runJavascript(js);
|
}
|
|
static Future<bool> removeMarkers(
|
WebViewController? _webViewController, List<Marker> markers) async {
|
List ids = [];
|
markers.forEach((element) {
|
ids.add(element.Id);
|
});
|
String js = "markerUtil.removeMarker(${ids})";
|
await _webViewController!.runJavascript(js);
|
return true;
|
}
|
|
static cleanAllMarkers(WebViewController? _webViewController) {
|
//_webViewController!.cleanAllMarkers();
|
}
|
|
static Future<int?> getDistance(
|
SimpleLocation pointA, SimpleLocation pointB) async {
|
return await getLocationDistance(
|
Coordinate(pointA.latitude!, pointA.longitude!),
|
Coordinate(pointB.latitude!, pointB.longitude!));
|
}
|
|
static String getDistanceDesc(int distance) {
|
if (distance >= 1000) {
|
return "${(distance / 1000).toStringAsFixed(1)}米";
|
} else {
|
return "$distance米";
|
}
|
}
|
}
|
|
///路径录制管理
|
///
|
class TravelRECManager {
|
WebViewController? webViewController;
|
List<SimpleLocation> positionList = [];
|
List<Marker> startMarkers = [];
|
|
TravelRECManager(this.webViewController) {
|
webViewController!.runJavascript("lineManager.init(map,false)");
|
}
|
|
//开始录制
|
startREC(SimpleLocation currentPosition) {
|
positionList.clear();
|
positionList.add(currentPosition);
|
|
//画起始点
|
MapMarkerUtil.addTravelStartMarker(webViewController, currentPosition)
|
.then((value) {
|
startMarkers = value;
|
});
|
}
|
|
//添加位置
|
addLocation(SimpleLocation lication) async {
|
if (positionList.isEmpty) {
|
return;
|
}
|
//计算距离,如果距离在10米内就不添加到数组
|
int? distance = await getLocationDistance(
|
Coordinate(positionList[positionList.length - 1].latitude!,
|
positionList[positionList.length - 1].longitude!),
|
Coordinate(lication.latitude!, lication.longitude!));
|
if (distance != null && distance >= 10) {
|
//上传位置
|
positionList.add(lication);
|
await webViewController!.runJavascript(
|
"lineManager.addPoint([${lication.longitude},${lication.latitude}])");
|
}
|
}
|
|
//停止录制
|
stopREC() async {
|
//删除marker
|
await MapUtil.removeMarkers(webViewController, startMarkers);
|
await webViewController!.runJavascript("lineManager.remove()");
|
//清除数据
|
positionList.clear();
|
}
|
}
|
|
//测距
|
class MeasureManager {
|
WebViewController? webViewController;
|
List<SimpleLocation> positionList = [];
|
String? lineId;
|
|
MeasureManager(this.webViewController) {}
|
|
//清除所有覆盖物
|
clear() async {
|
positionList.clear();
|
await webViewController!.runJavascript("lineManager.remove()");
|
}
|
|
Future<double> _getDistance() async {
|
//计算距离
|
double distance = 0;
|
if (positionList.length > 1) {
|
for (var i = 1; i < positionList.length; i++) {
|
distance +=
|
(await MapUtil.getDistance(positionList[i - 1], positionList[i]))!;
|
}
|
}
|
return distance;
|
}
|
|
//添加位置
|
Future<double> addPoint(SimpleLocation location) async {
|
if (lineId == null) {
|
webViewController!.runJavascript("lineManager.init(map,true)");
|
lineId = "line";
|
}
|
//添加点
|
positionList.add(location);
|
String js =
|
"lineManager.addPoint([${location.longitude},${location.latitude}])";
|
print("js:$js");
|
await webViewController!.runJavascript(js);
|
return await _getDistance();
|
}
|
|
//回退位置
|
Future<double> backPoint() async {
|
if (positionList.isEmpty) {
|
return 0;
|
}
|
positionList.removeAt(positionList.length - 1);
|
await webViewController!.runJavascript("lineManager.pop()");
|
return await _getDistance();
|
}
|
}
|
|
class MapMarkerUtil {
|
static Future update(WebViewController? _webViewController, String id,
|
{String? icon, SimpleLocation? position, bool? visibility}) async {
|
Map<String, dynamic> params = {};
|
if (icon != null) {
|
params["icon"] = "data:image/png;base64," + icon;
|
}
|
|
if (position != null) {
|
params["position"] = position.toJson();
|
}
|
|
if (visibility != null) {
|
params["visibility"] = visibility;
|
}
|
|
String js = "markerUtil.updateMarker('$id',${jsonEncode(params)})";
|
print("js:$js");
|
await _webViewController!.runJavascript(js);
|
}
|
|
///添加轨迹开始点
|
static Future<List<Marker>> addTravelStartMarker(
|
WebViewController? _webViewController, SimpleLocation position) async {
|
ByteData byteData =
|
await rootBundle.load("assets/images/map/icon_travel_start.png");
|
Uint8List pngBytes = byteData.buffer.asUint8List();
|
String markerIcon = base64.encode(pngBytes);
|
|
byteData =
|
await rootBundle.load("assets/images/map/icon_travel_start_1.png");
|
pngBytes = byteData.buffer.asUint8List();
|
String marker1Icon = base64.encode(pngBytes);
|
|
Marker marker1 = await MapUtil.addMarker(
|
_webViewController, position, marker1Icon,
|
offset: Offset(0, 20), width: 28, height: 28);
|
|
Marker marker = await MapUtil.addMarker(
|
_webViewController, position, markerIcon,
|
zIndex: 1, width: 40, height: 45);
|
|
return [marker, marker1];
|
}
|
|
//添加轨迹结束点
|
static Future<List<Marker>> addTravelEndMarker(
|
WebViewController? _webViewController, SimpleLocation position) async {
|
ByteData byteData =
|
await rootBundle.load("assets/images/map/icon_travel_end.png");
|
Uint8List pngBytes = byteData.buffer.asUint8List();
|
String markerIcon = base64.encode(pngBytes);
|
|
byteData = await rootBundle.load("assets/images/map/icon_travel_end_1.png");
|
pngBytes = byteData.buffer.asUint8List();
|
String marker1Icon = base64.encode(pngBytes);
|
|
Marker marker1 = await MapUtil.addMarker(
|
_webViewController, position, marker1Icon,
|
offset: Offset(0, 20), width: 28, height: 28, zIndex: 1);
|
|
Marker marker = await MapUtil.addMarker(
|
_webViewController, position, markerIcon,
|
zIndex: 10, width: 40, height: 45);
|
|
return [marker, marker1];
|
}
|
|
///添加文字图层
|
static Future addText(WebViewController? _webViewController,
|
SimpleLocation position, String text,
|
{Color bgColor = const Color(0xAA0E95FE),
|
Color fontColor = Colors.white}) async {
|
// BMFText bmfText = BMFText(
|
// text: " " + text + " ",
|
// position: position,
|
// bgColor: bgColor,
|
// fontColor: fontColor,
|
// fontSize: 30,
|
// typeFace: BMFTypeFace(
|
// familyName: BMFFamilyName.sMonospace,
|
// textStype: BMFTextStyle.BOLD_ITALIC),
|
// alignY: BMFVerticalAlign.ALIGN_CENTER_VERTICAL,
|
// alignX: BMFHorizontalAlign.ALIGN_LEFT);
|
//
|
// /// 添加text
|
// await _webViewController!.addText(bmfText);
|
}
|
}
|