关于使用mapox动态绘制线面,实时更新数据及计算的面积线段长度

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"],
  });
};

只是简易版本,后续持续更新

持续更新的功能

  1. 撤销和重做(有一点眉头,代码有体现,欢迎指教)
  2. 绘制线和绘制面的切换
  3. 删除绘制
  4. .....其他功能
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值