Laravel中Mapbox GL Draw多边形加载后无法正常显示问题
解决Laravel+Mapbox GL JS编辑页面多边形不显示问题
问题诊断
- 数据库存储的坐标存在多层JSON转义(重复引号包裹),导致读取后格式不符合GeoJSON要求
- 控制器对已被模型自动转换为数组的字段重复执行
json_encode,加剧格式混乱 - 地图初始化时未等待Mapbox地图加载完成就尝试添加多边形
- 表单缺少存储多边形坐标的隐藏字段,导致保存和回显逻辑不完整
分步解决方案
1. 修复数据库坐标格式问题
模型已配置polygon_coordinates为array类型,保存时直接传入数组即可,禁止手动JSON编码。针对已存在的脏数据,可在模型中添加访问器自动处理多层转义:
// app/Models/ZoneCoverage.php public function getPolygonCoordinatesAttribute($value) { // 循环解码直到得到数组格式 while (is_string($value)) { $decoded = json_decode($value, true); if (json_last_error() === JSON_ERROR_NONE) { $value = $decoded; } else { break; } } return $value; }
2. 简化控制器逻辑
模型会自动将polygon_coordinates字段转为数组,无需手动json_encode,直接传递给视图即可:
// 控制器edit方法 public function edit($id) { $zoneCoverage = ZoneCoverage::findOrFail($id); $salesRegions = SalesRegion::all(); // 直接传递数组,避免重复编码 $polygonCoordinates = $zoneCoverage->polygon_coordinates; return view('plugins/demo::zone_coverage.form', compact('zoneCoverage', 'salesRegions', 'polygonCoordinates')); }
3. 修正视图地图加载逻辑
确保地图加载完成后再添加多边形,同时补充表单隐藏字段:
<!-- 在表单内部添加隐藏字段,用于存储多边形坐标 --> <input type="hidden" name="polygon_coordinates" id="polygon_coordinates" value="{{ old('polygon_coordinates', json_encode($zoneCoverage->polygon_coordinates ?? [])) }}"> <!-- 修改initMap函数中的多边形加载部分 --> function initMap() { mapboxgl.accessToken = 'pk.eyJ1Ijoia290aTQyIiwiYSI6ImNsdnVudDFyOTE2N3Myam53eTZpcGxkOG8ifQ.IuuMRUS4czPqGuYWnpJ6Ww'; const map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/satellite-v9', center: [28.9784, 41.0082], zoom: 13 }); const draw = new MapboxDraw({ displayControlsDefault: false, controls: { polygon: true, trash: true }, defaultMode: 'draw_polygon' }); map.addControl(draw); map.on('draw.create', updateArea); map.on('draw.delete', updateArea); map.on('draw.update', updateArea); function updateArea(e) { const data = draw.getAll(); const answer = document.getElementById('calculated-area'); if (data.features.length > 0) { const area = turf.area(data); const rounded_area = Math.round(area * 100) / 100; // 避免元素不存在导致报错 if(answer) answer.innerHTML = `<p><strong>${rounded_area}</strong></p><p>square meters</p>`; document.getElementById('polygon_coordinates').value = JSON.stringify(data.features[0].geometry.coordinates); } else { if(answer) answer.innerHTML = ''; if (e.type !== 'draw.delete') alert('Click the map to draw a polygon.'); } } @if(isset($polygonCoordinates) && !empty($polygonCoordinates)) // 等待地图load事件触发后再添加多边形 map.on('load', function() { const polygon = { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": {!! json_encode($polygonCoordinates) !!} } }; draw.add(polygon); map.fitBounds(turf.bbox(polygon), { padding: 20 }); }); @endif setTimeout(function() { map.resize(); }, 500); }
4. 清理冗余依赖
视图中引入了Leaflet相关CSS,但实际使用的是Mapbox GL JS,可移除冗余代码:
<!-- 移除以下两行无用代码 --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" /> <link rel="stylesheet" href="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css" />
内容的提问来源于stack exchange,提问作者mehmet
相关产品推荐
相关产品推荐

