地图修改

This commit is contained in:
cwchen 2026-01-14 13:29:07 +08:00
parent 7ab1cda769
commit a9c2b1dae0
1 changed files with 549 additions and 29 deletions

View File

@ -406,9 +406,12 @@
currentLocation: null,
currentHeading: 0,
watchPositionId: null,
watchOrientationId: null
watchOrientationId: null,
watchLocationTimer: null,
mapLoaded: false
},
locationIconCache: null,
baiduGeolocation: null,
elements: {
panel: null,
tree: null,
@ -429,15 +432,12 @@
this.state.projectInfo = Utils.safeParseJSON(params.projectInfo, []);
this.state.currentClickedProject = Utils.safeParseJSON(params.clickedProject);
// 初始化地图
// 初始化地图(地图加载完成后再初始化定位功能)
this.initMap(this.state.projectInfo);
// 渲染工程列表
this.renderProjectList();
// 初始化定位功能
this.initLocationTracking();
// 处理 URL Action
this.handleUrlActions(params);
},
@ -505,7 +505,27 @@
this.map.centerAndZoom(center, 12);
this.map.enableScrollWheelZoom(true);
projectInfo.forEach(p => this.addProjectMarker(p));
// 等待地图加载完成
this.map.addEventListener('tilesloaded', () => {
console.log('地图瓦片加载完成');
this.state.mapLoaded = true;
// 地图加载完成后,添加项目标记
projectInfo.forEach(p => this.addProjectMarker(p));
// 地图加载完成后,初始化定位跟踪
this.initLocationTracking();
});
// 也监听地图初始化完成事件(备用)
this.map.addEventListener('load', () => {
console.log('地图加载完成');
if (!this.state.mapLoaded) {
this.state.mapLoaded = true;
projectInfo.forEach(p => this.addProjectMarker(p));
this.initLocationTracking();
}
});
},
/**
@ -575,27 +595,474 @@
* 开始监听位置变化
*/
startWatchingPosition() {
const options = {
enableHighAccuracy: true, // 高精度定位
timeout: 10000,
maximumAge: 0 // 不使用缓存
// 优先使用百度地图SDK定位直接返回BD09坐标最准确
if (typeof BMapGL !== 'undefined' && BMapGL.Geolocation) {
console.log('使用百度地图SDK辅助定位API优先');
this.startBaiduGeolocation();
} else if (typeof uni !== 'undefined' && uni.getLocation) {
console.log('使用uni-app GPS定位APIWGS84');
this.startUniAppGPSGeolocation();
} else if (typeof plus !== 'undefined' && plus.geolocation) {
console.log('使用5+定位API');
this.startPlusGeolocation();
} else {
console.log('使用浏览器定位API');
this.startBrowserGeolocation();
}
},
/**
* 使用百度地图定位返回BD09坐标无需转换- 开启SDK辅助定位
*/
startBaiduGeolocation() {
// 确保地图已加载完成
if (!this.map || !this.state.mapLoaded) {
console.warn('地图未加载完成,延迟启动百度定位');
setTimeout(() => this.startBaiduGeolocation(), 500);
return;
}
const geolocation = new BMapGL.Geolocation();
// 开启SDK辅助定位提高定位精度
geolocation.enableSDKLocation();
console.log('已开启百度地图SDK辅助定位');
// 获取当前位置增加超时时间等待GPS定位
let retryCount = 0;
const maxRetries = 3;
const tryGetPosition = () => {
geolocation.getCurrentPosition((result) => {
const status = geolocation.getStatus();
console.log('百度地图定位状态:', status, '结果:', result, '重试次数:', retryCount);
// 百度地图定位成功状态码是0
if (status === 0 && result && result.point) {
const point = result.point;
const accuracy = result.accuracy || 999; // 如果没有精度信息,假设精度较差
console.log('百度地图SDK定位成功 - 经度:', point.lng, '纬度:', point.lat, '精度:', accuracy, '米');
// 验证坐标有效性
if (point.lng && point.lat && !isNaN(point.lng) && !isNaN(point.lat) &&
Math.abs(point.lng) <= 180 && Math.abs(point.lat) <= 90) {
// 如果精度太差大于50米且还有重试次数继续重试
if (accuracy > 50 && retryCount < maxRetries) {
retryCount++;
console.log(`精度较差(${accuracy}米),重试获取更精确位置 (${retryCount}/${maxRetries})`);
setTimeout(tryGetPosition, 2000);
return;
}
// 如果精度仍然很差大于100米切换到GPS定位
if (accuracy > 100 && typeof uni !== 'undefined' && uni.getLocation) {
console.warn('百度定位精度较差(' + accuracy + '米)切换到GPS定位');
this.startUniAppGPSGeolocation();
return;
}
this.state.currentLocation = {
lng: point.lng,
lat: point.lat,
accuracy: accuracy
};
// 使用逆地理编码验证位置(可选,用于调试)
this.verifyLocationWithGeocoder(point.lng, point.lat);
this.updateLocationMarker();
} else {
console.error('百度定位返回无效坐标:', point);
// 降级到uni-app定位
if (typeof uni !== 'undefined' && uni.getLocation) {
this.startUniAppGPSGeolocation();
}
}
} else {
// 如果失败且还有重试次数,继续重试
if (retryCount < maxRetries) {
retryCount++;
console.log(`定位失败,重试 (${retryCount}/${maxRetries})`);
setTimeout(tryGetPosition, 2000);
return;
}
console.warn('百度地图定位失败,状态:', status, '尝试备用方案');
// 降级到uni-app定位
if (typeof uni !== 'undefined' && uni.getLocation) {
this.startUniAppGPSGeolocation();
} else {
this.startBrowserGeolocation();
}
}
}, {
enableHighAccuracy: true,
timeout: 30000 // 30秒超时等待GPS定位
});
};
tryGetPosition();
// 持续监听位置变化(使用定时器定期获取)
this.state.watchLocationTimer = setInterval(() => {
geolocation.getCurrentPosition((result) => {
const status = geolocation.getStatus();
if (status === 0 && result && result.point) {
const point = result.point;
const accuracy = result.accuracy || 999;
// 验证坐标有效性
if (point.lng && point.lat && !isNaN(point.lng) && !isNaN(point.lat) &&
Math.abs(point.lng) <= 180 && Math.abs(point.lat) <= 90) {
// 如果精度太差大于100米切换到GPS定位
if (accuracy > 100 && typeof uni !== 'undefined' && uni.getLocation) {
console.warn('百度定位精度持续较差(' + accuracy + '米)切换到GPS定位');
clearInterval(this.state.watchLocationTimer);
this.startUniAppGPSGeolocation();
return;
}
// 只更新精度更好的位置精度提升超过10米或者精度小于50米
if (!this.state.currentLocation ||
(accuracy < this.state.currentLocation.accuracy - 10) ||
(accuracy < 50 && this.state.currentLocation.accuracy >= 50)) {
console.log('位置更新 - 经度:', point.lng, '纬度:', point.lat, '精度:', accuracy, '米');
this.state.currentLocation = {
lng: point.lng,
lat: point.lat,
accuracy: accuracy
};
this.updateLocationMarker();
}
}
}
}, {
enableHighAccuracy: true,
timeout: 30000
});
}, 5000); // 每5秒更新一次给GPS更多时间稳定
// 保存geolocation实例以便后续使用
this.baiduGeolocation = geolocation;
},
/**
* 使用逆地理编码验证位置(用于调试)
*/
verifyLocationWithGeocoder(lng, lat) {
if (!this.map) return;
const geocoder = new BMapGL.Geocoder();
const point = new BMapGL.Point(lng, lat);
geocoder.getLocation(point, (result) => {
if (result && result.address) {
console.log('位置验证 - 地址:', result.address);
}
});
},
/**
* 使用uni-app GPS定位WGS84坐标最准确
*/
startUniAppGPSGeolocation() {
console.log('使用uni-app GPS定位WGS84');
// 先获取一次当前位置
uni.getLocation({
type: 'wgs84', // 使用WGS84坐标系GPS原始坐标然后转换为BD09
altitude: false,
geocode: false,
highAccuracyExpireTime: 10000, // 增加等待时间获取GPS定位
success: (res) => {
console.log('uni-app GPS定位成功:', res.longitude, res.latitude, '精度:', res.accuracy);
// uni-app返回的是WGS84坐标需要转换为BD09
this.wgs84ToBd09(res.longitude, res.latitude, (bd09) => {
if (bd09 && bd09.lng && bd09.lat) {
this.state.currentLocation = {
lat: bd09.lat,
lng: bd09.lng,
accuracy: res.accuracy || 0
};
console.log('GPS坐标转换完成 - BD09:', bd09.lng, bd09.lat);
this.updateLocationMarker();
} else {
console.error('GPS坐标转换失败使用GCJ02定位');
this.startUniAppGeolocation();
}
});
},
fail: (err) => {
console.error('uni-app GPS定位失败:', err);
// 降级到GCJ02定位
this.startUniAppGeolocation();
}
});
// 持续监听位置变化
this.state.watchLocationTimer = setInterval(() => {
uni.getLocation({
type: 'wgs84',
altitude: false,
geocode: false,
highAccuracyExpireTime: 10000,
success: (res) => {
this.wgs84ToBd09(res.longitude, res.latitude, (bd09) => {
if (bd09 && bd09.lng && bd09.lat) {
// 只更新精度更好的位置
if (!this.state.currentLocation || res.accuracy < this.state.currentLocation.accuracy || res.accuracy < 20) {
this.state.currentLocation = {
lat: bd09.lat,
lng: bd09.lng,
accuracy: res.accuracy || 0
};
this.updateLocationMarker();
}
}
});
},
fail: (err) => {
console.error('uni-app GPS定位更新失败:', err);
}
});
}, 3000); // 每3秒更新一次给GPS更多时间
},
/**
* 使用uni-app定位GCJ02坐标
*/
startUniAppGeolocation() {
// 先获取一次当前位置
uni.getLocation({
type: 'gcj02', // 使用GCJ02坐标系火星坐标然后转换为BD09
altitude: false,
geocode: false,
highAccuracyExpireTime: 4000,
success: (res) => {
console.log('uni-app定位成功:', res.longitude, res.latitude, '精度:', res.accuracy);
// uni-app返回的是GCJ02坐标需要转换为BD09
this.gcj02ToBd09(res.longitude, res.latitude, (bd09) => {
if (bd09 && bd09.lng && bd09.lat) {
this.state.currentLocation = {
lat: bd09.lat,
lng: bd09.lng,
accuracy: res.accuracy || 0
};
console.log('坐标转换完成 - BD09:', bd09.lng, bd09.lat);
this.updateLocationMarker();
} else {
console.error('坐标转换失败,使用备用方案');
// 如果转换失败,尝试使用百度地图定位
if (typeof BMapGL !== 'undefined' && BMapGL.Geolocation) {
this.startBaiduGeolocation();
} else {
this.startBrowserGeolocation();
}
}
});
},
fail: (err) => {
console.error('uni-app定位失败:', err);
// 降级到百度地图定位或浏览器定位
if (typeof BMapGL !== 'undefined' && BMapGL.Geolocation) {
this.startBaiduGeolocation();
} else {
this.startBrowserGeolocation();
}
}
});
// 持续监听位置变化
this.state.watchLocationTimer = setInterval(() => {
uni.getLocation({
type: 'gcj02',
altitude: false,
geocode: false,
highAccuracyExpireTime: 4000,
success: (res) => {
this.gcj02ToBd09(res.longitude, res.latitude, (bd09) => {
if (bd09 && bd09.lng && bd09.lat) {
// 只更新精度更好的位置
if (!this.state.currentLocation || res.accuracy < this.state.currentLocation.accuracy || res.accuracy < 50) {
this.state.currentLocation = {
lat: bd09.lat,
lng: bd09.lng,
accuracy: res.accuracy || 0
};
this.updateLocationMarker();
}
}
});
},
fail: (err) => {
console.error('uni-app定位更新失败:', err);
}
});
}, 2000); // 每2秒更新一次位置
},
/**
* 使用5+定位
*/
startPlusGeolocation() {
const geolocation = plus.geolocation;
const options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
};
// 获取当前位置
geolocation.getCurrentPosition(
(position) => {
console.log('5+定位成功:', position);
// 5+返回的是WGS84坐标需要转换为BD09
this.wgs84ToBd09(position.coords.longitude, position.coords.latitude, (bd09) => {
this.state.currentLocation = {
lat: bd09.lat,
lng: bd09.lng,
accuracy: position.coords.accuracy || 0
};
this.updateLocationMarker();
});
},
(error) => {
console.error('5+定位失败:', error);
this.startBrowserGeolocation();
},
options
);
// 持续监听位置变化
this.state.watchPositionId = geolocation.watchPosition(
(position) => {
this.wgs84ToBd09(position.coords.longitude, position.coords.latitude, (bd09) => {
this.state.currentLocation = {
lat: bd09.lat,
lng: bd09.lng,
accuracy: position.coords.accuracy || 0
};
this.updateLocationMarker();
});
},
(error) => {
console.error('5+定位监听错误:', error);
},
options
);
},
/**
* 使用浏览器定位
*/
startBrowserGeolocation() {
if (!navigator.geolocation) {
console.error('浏览器不支持定位');
return;
}
const options = {
enableHighAccuracy: true, // 高精度定位使用GPS
timeout: 20000, // 增加超时时间到20秒确保获取高精度定位
maximumAge: 0 // 不使用缓存,始终获取最新位置
};
console.log('开始浏览器定位,选项:', options);
// 先获取一次当前位置
navigator.geolocation.getCurrentPosition(
(position) => this.updateLocation(position),
(error) => this.handleLocationError(error),
(position) => {
console.log('获取到初始位置:', position.coords);
this.updateLocation(position);
},
(error) => {
console.error('获取初始位置失败:', error);
this.handleLocationError(error);
},
options
);
// 持续监听位置变化
this.state.watchPositionId = navigator.geolocation.watchPosition(
(position) => this.updateLocation(position),
(error) => this.handleLocationError(error),
(position) => {
console.log('位置更新:', position.coords);
this.updateLocation(position);
},
(error) => {
console.error('位置监听错误:', error);
this.handleLocationError(error);
},
options
);
},
/**
* GCJ02坐标转BD09坐标百度坐标
*/
gcj02ToBd09(gcj_lng, gcj_lat, callback) {
const ak = 'iqyZkSZPurf61MhFV7hesbDukHdMBEEb';
// 使用6位小数精度百度API推荐精度
const coords = `${Number(gcj_lng).toFixed(6)},${Number(gcj_lat).toFixed(6)}`;
const url = `https://api.map.baidu.com/geoconv/v1/?coords=${coords}&from=3&to=5&ak=${ak}`;
console.log('GCJ02转BD09 - 输入:', gcj_lng, gcj_lat);
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.timeout = 10000; // 10秒超时
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
if (response.status === 0 && response.result && response.result.length > 0) {
const point = response.result[0];
const result = {
lng: Number(point.x),
lat: Number(point.y)
};
console.log('GCJ02转BD09成功:', result.lng, result.lat);
if (callback) callback(result);
return;
}
} catch (e) {
console.error('GCJ02转BD09解析失败:', e);
}
}
// API失败使用算法转换
console.warn('GCJ02转BD09 API失败使用算法转换');
const result = this.gcj02ToBd09Fallback(gcj_lng, gcj_lat);
if (callback) callback(result);
}
};
xhr.onerror = () => {
console.warn('GCJ02转BD09网络错误使用算法转换');
const result = this.gcj02ToBd09Fallback(gcj_lng, gcj_lat);
if (callback) callback(result);
};
xhr.ontimeout = () => {
console.warn('GCJ02转BD09超时使用算法转换');
const result = this.gcj02ToBd09Fallback(gcj_lng, gcj_lat);
if (callback) callback(result);
};
xhr.send();
},
/**
* GCJ02转BD09算法
*/
gcj02ToBd09Fallback(gcj_lng, gcj_lat) {
const x_PI = 3.14159265358979324 * 3000.0 / 180.0;
let z = Math.sqrt(gcj_lng * gcj_lng + gcj_lat * gcj_lat) + 0.00002 * Math.sin(gcj_lat * x_PI);
let theta = Math.atan2(gcj_lat, gcj_lng) + 0.000003 * Math.cos(gcj_lng * x_PI);
let bd_lng = z * Math.cos(theta) + 0.0065;
let bd_lat = z * Math.sin(theta) + 0.006;
return { lng: bd_lng, lat: bd_lat };
},
/**
* WGS84坐标转BD09坐标优先使用百度地图Web API最准确
*/
@ -609,43 +1076,73 @@
*/
wgs84ToBd09WebAPI(wgs_lng, wgs_lat, callback) {
const ak = 'iqyZkSZPurf61MhFV7hesbDukHdMBEEb'; // 百度地图AK
const coords = `${wgs_lng},${wgs_lat}`;
// 使用6位小数精度百度API推荐精度
const coords = `${Number(wgs_lng).toFixed(6)},${Number(wgs_lat).toFixed(6)}`;
const url = `https://api.map.baidu.com/geoconv/v1/?coords=${coords}&from=1&to=5&ak=${ak}`;
console.log('调用坐标转换API - WGS84:', wgs_lng, wgs_lat, 'URL:', url);
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.timeout = 5000;
xhr.timeout = 10000; // 10秒超时
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
const responseText = xhr.responseText;
console.log('坐标转换API原始响应:', responseText);
const response = JSON.parse(responseText);
if (response.status === 0 && response.result && response.result.length > 0) {
const point = response.result[0];
const result = { lng: point.x, lat: point.y };
// 百度API返回x=经度y=纬度
const result = {
lng: Number(point.x),
lat: Number(point.y)
};
// 验证转换结果的有效性
if (isNaN(result.lng) || isNaN(result.lat) ||
result.lng === 0 || result.lat === 0 ||
Math.abs(result.lng) > 180 || Math.abs(result.lat) > 90) {
console.error('坐标转换结果无效:', result, '原始响应:', response);
const fallback = this.wgs84ToBd09Fallback(wgs_lng, wgs_lat);
console.warn('使用备用算法:', fallback);
if (callback) callback(fallback);
return;
}
// 计算偏移距离(用于调试)
const offsetLng = result.lng - wgs_lng;
const offsetLat = result.lat - wgs_lat;
console.log('Web API转换成功 - WGS84:', wgs_lng, wgs_lat, '-> BD09:', result.lng, result.lat);
console.log('坐标偏移:', '经度:', offsetLng.toFixed(6), '纬度:', offsetLat.toFixed(6));
if (callback) callback(result);
return;
} else {
console.warn('Web API返回错误:', response);
console.error('Web API返回错误 - 状态码:', response.status, '错误信息:', response.message || JSON.stringify(response));
}
} catch (e) {
console.warn('Web API解析失败:', e);
console.error('Web API解析失败:', e, '响应文本:', xhr.responseText);
}
} else {
console.error('Web API请求失败 - HTTP状态码:', xhr.status, '响应:', xhr.responseText);
}
// API调用失败使用备用算法
console.warn('坐标转换API失败使用备用算法');
const result = this.wgs84ToBd09Fallback(wgs_lng, wgs_lat);
console.log('使用备用算法转换 - WGS84:', wgs_lng, wgs_lat, '-> BD09:', result.lng, result.lat);
console.log('备用算法转换结果 - WGS84:', wgs_lng, wgs_lat, '-> BD09:', result.lng, result.lat);
if (callback) callback(result);
}
};
xhr.onerror = () => {
console.warn('Web API网络错误使用备用算法');
console.error('Web API网络错误');
const result = this.wgs84ToBd09Fallback(wgs_lng, wgs_lat);
if (callback) callback(result);
};
xhr.ontimeout = () => {
console.warn('Web API超时使用备用算法');
console.error('Web API请求超时');
const result = this.wgs84ToBd09Fallback(wgs_lng, wgs_lat);
if (callback) callback(result);
};
@ -750,8 +1247,14 @@
* 更新定位标记
*/
updateLocationMarker() {
if (!this.map || !this.state.currentLocation) {
console.warn('无法更新定位标记:地图或位置信息缺失');
// 确保地图已加载完成且有位置信息
if (!this.map || !this.state.mapLoaded) {
console.warn('无法更新定位标记:地图未加载完成');
return;
}
if (!this.state.currentLocation) {
console.warn('无法更新定位标记:位置信息缺失');
return;
}
@ -781,8 +1284,8 @@
* 回到平板当前位置
*/
centerToLocation() {
if (!this.map) {
console.warn('地图未初始化');
if (!this.map || !this.state.mapLoaded) {
console.warn('地图未加载完成');
return;
}
@ -1021,9 +1524,24 @@
* 停止定位跟踪
*/
stopLocationTracking() {
// 停止定位定时器包括uni-app和百度地图
if (this.state.watchLocationTimer !== null) {
clearInterval(this.state.watchLocationTimer);
this.state.watchLocationTimer = null;
}
// 清理百度地图定位实例
if (this.baiduGeolocation) {
this.baiduGeolocation = null;
}
// 停止位置监听
if (this.state.watchPositionId !== null) {
navigator.geolocation.clearWatch(this.state.watchPositionId);
if (navigator.geolocation) {
navigator.geolocation.clearWatch(this.state.watchPositionId);
} else if (typeof plus !== 'undefined' && plus.geolocation) {
plus.geolocation.clearWatch(this.state.watchPositionId);
}
this.state.watchPositionId = null;
}
@ -1034,7 +1552,9 @@
}
// 移除方向事件监听
window.removeEventListener('deviceorientation', this.handleOrientation);
if (this.handleOrientation) {
window.removeEventListener('deviceorientation', this.handleOrientation);
}
// 移除定位标记
if (this.overlays.locationMarker && this.map) {