This commit is contained in:
2026-08-24 15:08:55 +08:00
parent ebd219c88e
commit ed4e4dce10
2 changed files with 89 additions and 15 deletions
+57 -12
View File
@@ -21,6 +21,8 @@ class DroneMap:
self.font_scale = 1.0
self.socket_colors = {}
self.drone_group_colors = {}
self.mission_following_enabled = False
self.mission_following_drone_id = None
# 創建橋接對象
self.bridge = MapBridge()
@@ -199,16 +201,18 @@ class DroneMap:
bridge = channel.objects.bridge;
});
var map = L.map('map').setView([0, 0], 19);
var map = L.map('map', {maxZoom: 20}).setView([0, 0], 19);
// 創建不同的地圖圖層
var streetLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
maxNativeZoom: 19,
maxZoom: 20,
attribution: '© OpenStreetMap contributors'
});
var satelliteLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
maxZoom: 19,
maxNativeZoom: 19,
maxZoom: 20,
attribution: 'Tiles © Esri'
});
@@ -217,7 +221,6 @@ class DroneMap:
currentLayer.addTo(map);
var isSatellite = true;
// 地圖點擊事件
map.on('click', function(e) {
if (selectionMode === 'polygon') {
@@ -349,6 +352,7 @@ class DroneMap:
var socketColors = {};
var droneGroupColors = {};
var focusedId = null;
var missionFollowingEnabled = false;
var initialized = false;
var trajectoryGroup = L.layerGroup().addTo(map);
@@ -767,15 +771,34 @@ class DroneMap:
function focusOn(id) {
if (!markers[id]) return;
focusedId = id;
// 非任務狀態只移動一次;任務執行中才記住焦點持續跟隨。
focusedId = missionFollowingEnabled ? id : null;
var latlng = markers[id].getLatLng();
autoCenteringMap = true;
map.flyTo(latlng, map.getZoom());
setTimeout(() => { autoCenteringMap = false; }, 500);
}
setInterval(() => {
function setMissionFollowingEnabled(enabled, preferredId) {
missionFollowingEnabled = Boolean(enabled);
if (!missionFollowingEnabled) {
// 非任務狀態不跟隨 UAV 或目標點,保留使用者手動地圖視角。
focusedId = null;
return;
}
// 任務已在執行時保留原有焦點;尚無焦點時跟隨指定 UAV。
if (focusedId && markers[focusedId]) {
return;
}
if (preferredId && markers[preferredId]) {
focusOn(preferredId);
initialized = true;
}
}
setInterval(() => {
if (missionFollowingEnabled && focusedId && markers[focusedId]) {
var latlng = markers[focusedId].getLatLng();
autoFollowPanTo(latlng);
}
@@ -793,7 +816,7 @@ class DroneMap:
.setLatLng([lat, lon])
.setRotationAngle(heading);
idLabels[id].setLatLng([lat, lon]);
if (id === focusedId) {
if (missionFollowingEnabled && id === focusedId) {
autoFollowPanTo(markers[id].getLatLng());
}
} else {
@@ -813,7 +836,6 @@ class DroneMap:
if (bridge) {
bridge.emitDroneClicked(id);
}
focusOn(id);
})
.addTo(map);
@@ -828,14 +850,23 @@ class DroneMap:
if (bridge) {
bridge.emitDroneClicked(id);
}
focusOn(id);
})
.addTo(map);
if (!initialized || id < focusedId) {
if (!initialized) {
// 第一次收到 UAV 位置時只做一次初始置中,
// 非任務狀態不設 focusedId,所以後續不會跟隨。
if (missionFollowingEnabled) {
focusedId = id;
}
autoCenteringMap = true;
map.setView([lat, lon], 19);
setTimeout(() => { autoCenteringMap = false; }, 300);
initialized = true;
} else if (missionFollowingEnabled &&
(!focusedId || id < focusedId)) {
focusedId = id;
map.setView([lat, lon], 19);
initialized = true;
}
}
}
@@ -975,6 +1006,9 @@ class DroneMap:
self.set_font_scale(self.font_scale)
self.set_socket_colors(self.socket_colors)
self.set_drone_group_colors(self.drone_group_colors)
self.set_mission_following(
self.mission_following_enabled,
self.mission_following_drone_id)
else:
_log("ERROR", "地圖載入失敗")
@@ -1021,6 +1055,17 @@ class DroneMap:
if self.map_loaded:
self.map_view.page().runJavaScript(f"focusOn('{drone_id}');")
def set_mission_following(self, enabled, preferred_drone_id=None):
"""只在任務執行中啟用 UAV 自動跟隨。"""
self.mission_following_enabled = bool(enabled)
self.mission_following_drone_id = preferred_drone_id
if self.map_loaded:
preferred_json = json.dumps(preferred_drone_id)
self.map_view.page().runJavaScript(
"setMissionFollowingEnabled("
f"{str(self.mission_following_enabled).lower()}, "
f"{preferred_json});")
def set_font_scale(self, scale):
"""設定地圖 HTML 控制項的字體倍率。"""
self.font_scale = scale
@@ -1149,7 +1194,7 @@ class MapBridge(QObject):
def emitGpsSignal(self, lat, lon):
"""供 JavaScript 調用的方法"""
self.gps_signal.emit(lat, lon)
@pyqtSlot(str)
def emitDroneClicked(self, drone_id):
"""供 JavaScript 調用的方法 - 當無人機被點擊時"""