mapboxgl.accessToken = "你自己的accessToken";
const coordinates = document.getElementById("coordinates");
const map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/streets-v11",
center: [106.33, 29.35],
zoom: 10,
});
// 绘制线还是面
let isDrawType = "area";
// 记录每一步生成的点的集合的集合
const records = [];
// 创建数据源
const createSource = (sName, data) => {
if (map.getSource(sName)) {
return map.removeSource(sName);
}
map.addSource(sName, {
type: "geojson",
data,
});
};
// 创建数据源所需要的数据json
const createSourceData = (features) => {
return {
features,
type: "FeatureCollection",
};
};
// 创建线需要的feature
const createLineFeature = (features) => {
const linestring = {
type: "Feature",
geometry: {
type: "LineString",
coordinates: [],
},
};
linestring.geometry.coordinates = features;
return linestring;
};
const createAreaFeature = (features) => {
let polygonString = {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [],
},
};
polygonString.geometry.coordinates = [[...features, features[0]]];
return polygonString;
};
let currentIndex = -1;
// 点击生成的点的坐标集合
let points = [];
// 由点位生成的marker标记实例
let markers = [];
document.getElementById("line").onclick = () => {
if(!records.length) return;
points = records[currentIndex - 1];
currentIndex -= 1;
createPointMarker();
createArea();
};
map.on("load", () => {
createSource("draw-line", null);
createSource("draw-area", null);
createLineLayer();
createAreaLayer();
});
// 点击事件
map.on("click", (e) => {
points.push(e.lngLat);
records.push(JSON.parse(JSON.stringify(points)));
currentIndex += 1;
createPointMarker();
isDrawType === "line" ? createLine() : createArea();
});
// 统一生成线
const createLine = () => {
let pos = points.map((p) => [p.lng, p.lat]);
map
.getSource("draw-line")
.setData(createSourceData([createLineFeature(pos)]));
if (pos.length < 2) return;
document.querySelector("#result").innerHTML =
turf.length(turf.lineString(pos)) + "km";
};
// 统一生成面
const createArea = () => {
if(!points) return;
let pos = points.map((p) => [p.lng, p.lat]);
if (pos.length < 3)
return map.setLayoutProperty("measure-area", "visibility", "none");
map.setLayoutProperty("measure-area", "visibility", "visible");
map
.getSource("draw-area")
.setData(createSourceData([createAreaFeature(pos)]));
document.querySelector("#result").innerHTML =
turf.area(turf.polygon([[...pos, pos[0]]])) + "m²";
};
// 根据点位生成marker
const createPointMarker = () => {
if (markers?.length) {
markers.forEach((i) => i.remove());
}
if(!points) return;
markers = points.map((item) => {
const element = document.createElement("div");
element.setAttribute("class", "marker");
return new mapboxgl.Marker({ draggable: true, element })
.setLngLat(item)
.addTo(map);
});
markers.forEach((marker, index) => {
let v = index;
marker.on("drag", (val) => {
points.splice(v, 1, val.target._lngLat);
isDrawType === "line" ? createLine() : createArea();
});
marker.on("dragend", () => {
records.push(JSON.parse(JSON.stringify(points)));
currentIndex += 1;
});
});
};
// 创建绘制线需要的图层
const createLineLayer = () => {
map.addLayer({
id: "measure-lines",
type: "line",
source: "draw-line",
layout: {
"line-cap": "round",
"line-join": "round",
},
paint: {
"line-color": "#ff3366",
"line-width": 1.5,
},
filter: ["in", "$type", "LineString"],
});
};
// 创建绘制面需要的图层
const createAreaLayer = () => {
map.addLayer({
id: "measure-area",
type: "fill",
source: "draw-area",
layout: {},
paint: {
"fill-color": "#ff3366",
"fill-opacity": 0.3,
},
filter: ["in", "$type", "Polygon"],
});
};
只是简易版本,后续持续更新
持续更新的功能
- 撤销和重做(有一点眉头,代码有体现,欢迎指教)
- 绘制线和绘制面的切换
- 删除绘制
- .....其他功能