flutter_integrated_whb/assets/map/test_baidu_map.html

381 lines
14 KiB
HTML
Raw Normal View History

<!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>