flutter_integrated_whb/assets/map/test_baidu_map.html

381 lines
14 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>特殊作业扎点</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<style>
body, html, #container {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
font-family: "微软雅黑";
}
#hint {
position: absolute;
z-index: 9999;
left: 10px;
top: 10px;
padding: 6px 10px;
background: rgba(255,255,255,0.9);
border-radius: 4px;
font-size: 12px;
}
</style>
<!-- Baidu Map WebGL (保留你的 key) -->
<script type="text/javascript"
src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr"></script>
<script src="./uni.webview.1.5.4.js"></script>
</head>
<body onload="onLoad()">
<div id="container"></div>
<div id="hint" style="display:none"></div>
</body>
<script>
// 地图与数据容器
var map = null;
var marker = null;
var GSON_LON_LAT_WSG84 = []; // WGS84 多点 [[lon,lat,alt], ...]
var GSON_LON_LAT_BD09 = []; // 转换后的 BD09 二维点 [[lng,lat],...]
var convertor = null;
// ---------------------------
// 通用通知宿主Flutter / 原生 / web
// 会尝试多种桥接方式
// data 可以是对象或字符串
// ---------------------------
function notifyHost(data) {
try {
// prefer passing object where supported
if (window.JS && typeof window.JS.postMessage === 'function') {
// webview_flutter JavaScriptChannel expects string
var payload = (typeof data === 'string') ? data : JSON.stringify(data);
window.JS.postMessage(payload);
return;
}
if (window.flutter_inappwebview && typeof window.flutter_inappwebview.callHandler === 'function') {
// flutter_inappwebview can accept objects
window.flutter_inappwebview.callHandler('messageHandler', data);
return;
}
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.JS && typeof window.webkit.messageHandlers.JS.postMessage === 'function') {
window.webkit.messageHandlers.JS.postMessage(data);
return;
}
// fallback to uni (if present) to keep backward compatibility
if (window.uni && typeof window.uni.postMessage === 'function') {
window.uni.postMessage({data: data});
return;
}
// last resort, console (useful for debugging)
console.log('notifyHost:', data);
} catch (e) {
console.error('notifyHost error:', e);
}
}
// ---------------------------
// 尝试从 URL 初始化(如果 Flutter 把参数拼在 URL 上)
// 支持参数: longitude, latitude, GSON (JSON string, 已 encodeURIComponent)
// ---------------------------
function tryInitFromUrl() {
try {
const params = new URLSearchParams(window.location.search);
const lon = params.get('longitude');
const lat = params.get('latitude');
const gsonRaw = params.get('GSON'); // 预期是 encodeURIComponent(JSON.stringify([...]))
var has = false;
if (lon && lat) has = true;
if (gsonRaw) has = true;
if (!has) return false;
var gson = null;
if (gsonRaw) {
try {
gson = JSON.parse(decodeURIComponent(gsonRaw));
} catch (e) {
// 如果直接是未 encode 的 JSON 字符串,也尝试解析
try { gson = JSON.parse(gsonRaw); } catch (e2) { gson = null; }
}
}
// 使用从 url 获取到的数据执行初始化
initWithData({
longitude: parseFloat(lon),
latitude: parseFloat(lat),
GSON: gson
});
return true;
} catch (e) {
console.warn('tryInitFromUrl error', e);
return false;
}
}
// ---------------------------
// Flutter/宿主可调用的初始化函数
// 支持两种调用方式:
// 1) initWithData({longitude: xx, latitude: yy, GSON: [...]})
// 2) initWithData(longitude, latitude, GSONArray)
// GSONArray 结构应与原来一致([[lon,lat,alt], ...]
// ---------------------------
window.initWithData = function() {
var args = arguments;
var payload = {};
if (args.length === 1 && typeof args[0] === 'object') {
payload = args[0];
} else {
// try positional
payload.longitude = args[0];
payload.latitude = args[1];
payload.GSON = args[2];
}
try {
if (!payload) payload = {};
// default safe parse
var lon = Number(payload.longitude) || 0;
var lat = Number(payload.latitude) || 0;
var gson = payload.GSON || [];
// ensure convertor exists
if (!convertor && window.BMapGL && typeof BMapGL.Convertor === 'function') {
convertor = new BMapGL.Convertor();
}
// set global wgs84 list (if provided)
if (Array.isArray(gson) && gson.length > 0) {
GSON_LON_LAT_WSG84 = gson;
}
// init map & polygon
fnInitMap(lon, lat);
if (GSON_LON_LAT_WSG84 && GSON_LON_LAT_WSG84.length > 0) {
fnInitConvertorData(GSON_LON_LAT_WSG84);
}
showHint('地图已初始化');
return true;
} catch (e) {
console.error('initWithData error', e);
return false;
}
};
// 显示调试提示
function showHint(text) {
var el = document.getElementById('hint');
if (!el) return;
el.style.display = 'block';
el.innerText = text;
setTimeout(function(){ el.style.display = 'none'; }, 4000);
}
// ---------------------------
// 页面加载
// ---------------------------
function onLoad() {
// create convertor if possible
if (window.BMapGL && typeof BMapGL.Convertor === 'function') {
convertor = new BMapGL.Convertor();
} else {
console.warn('BMapGL.Convertor not ready yet.');
}
// 创建地图对象(延迟绑定 center等 init 时调用)
map = new BMapGL.Map('container');
map.enableScrollWheelZoom(true);
map.setDisplayOptions({ building: false });
map.addEventListener('click', MapClick);
// 如果 URL 带参数则自动初始化,否则等待宿主调用 initWithData(...)
var ok = tryInitFromUrl();
if (!ok) {
showHint('等待宿主调用 initWithData(...) 初始化地图');
}
}
// ---------------------------
// 点在多边形内判定(二维,只用 lon/lat
// polygon = [[lng,lat], ...]
// point = [lng, lat]
// ---------------------------
function isPointInPolygon(point, polygon) {
const x = point[0];
const y = point[1];
let inside = false;
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i][0], yi = polygon[i][1];
const xj = polygon[j][0], yj = polygon[j][1];
const intersect = ((yi > y) !== (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
// 地图点击处理
function MapClick(e) {
try {
if (marker) map.removeOverlay(marker);
marker = new BMapGL.Marker(new BMapGL.Point(e.latlng.lng, e.latlng.lat));
const x = [e.latlng.lng, e.latlng.lat];
let inside = (GSON_LON_LAT_BD09 && GSON_LON_LAT_BD09.length > 0) ? isPointInPolygon(x, GSON_LON_LAT_BD09) : true;
if (!inside) {
alert("当前选择点位不在区域中!");
notifyHost({type:'point_selected', ok:false, reason:'out_of_polygon', lng:e.latlng.lng, lat:e.latlng.lat});
} else {
map.addOverlay(marker);
// 把 BD09 -> WGS84 转换后的点回传给宿主
fnConvertorBd09ToWgs84Data2(e.latlng.lng, e.latlng.lat);
notifyHost({type:'point_selected', ok:true, lng:e.latlng.lng, lat:e.latlng.lat});
}
} catch (err) {
console.error('MapClick error', err);
}
}
// ---------------------------
// 将 WGS84 多点转换为 BD09 并绘制多边形
// arr: [[lon,lat,...], ...] 注意原 arr GSON_LON_LAT_WSG84顺序是 lon, lat
// ---------------------------
function fnInitConvertorData(arr) {
try {
if (!convertor) convertor = new BMapGL.Convertor();
var points = [];
for (let i = 0; i < arr.length; i++) {
var xi = arr[i][0], yi = arr[i][1];
points.push(new BMapGL.Point(xi, yi));
}
convertor.translate(points, 1, 5, function(res) {
if (!res || !res.points) {
console.warn('convertor.translate returned no points', res);
return;
}
GSON_LON_LAT_BD09 = [];
var list = [];
for (var p = 0; p < res.points.length; p++) {
let item = res.points[p];
GSON_LON_LAT_BD09.push([item.lng, item.lat]);
list.push(new BMapGL.Point(item.lng, item.lat));
}
var polygon = new BMapGL.Polygon(list, {
zIndex: 999,
strokeColor: 'blue',
strokeWeight: 5,
strokeOpacity: 0.5
});
map.addOverlay(polygon);
});
} catch (e) {
console.error('fnInitConvertorData error', e);
}
}
// ---------------------------
// 初始化地图中心longitude, latitude 为 WGS84
// ---------------------------
function fnInitMap(longitude, latitude) {
try {
if (!convertor) convertor = new BMapGL.Convertor();
var ponits = [ new BMapGL.Point(longitude, latitude) ];
convertor.translate(ponits, 1, 5, function(res) {
if (!res || !res.points || res.points.length === 0) {
console.warn('fnInitMap: translate failed', res);
return;
}
var pt = res.points[0];
map.centerAndZoom(new BMapGL.Point(pt.lng, pt.lat), 18);
});
} catch (e) {
console.error('fnInitMap error', e);
}
}
// ---------------------------
// BD09 -> WGS84 JS 版算法),并把结果 post 给宿主
// 注意: bdLat, bdLon 参数顺序(原函数输入顺序)
// 返回 [wgsLat, wgsLon](跟原实现一致)
// ---------------------------
const bd09ToWgs84 = (bdLat, bdLon) => {
const x_pi = (Math.PI * 3000.0) / 180.0;
const x = bdLon - 0.0065;
const y = bdLat - 0.006;
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
const gcjLon = z * Math.cos(theta);
const gcjLat = z * Math.sin(theta);
let dlat = transformlat(gcjLon - 105.0, gcjLat - 35.0);
let dlng = transformlng(gcjLon - 105.0, gcjLat - 35.0);
const radlat = (gcjLat / 180.0) * Math.PI;
let magic = Math.sin(radlat);
magic = 1 - 0.006693421622965943 * magic * magic;
const sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / (((6378245.0 * (1 - 0.006693421622965943)) / (magic * sqrtmagic)) * Math.PI);
dlng = (dlng * 180.0) / ((6378245.0 / sqrtmagic) * Math.cos(radlat) * Math.PI);
const mglat = gcjLat + dlat;
const mglng = gcjLon + dlng;
const wgsLon = gcjLon * 2 - mglng;
const wgsLat = gcjLat * 2 - mglat;
return [wgsLat, wgsLon];
};
const transformlat = (lng, lat) => {
let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += ((20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 * Math.sin(2.0 * lng * Math.PI)) * 2.0) / 3.0;
ret += ((20.0 * Math.sin(lat * Math.PI) + 40.0 * Math.sin((lat / 3.0) * Math.PI)) * 2.0) / 3.0;
ret += ((160.0 * Math.sin((lat / 12.0) * Math.PI) + 320 * Math.sin((lat * Math.PI) / 30.0)) * 2.0) / 3.0;
return ret;
};
const transformlng = (lng, lat) => {
let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += ((20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 * Math.sin(2.0 * lng * Math.PI)) * 2.0) / 3.0;
ret += ((20.0 * Math.sin(lng * Math.PI) + 40.0 * Math.sin((lng / 3.0) * Math.PI)) * 2.0) / 3.0;
ret += ((150.0 * Math.sin((lng / 12.0) * Math.PI) + 300.0 * Math.sin((lng / 30.0) * Math.PI)) * 2.0) / 3.0;
return ret;
};
// ---------------------------
// 使用百度 convertor如果可用把 BD09 点转回 WGS84 并 postMessage 给宿主
// 备用:也会调用 bd09ToWgs84 本地算法
// ---------------------------
function fnConvertorBd09ToWgs84Data2(lng, lat) {
try {
// first try convertor.translate from BMapGL
if (convertor && typeof convertor.translate === 'function') {
var pts = [ new BMapGL.Point(lng, lat) ];
convertor.translate(pts, 5, 1, function(res) {
if (res && res.points && res.points.length > 0) {
var p = res.points[0];
// res.points are in WGS84? depends on convert params; keep compatibility:
notifyHost({type:'converted', longitue: p.lng, latitude: p.lat});
return;
}
// fallback to local algorithm if convertor result absent
var w = bd09ToWgs84(lat, lng);
notifyHost({type:'converted', longitue: w[1], latitude: w[0]});
});
} else {
var w = bd09ToWgs84(lat, lng);
notifyHost({type:'converted', longitue: w[1], latitude: w[0]});
}
} catch (e) {
console.error('fnConvertorBd09ToWgs84Data2 error', e);
var w = bd09ToWgs84(lat, lng);
notifyHost({type:'converted', longitue: w[1], latitude: w[0]});
}
}
// 兼容老方法名
window.fnInitMap = fnInitMap;
window.fnInitConvertorData = fnInitConvertorData;
window.fnConvertorBd09ToWgs84Data2 = fnConvertorBd09ToWgs84Data2;
</script>
</html>