什么是Marker:标记点
什么是连接线:路径线
最终效果:
要求:
- marker为自定义的图形,并显示标记序号。
- 标记点可拖动,拖动期间不影响其连接线(跟随绘制)。
- 每两个点之间绘制连接线,样式为虚线。
实现过程:
- 基于
leafletjs
,网址:https://leafletjs.com/ - 知晓如何增加marker。并增加至图层组(方便管理)。
- 如何增加连接线,并重新定义其样式。需要给marker绑定拖动事件。
难点:
- 添加自定义marker
- 拖动时绘制连接线
具体代码:
//添加标记、移动标记、添加线
//此处未粘贴mymap,参考官方文档创建一个map
var marker_group = L.layerGroup([]) //存放marker
marker_group.addTo(mymap)
var line_group = L.layerGroup([]) //为marker计数,不可放置同一组
line_group.addTo(mymap)
var polylinelist = [] //存放marker的坐标,用于生成连接线
var polylinelist_cache = [] //存放marker的坐标,缓存坐标。因marker移动时,会产生两个坐标:新坐标、旧坐标,旧坐标在拖动期间是不变的,拖动的同时又要绘制连接线,需要一个中间变量来索引到发生变化的值。拖动事件停止后再将这两个值进行同步,即可开始下一次拖动。
var lines = L.polyline([], {color: '#25db71', weight: 1, dashArray: [5, 5],})
//定义连接线的样式,dashArray表示虚线,[实线长度,实线间距]
mymap.on("dblclick", function (e) {
//双击事件,双击添加marker
addMarker(e.latlng.lat, e.latlng.lng)
})
function redrawLine() {
//给polyline设定新的坐标数据后,重新绘制
lines.setLatLngs(polylinelist)
lines.redraw()
}
function IniDivIcon(marker_id) {
//初始化marker,使其具有编号,采用自定义icon对象
return L.divIcon({
className: 'my-div-icon',
html: "<p class='text-center' style='margin-bottom:0;font-size:22px;color:#00ff3a;'>" +
marker_id +
"</p>" +
"<img src='{% static 'http_app/index/img/position.png' %}' height=30 width=22>",
iconSize: [22, 30], //marker的宽,高
iconAnchor: [11, 63], // 坐标值对应的marker位置。以marker左上角为[0,0],也就是你想标记的位置实际是marker的左上角,需要调整marker的底部尖端为实际标记位置
});
}
function addMarker(lat, long) {
//增加新的marker
const marker_id = Object.keys(marker_group._layers).length + 1 //根据图层组内marker数量为marker添加编号
const marker = L.marker([lat, long], {
icon: IniDivIcon(marker_id),
draggable: true, //可拖动
})
marker_group.addLayer(marker) //添加至图层组
//为每个marker绑定事件。drag移动中不断触发更新连接线,dragend停止移动后触发polylinelist与polylinelist_cache同步
marker.on("drag", function (e) {
IconOnMove([e.latlng.lat, e.latlng.lng], [e.oldLatLng.lat, e.oldLatLng.lng])
})
marker.on("dragend", function (e) {
polylinelist_cache = Array.from(polylinelist) //坑1:polylinelist_cache = polylinelist会将内存地址引用,即深copy
})
//根据marker增加轨迹线
const latlngs_length = polylinelist.push([lat, long]) //轨迹线数组
polylinelist_cache.push([lat, long]) //轨迹线缓存数组
//如果只有1个 不添加连接线,2个添加连接线并将线添加至图层组,3个及以上则更新轨迹线数组
if (latlngs_length >= 3) {
redrawLine()
} else if (latlngs_length < 3 && latlngs_length > 1) {
lines.setLatLngs(polylinelist)
line_group.addLayer(lines)
}
}
function checkArray(src, value) {
//校验两个数组是否一致
if (src.length !== value.length) {
return false;
}
for (var i = 0, l = src.length; i < l; i++) {
// Check if we have nested arrays
if (src[i] instanceof Array && value[i] instanceof Array) {
// recurse into the nested arrays
if (!src[i].equals(value[i]))
return false;
} else if (src[i] !== value[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
function IconOnMove(new_latlng, old_latlng) {
//移动marker,更新轨迹线
if (polylinelist_cache.length < 2) {
return
}
polylinelist_cache.forEach(function (value, index) {
// 遍历连接线的数据列表,与 old_latlng对比,根据index赋予新值
// const result = checkArray(value, old_latlng) 和下行可对换
const result = value.toString() === old_latlng.toString()
if (result) {
polylinelist[index] = new_latlng
redrawLine()
}
})
}
function clearAllIcon() {
//清空所有图层组
marker_group.clearLayers()
line_group.clearLayers()
polylinelist = []
polylinelist_cache = []
}
踩坑:
-
经典赋值问题:
marker.on("dragend", function (e) { polylinelist_cache = Array.from(polylinelist) //坑1:polylinelist_cache = polylinelist会将内存地址引用,即深copy }) //此处原本内容为 polylinelist_cache = polylinelist //即: `=`会将内存地址作为引用,即在第一次拖动停止后,再次拖动将会直接改变polylinelist_cache的值导致拖动无效果