百度地图修改
This commit is contained in:
parent
b332137dc3
commit
eef16b07ae
Binary file not shown.
|
After Width: | Height: | Size: 989 B |
|
|
@ -168,6 +168,24 @@
|
|||
background: rgba(0, 45, 182, 1);
|
||||
}
|
||||
|
||||
/* 回到定位按钮 */
|
||||
.location-center-btn {
|
||||
position: fixed; bottom: 20px; right: 20px;
|
||||
width: 32px; height: 32px;
|
||||
background: rgba(255, 255, 255, 0.95) url('./image/position.png') center center / 70% no-repeat;
|
||||
border-radius: 50%; display: flex; align-items: center; justify-content: center;
|
||||
cursor: pointer; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 998; pointer-events: auto;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.location-center-btn:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.location-center-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* 地图 Label 样式 - 提取至 CSS */
|
||||
.map-project-label {
|
||||
color: #002db6 !important;
|
||||
|
|
@ -230,6 +248,9 @@
|
|||
<div class="model-preview-close" id="close-preview-btn"></div>
|
||||
<div class="model-preview-ar" id="ar-btn">AR</div>
|
||||
</div>
|
||||
|
||||
<!-- 回到定位按钮 -->
|
||||
<div class="location-center-btn" id="location-center-btn" title="回到当前位置"></div>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
|
@ -358,14 +379,19 @@
|
|||
map: null,
|
||||
overlays: {
|
||||
markers: [],
|
||||
models: []
|
||||
models: [],
|
||||
locationMarker: null
|
||||
},
|
||||
state: {
|
||||
projectInfo: [],
|
||||
currentClickedProject: null,
|
||||
modelList: [],
|
||||
checkedNodeIds: [],
|
||||
selectedProjectId: null
|
||||
selectedProjectId: null,
|
||||
currentLocation: null,
|
||||
currentHeading: 0,
|
||||
watchPositionId: null,
|
||||
watchOrientationId: null
|
||||
},
|
||||
elements: {
|
||||
panel: null,
|
||||
|
|
@ -393,6 +419,9 @@
|
|||
// 渲染工程列表
|
||||
this.renderProjectList();
|
||||
|
||||
// 初始化定位功能
|
||||
this.initLocationTracking();
|
||||
|
||||
// 处理 URL Action
|
||||
this.handleUrlActions(params);
|
||||
},
|
||||
|
|
@ -405,6 +434,7 @@
|
|||
this.elements.selectAllBtn = document.getElementById('select-all-btn');
|
||||
this.elements.deselectAllBtn = document.getElementById('deselect-all-btn');
|
||||
this.elements.arBtn = document.getElementById('ar-btn');
|
||||
this.elements.locationCenterBtn = document.getElementById('location-center-btn');
|
||||
},
|
||||
|
||||
bindEvents() {
|
||||
|
|
@ -427,6 +457,14 @@
|
|||
this.elements.deselectAllBtn.addEventListener('click', () => this.deselectAllNodes());
|
||||
}
|
||||
|
||||
// 回到定位按钮
|
||||
if (this.elements.locationCenterBtn) {
|
||||
this.elements.locationCenterBtn.addEventListener('click', () => this.centerToLocation());
|
||||
}
|
||||
|
||||
// 页面卸载时清理定位监听
|
||||
window.addEventListener('beforeunload', () => this.stopLocationTracking());
|
||||
|
||||
// 监听 postMessage
|
||||
window.addEventListener('message', (e) => {
|
||||
const data = e.data;
|
||||
|
|
@ -454,6 +492,344 @@
|
|||
projectInfo.forEach(p => this.addProjectMarker(p));
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化定位跟踪
|
||||
*/
|
||||
initLocationTracking() {
|
||||
// 检查浏览器是否支持定位
|
||||
if (!navigator.geolocation) {
|
||||
console.warn('浏览器不支持地理定位');
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建定位标记图标(带方向的箭头)
|
||||
this.createLocationIcon();
|
||||
|
||||
// 开始监听位置变化
|
||||
this.startWatchingPosition();
|
||||
|
||||
// 开始监听设备方向变化
|
||||
this.startWatchingOrientation();
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建定位标记图标
|
||||
*/
|
||||
createLocationIcon() {
|
||||
// 创建一个带方向的箭头图标
|
||||
// 使用 Canvas 绘制一个圆形标记和方向箭头
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 40;
|
||||
canvas.height = 40;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 绘制圆形背景
|
||||
ctx.fillStyle = '#3388ff';
|
||||
ctx.beginPath();
|
||||
ctx.arc(20, 20, 15, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// 绘制白色边框
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.beginPath();
|
||||
ctx.arc(20, 20, 15, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
|
||||
// 绘制方向箭头(默认向上)
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(20, 5);
|
||||
ctx.lineTo(15, 15);
|
||||
ctx.lineTo(25, 15);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// 转换为图片URL
|
||||
this.locationIconUrl = canvas.toDataURL();
|
||||
},
|
||||
|
||||
/**
|
||||
* 开始监听位置变化
|
||||
*/
|
||||
startWatchingPosition() {
|
||||
const options = {
|
||||
enableHighAccuracy: true, // 高精度定位
|
||||
timeout: 10000,
|
||||
maximumAge: 0 // 不使用缓存
|
||||
};
|
||||
|
||||
// 先获取一次当前位置
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => this.updateLocation(position),
|
||||
(error) => this.handleLocationError(error),
|
||||
options
|
||||
);
|
||||
|
||||
// 持续监听位置变化
|
||||
this.state.watchPositionId = navigator.geolocation.watchPosition(
|
||||
(position) => this.updateLocation(position),
|
||||
(error) => this.handleLocationError(error),
|
||||
options
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新位置
|
||||
*/
|
||||
updateLocation(position) {
|
||||
const coords = position.coords || position;
|
||||
const { latitude, longitude, heading, accuracy } = coords;
|
||||
|
||||
if (!latitude || !longitude) return;
|
||||
|
||||
// 将WGS84坐标转换为百度坐标
|
||||
const point = new BMapGL.Point(longitude, latitude);
|
||||
|
||||
// 使用百度地图的坐标转换(如果需要)
|
||||
// 注意:BMapGL.Point 可以直接使用WGS84坐标,但为了更准确,建议转换
|
||||
// 这里先直接使用,如果发现位置偏移,再添加坐标转换
|
||||
|
||||
// 保存当前位置(使用原始坐标,转换在显示时处理)
|
||||
this.state.currentLocation = {
|
||||
lat: latitude,
|
||||
lng: longitude,
|
||||
accuracy: accuracy || 0
|
||||
};
|
||||
|
||||
// 如果有方向信息,更新方向
|
||||
if (heading !== null && heading !== undefined) {
|
||||
this.state.currentHeading = heading;
|
||||
}
|
||||
|
||||
// 更新地图上的标记
|
||||
this.updateLocationMarker();
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新定位标记
|
||||
*/
|
||||
updateLocationMarker() {
|
||||
if (!this.map || !this.state.currentLocation) return;
|
||||
|
||||
const { lng, lat } = this.state.currentLocation;
|
||||
|
||||
// 创建百度地图点(百度地图会自动处理坐标转换)
|
||||
const point = new BMapGL.Point(lng, lat);
|
||||
|
||||
// 创建带方向的图标
|
||||
const icon = this.createRotatedLocationIcon(this.state.currentHeading);
|
||||
|
||||
// 如果标记已存在,更新位置和图标
|
||||
if (this.overlays.locationMarker) {
|
||||
this.map.removeOverlay(this.overlays.locationMarker);
|
||||
}
|
||||
|
||||
// 创建新标记
|
||||
this.overlays.locationMarker = new BMapGL.Marker(point, { icon });
|
||||
this.map.addOverlay(this.overlays.locationMarker);
|
||||
|
||||
// 可选:自动跟随定位(取消注释以下代码以启用)
|
||||
// this.map.setCenter(point);
|
||||
},
|
||||
|
||||
/**
|
||||
* 回到平板当前位置
|
||||
*/
|
||||
centerToLocation() {
|
||||
if (!this.map) {
|
||||
console.warn('地图未初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有当前位置,直接定位
|
||||
if (this.state.currentLocation) {
|
||||
const { lng, lat } = this.state.currentLocation;
|
||||
const point = new BMapGL.Point(lng, lat);
|
||||
this.map.centerAndZoom(point, 18); // 使用较大的缩放级别以便看清当前位置
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有当前位置,尝试获取一次
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
const { latitude, longitude } = position.coords;
|
||||
const point = new BMapGL.Point(longitude, latitude);
|
||||
this.map.centerAndZoom(point, 18);
|
||||
|
||||
// 更新当前位置
|
||||
this.state.currentLocation = {
|
||||
lat: latitude,
|
||||
lng: longitude,
|
||||
accuracy: position.coords.accuracy || 0
|
||||
};
|
||||
|
||||
// 更新标记
|
||||
this.updateLocationMarker();
|
||||
},
|
||||
(error) => {
|
||||
console.warn('获取当前位置失败:', error);
|
||||
alert('无法获取当前位置,请检查定位权限设置');
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10000,
|
||||
maximumAge: 0
|
||||
}
|
||||
);
|
||||
} else {
|
||||
alert('浏览器不支持定位功能');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建旋转后的定位图标
|
||||
*/
|
||||
createRotatedLocationIcon(heading) {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 40;
|
||||
canvas.height = 40;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 保存上下文
|
||||
ctx.save();
|
||||
|
||||
// 移动到中心点
|
||||
ctx.translate(20, 20);
|
||||
|
||||
// 旋转画布(heading是相对于正北的角度,需要转换为相对于画布的角度)
|
||||
// 百度地图中,heading是相对于正北的角度(0-360),顺时针为正
|
||||
// 画布中,0度是向右,需要转换
|
||||
const rotation = (heading - 90) * Math.PI / 180; // 转换为弧度并调整方向
|
||||
ctx.rotate(rotation);
|
||||
|
||||
// 绘制圆形背景
|
||||
ctx.fillStyle = '#3388ff';
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, 15, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// 绘制白色边框
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, 15, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
|
||||
// 绘制方向箭头(向上)
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, -15);
|
||||
ctx.lineTo(-8, -5);
|
||||
ctx.lineTo(8, -5);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// 恢复上下文
|
||||
ctx.restore();
|
||||
|
||||
// 转换为图片URL
|
||||
const iconUrl = canvas.toDataURL();
|
||||
return new BMapGL.Icon(iconUrl, new BMapGL.Size(40, 40), {
|
||||
anchor: new BMapGL.Size(20, 20)
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 开始监听设备方向变化
|
||||
*/
|
||||
startWatchingOrientation() {
|
||||
// 绑定方法,确保在事件监听器中能正确访问 this
|
||||
this.handleOrientation = this.handleOrientation.bind(this);
|
||||
|
||||
// 检查是否支持 DeviceOrientationEvent
|
||||
if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {
|
||||
// iOS 13+ 需要请求权限
|
||||
DeviceOrientationEvent.requestPermission()
|
||||
.then(response => {
|
||||
if (response === 'granted') {
|
||||
window.addEventListener('deviceorientation', this.handleOrientation);
|
||||
}
|
||||
})
|
||||
.catch(console.error);
|
||||
} else if (window.DeviceOrientationEvent) {
|
||||
// 其他设备直接监听
|
||||
window.addEventListener('deviceorientation', this.handleOrientation);
|
||||
} else {
|
||||
// 如果不支持,尝试使用 Compass API(uni-app)
|
||||
if (typeof plus !== 'undefined' && plus.compass) {
|
||||
this.state.watchOrientationId = plus.compass.watchHeading(
|
||||
(heading) => {
|
||||
this.state.currentHeading = heading.magneticHeading;
|
||||
this.updateLocationMarker();
|
||||
},
|
||||
(error) => console.error('获取方向失败:', error),
|
||||
{ frequency: 100 }
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理设备方向变化
|
||||
*/
|
||||
handleOrientation(event) {
|
||||
// alpha: 绕Z轴旋转(指南针方向,0-360度)
|
||||
if (event.alpha !== null && event.alpha !== undefined) {
|
||||
this.state.currentHeading = event.alpha;
|
||||
this.updateLocationMarker();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理定位错误
|
||||
*/
|
||||
handleLocationError(error) {
|
||||
let message = '定位失败: ';
|
||||
switch(error.code) {
|
||||
case error.PERMISSION_DENIED:
|
||||
message += '用户拒绝了定位请求';
|
||||
break;
|
||||
case error.POSITION_UNAVAILABLE:
|
||||
message += '位置信息不可用';
|
||||
break;
|
||||
case error.TIMEOUT:
|
||||
message += '定位请求超时';
|
||||
break;
|
||||
default:
|
||||
message += '未知错误';
|
||||
break;
|
||||
}
|
||||
console.warn(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* 停止定位跟踪
|
||||
*/
|
||||
stopLocationTracking() {
|
||||
// 停止位置监听
|
||||
if (this.state.watchPositionId !== null) {
|
||||
navigator.geolocation.clearWatch(this.state.watchPositionId);
|
||||
this.state.watchPositionId = null;
|
||||
}
|
||||
|
||||
// 停止方向监听
|
||||
if (typeof plus !== 'undefined' && plus.compass && this.state.watchOrientationId !== null) {
|
||||
plus.compass.clearWatch(this.state.watchOrientationId);
|
||||
this.state.watchOrientationId = null;
|
||||
}
|
||||
|
||||
// 移除方向事件监听
|
||||
window.removeEventListener('deviceorientation', this.handleOrientation);
|
||||
|
||||
// 移除定位标记
|
||||
if (this.overlays.locationMarker && this.map) {
|
||||
this.map.removeOverlay(this.overlays.locationMarker);
|
||||
this.overlays.locationMarker = null;
|
||||
}
|
||||
},
|
||||
|
||||
addProjectMarker(info) {
|
||||
if (!info.lng || !info.lat) return;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue