import util from "@/common/util.js";
import conf from "@/common/config.js"
export default {
data() {
return {
mapCtx: null,
// 地图中心
mapCenter: {
longitude: 117.4897043557885,
latitude: 30.08812622949965,
},
// 地图边界,这里使用矩形边界
bounds: {
northEast: {
latitude: 30.0927032267595,
longitude: 117.495632609787
},
southWest: {
latitude: 30.0835492322398,
longitude: 117.48377610179
}
},
// 我的位置
myLocation: {
longitude: 0,
latitude: 0,
},
scale: 17, // 初始缩放级别
minScale: 17, // 最小缩放级别
maxScale: 20, // 最大缩放级别
tileSize: 256, // 瓦片图分辨率,通常为256x256像素
tileCache: [], // 缓存需要加载的瓦片图 URL
showLocation: false, // 显示当前定位
enablePoi: false, // 是否展示 POI 点
markerInfo: {}, //当前选择基础设施
markers: [], // 地图标注集合
linePoints: [], // 路线点集
gridSize: 30, // 聚合算法的可聚合距离,即距离小于该值的点会聚合至一起,以像素为单位
scenicLimit: 10, //景区范围阈值
spotLimit: 10, //景区范围阈值
isAutoGuide: false, //开启导游
}
},
computed: {
markerIds() {
return this.markers.map(v => v.id)
},
polyline() {
return [{
color: '#61afef',
width: 10,
points: this.linePoints
}]
},
showLines() {
return this.linePoints.length
}
},
methods: {
initMap() {
this.mapCtx = uni.createMapContext('customMap')
// 开启点聚合
this.mapCtx.initMarkerCluster({
gridSize: this.gridSize
})
// 加载手绘地图
this.loadTileMap(this.scale)
},
// 我的位置
setLocation(showLocation) {
uni.getLocation({
type: 'gcj02',
success: (res) => {
const {
latitude,
longitude
} = res;
// 计算当前位置是否在景区范围,在-显示我的位置并将地图中心点修改我的位置,不在-只显示我的位置
const distance = util.GetDistance(longitude, latitude, this.mapCenter.longitude, this.mapCenter
.latitude);
this.myLocation.longitude = longitude
this.myLocation.latitude = latitude
if (distance < this.scenicLimit) {
this.mapCenter.longitude = longitude
this.mapCenter.latitude = latitude
} else {
this.showToast('您当前不在景区范围内!')
}
}
});
if (showLocation) {
this.showLocation = false
} else {
this.showLocation = true
}
},
onRegionChange(e) {
if (e.type === 'end') {
const scale = Math.round(e.detail.scale)
setTimeout(() => {
this.loadTileMap(scale)
}, 300);
// 边界限制
this.checkMapBounds(e.detail.centerLocation)
}
},
// 地图边界限制
checkMapBounds(center) {
const {
latitude,
longitude
} = center;
// 处理逻辑
// 检查地图中心是否超出边界
if (
latitude < this.bounds.southWest.latitude ||
latitude > this.bounds.northEast.latitude ||
longitude < this.bounds.southWest.longitude ||
longitude > this.bounds.northEast.longitude
) {
console.log(latitude+','+longitude,'-------',this.mapCenter.latitude+','+this.mapCenter.longitude)
// 如果超出边界,将地图中心移动到原中心
this.mapCtx.moveToLocation({
latitude: this.mapCenter.latitude,
longitude: this.mapCenter.longitude,
success: () => {},
fail: (err) => {}
});
}
},
loadTileMap(scale) {
this.mapCtx.getRegion({
success: (res) => {
const {
northeast,
southwest
} = res;
// 计算需要加载的瓦片图行列号范围
const minX = this.lngToTileX(southwest.longitude, scale);
const maxX = this.lngToTileX(northeast.longitude, scale);
const minY = this.latToTileY(northeast.latitude, scale);
const maxY = this.latToTileY(southwest.latitude, scale);
const tileUrls = [];
for (let x = minX; x <= maxX; x++) {
for (let y = minY; y <= maxY; y++) {
const bounds = this.getTileBounds(x, y, scale)
// 这里需要替换为实际的瓦片图 URL 模板
const url =
`${conf.mapurl}/${scale}/${x}_${y}.png`;
tileUrls.push({
url,
bounds,
id: Date.now()
});
}
}
// 加载并显示瓦片图
this.loadAndDrawTiles(tileUrls);
},
fail: (err) => {
console.error('获取地图范围失败:', err);
}
});
},
// 经度转列号
lngToTileX(lng, zoom) {
return Math.floor((lng + 180) / 360 * Math.pow(2, zoom));
},
// 纬度转行号
latToTileY(lat, zoom) {
const latRad = lat * Math.PI / 180;
return Math.floor((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * Math.pow(2,
zoom));
},
// 获取瓦片图边界
getTileBounds(tileX, tileY, zoom) {
const {
tileSize
} = this;
// 计算当前瓦片在地图中的像素坐标
const xPixel = tileX * tileSize;
const yPixel = tileY * tileSize;
// 计算地图左上角和右下角的像素坐标
const left = xPixel;
const top = yPixel;
const right = xPixel + tileSize;
const bottom = yPixel + tileSize;
// 将像素坐标转换为经纬度坐标
const nw = this.pixelToLatLng(left, top, zoom);
const se = this.pixelToLatLng(right, bottom, zoom);
return {
southwest: {
longitude: nw.lng,
latitude: se.lat
},
northeast: {
longitude: se.lng,
latitude: nw.lat
}
};
},
// 像素坐标转经纬度坐标
pixelToLatLng(x, y, zoom) {
const n = Math.PI - (2 * Math.PI * y) / Math.pow(2, zoom + 8);
return {
lat: (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))),
lng: (x / Math.pow(2, zoom + 8)) * 360 - 180
};
},
// 瓦片地图加载
loadAndDrawTiles(tileUrls) {
console.log(tileUrls,'tileUrls')
const cache = this.tileCache.slice(0)
if (cache && cache.length > 0) {
tileUrls.forEach((mp) => {
this.mapCtx.removeGroundOverlay({
id: mp.id,
success: (res) => {},
fail: (res) => {},
})
})
}
this.tileCache = []
tileUrls.forEach((mp) => {
this.mapCtx.addGroundOverlay({
id: mp.id,
src: mp.url,
bounds: mp.bounds,
zIndex: 9,
success: (res) => {console.log(res,'success')},
fail: (res) => {console.log(res,'fail')},
complete: () => {
this.tileCache.push(mp)
}
});
})
},
setMarkers(points, mapIcon) {
this.markers = []
if (points && points.length > 0) {
setTimeout(() => {
const ps = [...points]
ps.forEach((p, i) => {
const [longitude, latitude] = util.bMapToQQMap(p.lon, p.lat);
this.markers.push(
Object.assign({}, {
id: Number(p.id),
iconPath: mapIcon,
width: 36,
height: 43,
joinCluster: true, // 指定了该参数才会参与聚合
label: {
fontSize: 10,
padding: 5,
borderWidth: 1,
borderRadius: 10,
textAlign: 'center',
bgColor: '#ffffff',
content: p.title
},
longitude,
latitude,
info: p
})
)
})
this.setIncludePoints()
}, 300)
}
},
//
setIncludePoints() {
// 收集所有 markers 的经纬度
let points = this.markers.map(marker => {
return {
latitude: marker.latitude,
longitude: marker.longitude
}
});
// 边界点
// points.push(this.bounds.northEast)
// points.push(this.bounds.southWest)
this.mapCtx.includePoints({
points: points,
success: (res) => {
console.log('所有 markers 已居中显示', res);
},
fail: (err) => {
console.error('居中显示 markers 失败:', err);
}
});
},
// 路线标记
setPolyline(points) {
if (points.length > 0) {
const ps = [...points]
this.linePoints = ps.map((p, i) => {
const {
lon,
lat
} = p
const [longitude, latitude] = util.bMapToQQMap(p.lon, p.lat);
return {
longitude,
latitude,
}
})
}
},
// 点击标注
clickMarker(e) {
const target = this.markers.find(v => v.id == e.markerId)
this.markerInfo = target ? target.info : {};
this.openPopup('markerPopup')
},
// 开启导游(边走边听)
handleGuide(isAutoGuide) {
const _this = this
if (!isAutoGuide) {
uni.showModal({
title: '提示',
content: '启动后,小程序会在接近景点时,自动进行讲解!',
success: function(res) {
if (res.confirm) {
// 开启
_this.isAutoGuide = true
uni.authorize({
scope: 'scope.userLocation',
success: () => {
// 授权成功,开启实时位置更新
uni.startLocationUpdate({
success: () => {
console.log('开启位置更新成功,开始记录行程');
uni.onLocationChange(_this.checkSpotLimit)
},
fail: (err) => {
console.error('开启位置更新失败:', err);
},
});
},
fail: (err) => {
console.error('获取地理位置授权失败:', err);
}
});
}
}
});
} else {
uni.showModal({
title: '提示',
content: '关闭自动导游!',
success: function(res) {
if (res.confirm) {
// 关闭
_this.isAutoGuide = false
uni.authorize({
scope: 'scope.userLocation',
success: () => {
// 授权成功,关闭实时位置更新
uni.stopLocationUpdate({
success: () => {
console.log('关闭位置更新成功');
},
fail: (err) => {
console.error('关闭位置更新失败:', err);
},
complete: () => {
_this.stopAudio()
uni.offLocationChange(_this.checkSpotLimit)
}
});
},
fail: (err) => {
console.error('获取地理位置授权失败:', err);
}
});
}
},
})
}
},
// 计算当前位置是否在景点范围内
checkSpotLimit(res) {
console.log(res, '实时位置信息')
const {
longitude,
latitude
} = res
if (this.spotList && this.spotList.length > 0) {
const newSpotList = this.spotList.map((p) => {
p.distance = util.GetDistance(longitude, latitude, p.lon, p.lat);
return p
})
// 按distance进行升序排列
newSpotList.sort(function(a, b) {
return a.distance - b.distance
})
const sd = newSpotList[0]
if (sd.distance <= this.spotLimit) {
// 播报
this.audioPlay(sd, sd['chineseVoice'])
}
}
}
}
}

真机调试以后发现这个方法直接失败了,这个是因为什么啊,也没有报错信息,就直接进了失败的回调,也没有报错信息