以下所有代码在vue3项目中所调试的,如果是其它框架或者原生,稍微修改即可
// 初始化,
import mapboxgl, { Map, MapMouseEvent, Point } from 'mapbox-gl';
mapboxgl.accessToken='pk.eyJ1Ijoic3o2NjY2NjYiLCJhIjoiY2tuam44NXZzMDEwMzJ1cGV3djR6OHA5cCJ9.2LA3YOPHRLTTB25CvAoIdw';
const init = ()=>{
map = new mapboxgl.Map({
container:mapRef.value, // 容器div
// style: 'mapbox://styles/mapbox/satellite-streets-v11',
center: [120.20821745140512, 30.301670444054523],
zoom: 14, // 地图起始比列
maxZoom: 17,
})
}
点
// 添加数据源
map.addSource('pointSource', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features:[
{
type:"Feature",
geometry:{
type:'Point',
coordinates:[-122.486052, 37.830348]
},
properties:{
color:'red',
}
}
]
}
});
// 添加图层
map.addLayer({
id:'pointSource',
type:'circle', // 这里如果是添加图片的话改为symbol
source:'pointSource',
paint:{
'circle-radius':6,
}
})
线
// 添加数据源
map.addSource('lineSource', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features:[
{
type:"Feature",
geometry:{
type:'LineString',
coordinates: [
[-122.486052, 37.830348],
[-122.456052, 37.810348]
]
},
properties:{
color:'red',
}
}
]
}
});
// 添加图层
map.addLayer({
id:'lineSource',
type:'line', // 这里如果是添加图片的话改为symbol
source:'lineSource',
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
"line-color": [ // 动态线色
"match",
["get", "stage"], // 获取 stage 字段的值
"0",
"red", // 当 stage 为 0 时,线的颜色为蓝色
"1",
"blue", // 当 stage 为 1 时,线的颜色为红色
"gray", // 默认颜色,如果 stage 不是 0 或 1,则使用灰色
],
"line-width": [ // 动态线宽
"case",
["==", ["get", "stage"], "0"],
3,
["==", ["get", "stage"], "1"],
2,
4,
],
}
})
//--------------------------------------------------------------
// 渐变线
map.addSource("track-source", {
type: "geojson",
lineMetrics: true, // 需要在数据源中开启这个属性
data: trackLine
});
// 在图层paint属性中
paint: {
"line-gradient": [
"interpolate",
["linear"],
["line-progress"],
0,
"blue",
0.1,
"royalblue",
0.3,
"cyan",
0.5,
"lime",
0.7,
"yellow",
1,
"red"
],
}
面
// 添加数据源
map.addSource('polygonsSource', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features:[
{
type:"Feature",
geometry:{
type:'Polygon',
coordinates: [[
[-122.486052, 37.830348],
[-122.466052, 37.820348],
[-122.456052, 37.810348],
[-122.486052, 37.830348]
]]
},
properties:{
color:'red',
}
}
]
}
});
// 添加图层
map.addLayer({
id:'polygonsSource',
type:'fill', // 这里如果是添加图片的话改为symbol
source:'polygonsSource',
paint: {
'fill-color': '#007cbf',
'fill-opacity': 0.4
}
})
地面垂直线
// 这里利用了turf.js将一个点转为圆
const radius = 500;
const center = [x,y];
const options: any = {
steps: 4,
units: 'centimeters', // 这里单位可以改
properties: { height: 300, color: 'red' }, // 这里自定义高度
};
const circle = turf.circle(center, radius, options); // 变为一个要素
// 处理要素,自行处理
features.push(circle)
// 数据源
map.addSource('vertifyLayer', {
type: 'geojson',
data: { //
type: 'FeatureCollection',
features: [],
},
});
// 图层
map.addLayer({
id: 'vertifyLayer',
type: 'fill-extrusion',
source: 'vertifyLayer',
paint: {
'fill-extrusion-color': ['get', 'color'], // 圆柱颜色
'fill-extrusion-height': ['get', 'height'], // 动态获取每个要素的高度
'fill-extrusion-base': 0, // 三维填充的底部高度
'fill-extrusion-opacity': 0.6, // 三维填充的不透明度(可选,取值范围为 0 ~ 1,默认值为 1)
},
});
修改数据源
// vertifyLayer 为数据源的id
map.getSource('vertifyLayer').setData({
type: 'FeatureCollection',
features: [],
});
地图点击事件
map.on('click',(e)=>{ // 这个可以添加第二个参数,为需要点击的图层
console.log( [e.lngLat.lng, e.lngLat.lat] )
})
修改图层属性
map.setLayoutProperty(
`xxxx`, // 图层id
"visibility", //属性
"visible" // 需要设置的值
);
点击获取图层要素
map.on('click',(e)=>{
const features = map.queryRenderedFeatures(e.point); // 根据点击的经纬度获取要素
const feature = features[0];
const layerId = feature.layer.id; // 获取id
const properties = feature.properties; // 获取properties
})
// 也可以接收第二个参数
map.queryRenderedFeatures(e.point, {
layers: ["points"]
})
//获取指定位置上渲染的所有要素。
//限定查询范围为名为 "points" 的图层
//也可以是数据源id,为字符串'xxxx'
// --------------------------------------------------------------------------------
//完整如下,都为可选参数
map.queryRenderedFeatures(
[geometry],//一个包含 type 和 coordinates 属性的对象,用于指定查询范围的几何形状(Point、LineString、Polygon)
{
filter: [filterExpression], //一个数组,用于过滤查询结果
layers: [layerIDs],//一个字符串数组,用于指定要查询的图层 ID
maxFeatures: number,//一个数字,用于限制查询结果的最大数量
source: sourceID,// 一个字符串,用于指定要查询的数据源 ID
validate: boolean// 一个布尔值,用于控制是否对参数进行验证
}
)
获取图层对象数据源
// 返回指定 ID 为 'ccc' 的图层对象,如果该图层不存在则会返回 undefined。
map.getLayer('xxx')
// 获取数据源
map.getSource("points")._data
原生点击屏幕坐标转为经纬度
// div点击事件
const handleClick =(event)=>{
const bbox = [
[event.clientX, event.clientY],
[event.clientX + 5, event.clientY + 5], // 第二个暂时应该用不对
];
}
// 该方法用于将屏幕坐标系(以像素为单位)转换为地图坐标系(以经纬度为单位)
// 输入一个包含 x 和 y 属性的对象,表示屏幕坐标,输出一个 LngLat 对象,表示地图坐标。
let lngLat = map.unproject([event.clientX, event.clientY]);
// 该方法用于将地图坐标系(以经纬度为单位)转换为屏幕坐标系(以像素为单位)
// 输入一个 LngLat 对象,表示地图坐标,输出一个包含 x 和 y 属性的对象,表示屏幕坐标。
let points = map.project(lngLat)
// 根据点击的经纬度获取要素
const features = map.queryRenderedFeatures(points);
const feature = features[0];
原生鼠标滚轮事件调用地图滚动
// @wheel = "handleWheel"
const handleWheel =(event)=>{
event.stopPropagation();
}
// mapbox设置图层
map.zoomTo(map.getZoom() - event.deltaY * 0.01);
原生鼠标滑动事件调用地图滑动
//1. 给div绑定以下三个方法
@mousemove.stop="handleMouseMove" // 鼠标开始移动
@mousedown.stop="handleDragStart" // 鼠标移动结束
@mouseup.stop="handleDragEnd" // 鼠标松开
// 2. 需要一个值来判断鼠标是否按下松开,(mapbox移动地图逻辑是按下鼠标左键拖动地图,松开左键结束拖动)
let isDragging = false
let lastPointX, lastPointY; // 鼠标点击的经纬度
// 滑动事件
const handleMouseMove = (event)=>{
if (!isDragging){
// 说明没有点击,但是可以做些其它操作,这里我是做了鼠标悬浮操作
mouseent([event.clientX, event.clientY])
}else{
// 触发点击移动事件
const deltaMove = {
x: event.clientX - lastPointX,
y: event.clientY - lastPointY,
};
lastPointX = event.clientX;
lastPointY = event.clientY;
// 触发滑动事件
mouseFun(deltaMove)
}
}
// 鼠标按下事件
const handleDragStart = (event)=>{
isDragging = true;
lastPointX = event.clientX; // 赋值经纬度
lastPointY = event.clientY;
}
// 鼠标松开事件
const handleDragEnd = (event) => {
isDragging = false;
};
//------------------------------------------------------------------------------
// mapbox设置滑动
const mouseFun = (deltaMove)=>{
map.panBy([-deltaMove.x, -deltaMove.y], {
duration: 0,
});
}
//------------------------------------------------------------------------------
// 顺便说一下鼠标悬浮操作事件
let popup = new mapboxgl.Popup({ // 悬浮弹窗
closeButton: false,
closeOnClick: false,
});
const mouseent = (val)=>{
let lngLat = map.unproject([val[0], val[1]]);
let points = map.project(lngLat); // 先进行坐标转换
const features = map.queryRenderedFeatures(points); // 获取要素
const feature = features[0];
// 判断鼠标悬浮的该要素是否为真
if (feature) {
const layerId = feature.layer.id;
const properties = feature.properties; // 如果为真获取该要素的id以及properties
// 判断该id是否包含指定的图层id
if(properties.id && layerId.includes("point-layer1")){
// 自定义鼠标悬浮弹窗
popup
.setLngLat([lngLat.lng, lngLat.lat])
.addClassName("my-custom-popup")
.setHTML(`<div>${properties.name}</div>`)
.addTo(map);
}else{
popup.remove(); // 关闭悬浮弹窗
}
}
}
处理地图数据为url地址
// 比如接口返回为url,打开该url显示为mapbox需要的geojson数据
const url = `http://xxxx.xxxxx.xx`
fetch(url).then((response)=>response.json()).then((geojson)=>{
// 这里就能拿到正确的mapbox需要的geojson数据了
})
创建自定义组件的popup
let mountNode: any;
map.on('click','xxx',(x)=>{
// 创建该弹窗
createVideoPopUp(sdf)
// x,y为经纬度坐标,显示在地图上
new mapboxgl.Popup({ closeButton: false }).setLngLat(x,y).setDOMContent(mountNode).addTo(map);
})
// features可以为传递的参数
function createVideoPopUp(features: object) {
// console.log('features', features)
const app = createVNode(pop, { obj: features }) // pop为自定义的组件,{ obj: features }为传参
mountNode = document.createElement("div");
render(app, mountNode);
document.body.appendChild(mountNode);
}
// 自定义组件中接收传参
defineProps({
obj: {
type: Object
}
})
如果有错误的地方还请大佬指正,还有更好的方法还请大佬指教!