我需要编写一个函数,它采用基于
lat
和 lon
值的 GeoJSON 并将多边形绘制到 2d 画布上。
除此之外,我还需要添加一些距离并绘制内部多边形,其中多边形的 4 个边(北、东、西、南)与外多边形的距离不同。我有一个问题,边缘坐标仅在一维中输出,在绘制多边形时,某些点/线需要通过单边(北或南等)偏移......或者在某些情况下,两侧需要偏移都要考虑在内。
有人能指出我解决问题的方向吗?到目前为止,除了绿色圆圈中的边缘情况外,大多数线条都已正确绘制。
正确的图片应该是这样的
正确
当前实现的codepen
https://codepen.io/Zlatko-Memisevic/pen/qBGNVgj
const exampleGeoJson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[9.409277330768161, 47.330294996637527],
[9.40929555711242, 47.330394995087424],
[9.409449188016863, 47.330385694636568],
[9.409441872135783, 47.330340644668418],
[9.409432145964761, 47.330341377653177],
[9.409430621953572, 47.330332010609965],
[9.409383287787568, 47.330335311475089],
[9.409376169945089, 47.330288098791449],
[9.409349057871147, 47.330289992509627],
[9.409347814140572, 47.330283553765319],
[9.409279252163072, 47.330288260899749],
[9.409281541354549, 47.330294699779891],
[9.409277330768161, 47.330294996637527]
]
]
}
}]
};
function drawGeoJsonOnCanvas(geoJson, canvasId, offsets) {
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
if (!canvas) {
console.error(`Canvas element with id "${canvasId}" not found.`);
return;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
const bbox = turf.bbox(geoJson);
const scaleX = canvas.width / (bbox[2] - bbox[0]);
const scaleY = canvas.height / (bbox[3] - bbox[1]);
function drawPolygon(coordinates, dotted, labelSides = false) {
ctx.beginPath();
coordinates.forEach((coord, index) => {
const x = (coord[0] - bbox[0]) * scaleX;
const y = (bbox[3] - coord[1]) * scaleY;
if (index === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
});
ctx.closePath();
if (dotted) {
ctx.setLineDash([5, 5]);
} else {
ctx.setLineDash([]);
}
ctx.stroke();
if (labelSides) {
for (let i = 0; i < coordinates.length - 1; i++) {
const start = coordinates[i];
const end = coordinates[i + 1];
const mid = turf.midpoint(start, end);
const midX = (mid.geometry.coordinates[0] - bbox[0]) * scaleX;
const midY = (bbox[3] - mid.geometry.coordinates[1]) * scaleY;
const length = turf.distance(start, end, {
units: 'meters'
}).toFixed(2);
ctx.fillText(`${length}m`, midX, midY);
}
}
}
function getOffsetDistance(direction, offsets) {
if (direction >= -45 && direction < 45) {
return offsets.east;
} else if (direction >= 45 && direction < 135) {
return offsets.north;
} else if (direction >= -135 && direction < -45) {
return offsets.south;
} else {
return offsets.west;
}
}
const features = geoJson.features;
features.forEach(feature => {
const coordinates = feature.geometry.coordinates[0];
drawPolygon(coordinates, false, true);
const offsettedCoordinates = [];
for (let i = 0; i < coordinates.length - 1; i++) {
const start = coordinates[i];
const end = coordinates[(i + 1) % coordinates.length];
const line = turf.lineString([start, end]);
const direction = turf.bearing(start, end);
const offsetDistance = getOffsetDistance(direction, offsets);
const offsettedLine = turf.transformTranslate(line, offsetDistance, direction + 90, {
units: 'centimeters'
});
offsettedCoordinates.push(offsettedLine.geometry.coordinates[0]);
offsettedCoordinates.push(offsettedLine.geometry.coordinates[1]);
}
const uniqueOffsettedCoordinates = Array.from(new Set(offsettedCoordinates.map(JSON.stringify))).map(JSON.parse);
uniqueOffsettedCoordinates.push(uniqueOffsettedCoordinates[0]); // Close the polygon
const innerPolygon = turf.polygon([uniqueOffsettedCoordinates]);
if (innerPolygon.geometry.type === 'Polygon') {
const innerCoordinates = innerPolygon.geometry.coordinates[0];
drawPolygon(innerCoordinates, true);
}
});
}
// Example usage
document.addEventListener('DOMContentLoaded', () => {
const offsets = {
north: 50, // in centimeters
south: 50, // in centimeters
east: 50, // in centimeters
west: 50 // in centimeters
};
drawGeoJsonOnCanvas(exampleGeoJson, 'geoCanvas', offsets);
});
#geoCanvas {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/6.5.0/turf.min.js"></script>
<canvas id="geoCanvas" width="800" height="600"></canvas>
从未见过针对您想要做的事情的开箱即用的解决方案。
一个新颖的解决方案是:
这会很繁琐并且涉及一些数学,但应该相当稳健,至少对于像你所展示的那样复杂的形状是这样。