preview map editor 60%
This commit is contained in:
@@ -11,6 +11,7 @@ const EMPTY_PREVIEW: GeoJSON.FeatureCollection = {
|
||||
features: [],
|
||||
};
|
||||
|
||||
// Khởi tạo engine vẽ circle bằng thao tác kéo chuột từ tâm ra biên.
|
||||
export function initCircle(
|
||||
map: maplibregl.Map,
|
||||
getMode: ModeGetter,
|
||||
@@ -21,12 +22,14 @@ export function initCircle(
|
||||
let isDragging = false;
|
||||
let dragPanDisabledByCircle = false;
|
||||
|
||||
// Xóa dữ liệu preview circle trên map.
|
||||
const clearPreview = () => {
|
||||
(map.getSource("draw-circle-preview") as maplibregl.GeoJSONSource | undefined)?.setData(
|
||||
EMPTY_PREVIEW
|
||||
);
|
||||
};
|
||||
|
||||
// Bật lại drag pan nếu trước đó bị tắt khi đang kéo vẽ circle.
|
||||
const releaseDragPan = () => {
|
||||
if (!dragPanDisabledByCircle) return;
|
||||
dragPanDisabledByCircle = false;
|
||||
@@ -35,6 +38,7 @@ export function initCircle(
|
||||
}
|
||||
};
|
||||
|
||||
// Reset toàn bộ trạng thái vẽ circle tạm thời.
|
||||
const resetDrawingState = () => {
|
||||
center = null;
|
||||
radiusMeters = 0;
|
||||
@@ -43,6 +47,7 @@ export function initCircle(
|
||||
releaseDragPan();
|
||||
};
|
||||
|
||||
// Cập nhật polygon preview theo tâm và bán kính hiện tại.
|
||||
const updatePreview = () => {
|
||||
if (!center || radiusMeters < MIN_RADIUS_METERS) {
|
||||
clearPreview();
|
||||
@@ -65,6 +70,7 @@ export function initCircle(
|
||||
});
|
||||
};
|
||||
|
||||
// Bắt đầu phiên vẽ circle khi nhấn chuột trái.
|
||||
const onMouseDown = (e: maplibregl.MapMouseEvent) => {
|
||||
if (getMode() !== "add-circle") return;
|
||||
if ((e.originalEvent as MouseEvent | undefined)?.button !== 0) return;
|
||||
@@ -82,6 +88,7 @@ export function initCircle(
|
||||
}
|
||||
};
|
||||
|
||||
// Cập nhật bán kính theo vị trí chuột trong lúc kéo.
|
||||
const onMouseMove = (e: maplibregl.MapMouseEvent) => {
|
||||
const canvas = map.getCanvas();
|
||||
if (getMode() !== "add-circle") {
|
||||
@@ -101,6 +108,7 @@ export function initCircle(
|
||||
updatePreview();
|
||||
};
|
||||
|
||||
// Hoàn tất circle và trả geometry cho callback.
|
||||
const finishCircle = () => {
|
||||
if (!isDragging || !center) {
|
||||
resetDrawingState();
|
||||
@@ -120,12 +128,14 @@ export function initCircle(
|
||||
resetDrawingState();
|
||||
};
|
||||
|
||||
// Kết thúc thao tác kéo bằng mouseup chuột trái.
|
||||
const onMouseUp = (e: maplibregl.MapMouseEvent) => {
|
||||
if (getMode() !== "add-circle") return;
|
||||
if ((e.originalEvent as MouseEvent | undefined)?.button !== 0) return;
|
||||
finishCircle();
|
||||
};
|
||||
|
||||
// Hủy phiên vẽ circle khi nhấn Escape.
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (getMode() !== "add-circle") return;
|
||||
if (e.key !== "Escape") return;
|
||||
@@ -150,6 +160,7 @@ export function initCircle(
|
||||
};
|
||||
}
|
||||
|
||||
// Tạo vòng polygon xấp xỉ hình tròn từ tâm, bán kính và số phân đoạn.
|
||||
function buildCircleRing(
|
||||
center: [number, number],
|
||||
radiusMeters: number,
|
||||
@@ -163,6 +174,7 @@ function buildCircleRing(
|
||||
return ring;
|
||||
}
|
||||
|
||||
// Tính khoảng cách hai điểm theo công thức Haversine (đơn vị mét).
|
||||
function distanceMeters(a: [number, number], b: [number, number]): number {
|
||||
const lat1 = toRad(a[1]);
|
||||
const lat2 = toRad(b[1]);
|
||||
@@ -178,6 +190,7 @@ function distanceMeters(a: [number, number], b: [number, number]): number {
|
||||
return EARTH_RADIUS_METERS * c; // Khoảng cách cung tròn: d = R * c.
|
||||
}
|
||||
|
||||
// Tính tọa độ điểm đích từ tâm, khoảng cách và góc phương vị.
|
||||
function destinationPoint(
|
||||
center: [number, number],
|
||||
distance: number,
|
||||
@@ -205,22 +218,26 @@ function destinationPoint(
|
||||
return [normalizeLng(toDeg(lng2)), toDeg(lat2)];
|
||||
}
|
||||
|
||||
// Chuẩn hóa kinh độ về miền [-180, 180].
|
||||
function normalizeLng(lng: number): number {
|
||||
let normalized = ((lng + 540) % 360) - 180; // Wrap về khoảng [-180, 180).
|
||||
if (normalized === -180) normalized = 180;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// Kẹp giá trị trong đoạn [min, max].
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Đổi đơn vị góc từ độ sang radian.
|
||||
function toRad(value: number): number {
|
||||
return (value * Math.PI) / 180; // Đổi độ sang radian.
|
||||
}
|
||||
|
||||
// Đổi đơn vị góc từ radian sang độ.
|
||||
function toDeg(value: number): number {
|
||||
return (value * 180) / Math.PI; // Đổi radian sang độ.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user