From 60339ea771a791d6d8b79fb6d74dae883dd6452e Mon Sep 17 00:00:00 2001 From: Sean Eidemiller Date: Mon, 5 Feb 2024 19:45:08 -0800 Subject: [PATCH 1/6] Map stays roughly centered when zooming in and out. --- common/scripts/map_actions.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/common/scripts/map_actions.js b/common/scripts/map_actions.js index f896052..796d4bf 100644 --- a/common/scripts/map_actions.js +++ b/common/scripts/map_actions.js @@ -1324,6 +1324,29 @@ function scaleView(zoom) { var dim_str = dimension.toString() + "px"; var scale = properties.zoom / last_zoom; + var scroll_element = document.scrollingElement; + var scroll_top = scroll_element.scrollTop; + var scroll_left = scroll_element.scrollLeft; + var scroll_height = scroll_element.scrollHeight; + var scroll_width = scroll_element.scrollWidth; + var client_height = scroll_element.clientHeight; + var client_width = scroll_element.clientWidth; + var scroll_left_ratio = scroll_left / scroll_width; + var scroll_top_ratio = scroll_top / scroll_height; + var offset_right = scroll_width - (scroll_left + client_width); + var offset_bottom = scroll_height - (scroll_top + client_height); + + setTimeout(function() { + scroll_element.scrollTop = scroll_element.scrollHeight * scroll_top_ratio; + scroll_element.scrollLeft = scroll_element.scrollWidth * scroll_left_ratio; + var new_offset_right = scroll_element.scrollWidth - (scroll_element.scrollLeft + client_width); + var new_offset_bottom = scroll_element.scrollHeight - (scroll_element.scrollTop + client_height); + var diff_right = offset_right - new_offset_right; + var diff_bottom = offset_bottom - new_offset_bottom; + scroll_element.scrollLeft = scroll_element.scrollLeft - (diff_right / 2) / 2; + scroll_element.scrollTop = scroll_element.scrollTop - (diff_bottom / 2) / 2; + }, 0); + var base_map = document.getElementById('map'); base_map.style.height = dim_str; base_map.style.width = dim_str; From 2cfa0b07f8a5517d21963b5a9e6e53edc2cf1980 Mon Sep 17 00:00:00 2001 From: Sean Eidemiller <157770408+rsedevnet@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:38:25 -0800 Subject: [PATCH 2/6] Scroll compensation on zoom now happening in the same event loop. (#22) Fix flicker and better centering - Scroll compensation on zoom now happening in the same event loop (no flickering). - Removed vi swap files added accidentally. - Added .gitignore with vi swap files. --------- Co-authored-by: Sean Eidemiller --- .gitignore | 3 +++ common/scripts/map_actions.js | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c756c3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# vi swap files +*.swo +*.swp diff --git a/common/scripts/map_actions.js b/common/scripts/map_actions.js index 796d4bf..aa4520a 100644 --- a/common/scripts/map_actions.js +++ b/common/scripts/map_actions.js @@ -1336,16 +1336,16 @@ function scaleView(zoom) { var offset_right = scroll_width - (scroll_left + client_width); var offset_bottom = scroll_height - (scroll_top + client_height); - setTimeout(function() { - scroll_element.scrollTop = scroll_element.scrollHeight * scroll_top_ratio; - scroll_element.scrollLeft = scroll_element.scrollWidth * scroll_left_ratio; - var new_offset_right = scroll_element.scrollWidth - (scroll_element.scrollLeft + client_width); - var new_offset_bottom = scroll_element.scrollHeight - (scroll_element.scrollTop + client_height); - var diff_right = offset_right - new_offset_right; - var diff_bottom = offset_bottom - new_offset_bottom; - scroll_element.scrollLeft = scroll_element.scrollLeft - (diff_right / 2) / 2; - scroll_element.scrollTop = scroll_element.scrollTop - (diff_bottom / 2) / 2; - }, 0); + scroll_element.scrollTop = scroll_height * scroll_top_ratio * scale; + scroll_element.scrollLeft = scroll_width * scroll_left_ratio * scale; + + var new_offset_right = scroll_element.scrollWidth * scale - (scroll_element.scrollLeft + client_width); + var new_offset_bottom = scroll_element.scrollHeight * scale - (scroll_element.scrollTop + client_height); + var diff_right = offset_right - new_offset_right; + var diff_bottom = offset_bottom - new_offset_bottom; + + scroll_element.scrollTop = scroll_element.scrollTop - (diff_bottom / 2) / 2; + scroll_element.scrollLeft = scroll_element.scrollLeft - (diff_right / 2) / 2; var base_map = document.getElementById('map'); base_map.style.height = dim_str; From ab5c93e22e6f6b41c86e14f4141cb23053491012 Mon Sep 17 00:00:00 2001 From: Onno Hommes Date: Tue, 27 Feb 2024 00:17:15 -0800 Subject: [PATCH 3/6] Add scroll wheel zoom This patch adds the ability to zoom with the scroll wheel like in BMS. Also the zoom can now go from 50% to 200% so greater range with a default of 100%. Issue: #5 --- common/scripts/map_actions.js | 36 +++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/common/scripts/map_actions.js b/common/scripts/map_actions.js index aa4520a..bdfb97d 100644 --- a/common/scripts/map_actions.js +++ b/common/scripts/map_actions.js @@ -97,6 +97,12 @@ var properties = { } }; +const limits = { + zoom_max: 2.0, + zoom_min: 0.5, + wheel_rate_hz: 20 +} + // Toolbar Icons for actions const toolbar = { icon: { @@ -827,13 +833,13 @@ function button(e) { break; case "zoom1": - if (id == "zoom1" && properties.zoom > 0.55) { - if (e.shiftKey) properties.zoom = 0.55; + if (id == "zoom1" && properties.zoom > limits.zoom_min) { + if (e.shiftKey) properties.zoom = limits.zoom_min; else properties.zoom -= 0.05; } case "zoom2": - if (id == "zoom2" && properties.zoom < 1.0) { - if (e.shiftKey) properties.zoom = 1; + if (id == "zoom2" && properties.zoom < limits.zoom_max) { + if (e.shiftKey) properties.zoom = limits.zoom_max; else properties.zoom += 0.05; } scaleView(properties.zoom); @@ -1222,6 +1228,26 @@ var pointer_end = function(e) { properties.ctrl = false; } +var wheel_enabled = true; +function enable_wheel() { + wheel_enabled = true; +} + +// Allow zooming with the mouse but limit it to a set wheel rate +// See Limiters (20 hz) +var mouse_zoom = function(e) { + e.preventDefault(); + var zoom = properties.zoom - (e.deltaY/200); + if ( wheel_enabled && zoom >= limits.zoom_min && zoom <= limits.zoom_max ) { + properties.zoom = zoom; + scaleView(properties.zoom); + saveSettings(); + refreshCanvas(); + wheel_enabled = false; + setTimeout(enable_wheel, (1 / limits.wheel_rate_hz) * 1000); + } +} + // // Canvas and Layer Routines // @@ -1640,6 +1666,7 @@ window.onload = function(e) { this.addEventListener('mousedown', pointer_start); this.addEventListener('mousemove', pointer_drag); this.addEventListener('mouseup', pointer_end); + this.addEventListener("wheel", mouse_zoom, {passive:false} ); // Trigger a Render updateToolbar(); @@ -1648,6 +1675,7 @@ window.onload = function(e) { window.scrollTo(bullseye.x-window.innerWidth/2,bullseye.y-window.innerHeight/2); // Draw the Layers + enable_wheel(); scaleView(properties.zoom); refreshCanvas(); } From fbaeae83e7edcf552f9a8b34df1f13d4138d976c Mon Sep 17 00:00:00 2001 From: Onno Hommes Date: Tue, 27 Feb 2024 20:30:02 -0800 Subject: [PATCH 4/6] Sync dev branch with main (#27) * Add scroll wheel zoom in and out (#25) * Map stays roughly centered when zooming in and out. * Scroll compensation on zoom now happening in the same event loop. (#22) Fix flicker and better centering - Scroll compensation on zoom now happening in the same event loop (no flickering). - Removed vi swap files added accidentally. - Added .gitignore with vi swap files. --------- Co-authored-by: Sean Eidemiller * Add scroll wheel zoom This patch adds the ability to zoom with the scroll wheel like in BMS. Also the zoom can now go from 50% to 200% so greater range with a default of 100%. Issue: #5 --------- Co-authored-by: Sean Eidemiller Co-authored-by: MaxWaldorf Co-authored-by: Sean Eidemiller <157770408+rsedevnet@users.noreply.github.com> * Fix Issue #17 repeated rescaling of image map. Repeated scaling of image map will after a while make the image map coordinates diverge from the location of the airport on the map. To fix this the coordinates of the image map will be cached and used for calculating the new image map coordinates when scaling is applie. This patch also now resizes the airport locator circle so it is not a tiny circle when zoomed to 200%. --------- Co-authored-by: Sean Eidemiller Co-authored-by: MaxWaldorf Co-authored-by: Sean Eidemiller <157770408+rsedevnet@users.noreply.github.com> --- common/scripts/map_actions.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/common/scripts/map_actions.js b/common/scripts/map_actions.js index bdfb97d..5907557 100644 --- a/common/scripts/map_actions.js +++ b/common/scripts/map_actions.js @@ -221,7 +221,7 @@ function locateAirport(list) { refreshCanvas(); x = parseInt(coords[0]); y = parseInt(coords[1]); - drawHighlight(context,x,y,radius); + drawHighlight(context,x,y,radius * properties.zoom); // Make the airport the focus window.scrollTo(x-window.innerWidth/2,y-window.innerHeight/2); @@ -538,14 +538,21 @@ function selectVisibility(list) { refreshCanvas(); } +var hotspots; +function storeMapCoordinates() { + var imgMap = document.getElementById("imgMap"); + hotspots = []; + for (area of imgMap.children) hotspots.push(area); +} // Scale the image map coordinates to match the airport overlay image function scaleMap(scale) { var imageMap = document.getElementById("imgMap"); var areas = imageMap.children; + i = 0; for (area of areas) { - area.coordArr = area.coords.split(','); - area.coords = area.coordArr.map(coord => Math.round(coord * scale)).join(','); + var coordArr = hotspots[i++].coords.split(','); + area.coords = coordArr.map(coord => Math.round(coord * scale)).join(','); if (area.alt == "Legend") properties.legend = area.coords; if (area.alt == "Bullseye") bullseye.coords = area.coords; } @@ -1641,7 +1648,9 @@ window.onload = function(e) { // Adjust map to used scale // Safari will slow beyond 3840 canvas size + storeMapCoordinates(); scaleMap(3840/4096); + storeMapCoordinates(); // Setup the Layers to be rendered on the main canvas setupLayer(layer.mission, canvas.width, canvas.height ); From a13db8afe38565b49512dce51a97e7a588c2bb86 Mon Sep 17 00:00:00 2001 From: Onno Hommes Date: Thu, 3 Jul 2025 01:03:48 -0700 Subject: [PATCH 5/6] Prepare for 4.38 Maps New landing page and under construction for 4.38 Maps. --- index.html | 182 +++++++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 82 deletions(-) diff --git a/index.html b/index.html index ce59b3a..67068bb 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,14 @@ -Falcon BMS - Interactive Maps (BMS 4.37) +Falcon BMS - Interactive Maps -
-
- -
+
+
+ + +
+
+
-

Falcon BMS 4.37 - Interactive Maps


- You find here Interactive Maps providing access to airbase and airstrip information for the respective theater of operations. The maps provide the following features: -
    -
  • Locate airports and navigation beacons and request their information by hovering over them
  • -
  • Move map, zoom in/out and measure distances on map
  • -
  • Mission.ini or Pilot.ini drag and drop to show route on map and more.
  • -
  • Full whiteboard collaboration using collaboration server
  • -
  • Save Whiteboard(.png) and restore with drag and drop
  • -
  • MIL-STD-2525D symbology
  • -
  • Weather import (fmap drop) for weather charts (Temperature, Doppler, Winds, Isobars)
  • -
  • Route Waypoint dialog (actions, heading, distance and duration updates, etc)
  • -
  • Computed Mission Flight Info, Mission Radio Frequencies and Mission Objectives
  • -
  • Show Lat/Long on map and x,y of image map
  • -
  • Aerodrome Weather Report (METAR) as tooltips and on route dialog (uses) fmap
  • -
  • Add notes on Whiteboard
  • -
  • Bullseye placement
  • -
  • Download and Import GFS data and files
  • -
-
Change log  |  Manual (PDF)
-
+

Falcon BMS - Interactive Maps


+

Theater Maps 4.37

+ @@ -193,7 +142,76 @@
Korea Theater
UNDER CONSTRUCTION +
+ + + + + + + + + + + + +
Korea Theater
Rev: 26 JUNE 2023
Balkans Theater
Rev: 26 JUNE 2023
Israel Theater
Rev: 26 JUNE 2023
Balkans Theater
UNDER CONSTRUCTION
Israel Theater
UNDER CONSTRUCTION
Hellenic Theater
UNDER CONSTRUCTION
+
+
+ Korea Theater +
+ +
+
+
+
+ Balkans Theater +
+ +
+
+
+
+ Israel Theater +
+ +
+
+
+
+ Hellenic Theater +
+ +
+
+
+

Map Features

+ The maps provide the following features: +
    +
  • Locate airports and navigation beacons and request their information by hovering over them
  • +
  • Move map, zoom in/out and measure distances on map
  • +
  • Mission.ini or Pilot.ini drag and drop to show route on map and more.
  • +
  • Full whiteboard collaboration using collaboration server
  • +
  • Save Whiteboard(.png) and restore with drag and drop
  • +
  • MIL-STD-2525D symbology
  • +
  • Weather import (fmap drop) for weather charts (Temperature, Doppler, Winds, Isobars)
  • +
  • Route Waypoint dialog (actions, heading, distance and duration updates, etc)
  • +
  • Computed Mission Flight Info, Mission Radio Frequencies and Mission Objectives
  • +
  • Show Lat/Long on map and x,y of image map
  • +
  • Aerodrome Weather Report (METAR) as tooltips and on route dialog (uses) fmap
  • +
  • Download and Import GFS data and files
  • +
  • Bullseye placement
  • +
+
Change log  |  Manual (PDF)
+
- \ No newline at end of file + From 435c01af4662eec283630075cc324574a227df4e Mon Sep 17 00:00:00 2001 From: Onno Hommes Date: Tue, 8 Jul 2025 23:54:32 -0700 Subject: [PATCH 6/6] KTO Basic Map Setup This PR contains an initial prototype for the 4.38 release with the new map_airbases overlay and JS fixes for zooming and scroll zoom. The top-level landing page will line to the KTO maps but the plates are not ready. It also contains the basic KTO framework but uses the 4.37 charts and data in many places. --- 04_KTO_Interactive_Map/index.html | 1880 +++++++++++++++++ .../resources/map_airbases.png | Bin 0 -> 95661 bytes common/scripts/map_actions.js | 65 +- index.html | 17 +- 4 files changed, 1923 insertions(+), 39 deletions(-) create mode 100644 04_KTO_Interactive_Map/index.html create mode 100644 04_KTO_Interactive_Map/resources/map_airbases.png diff --git a/04_KTO_Interactive_Map/index.html b/04_KTO_Interactive_Map/index.html new file mode 100644 index 0000000..f2035ac --- /dev/null +++ b/04_KTO_Interactive_Map/index.html @@ -0,0 +1,1880 @@ + + + +KTO Interactive Map + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +CHANGJIN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Mission Briefing
+ + + + + +
CallsignBeast5
Times08:40:0008:50:0008:54:0009:00:00
Fuel80005300/4300Laser Code1511
IntelSA-10

+
Package
+ + +
CallsignUHFVHFIDMTCN

+
Airbases
+ + +
TypeLocationAirportTCNGNDTWRAPPATIS

+
Flight Plan
+ + +
STPTLocationActionTOSHdg.Dist.TASMachAlt.Fuel

+
Objectives
+ + +
STPTLocationTarget

+
Support
+ + +
STPTLocationCallsignTypeUHFVHF

+
+ +
+
Weather Briefing
+ + +
CallsignTime010000Z

+
Performance Data
+ + +
TypeAirportRWYELEV.OATQNHPADA

+
Route METARs
+ + +
#StationMETAR

+
Winds and Temperatures Aloft
+ + +
#Station3000 ft6000 ft9000 ft12000 ft18000 ft24000 ft30000 ft

+
+ +
+

Altitude and Velocity

+
+
+ + + + +
+ +
+ +
+ +
+ + + + + + + + +
 
+ + + + + + + + + + + + +
move
zoom-out
zoom-in
bullseye
compass
ruler
symbol
pencil
text
eraser
reset
+
+
+
+
+ + + + +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea +South Korea + +South Korea +South Korea +South Korea +South Korea + +South Korea Airstrips +South Korea Airstrips +South Korea Airstrips +South Korea Airstrips + + +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea + +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea +North Korea + + + + + +North Korea Airstrips + + + + + + + + +North Korea Airstrips +North Korea Airstrips + + +Japan +Japan +Japan +Japan +Japan + + + +China + + + + + +VORTAC +VORTAC +VORTAC + + + +VORTAC + +VORTAC +VORTAC +VORTAC + + + +Legend + +Bullseye + + + + + diff --git a/04_KTO_Interactive_Map/resources/map_airbases.png b/04_KTO_Interactive_Map/resources/map_airbases.png new file mode 100644 index 0000000000000000000000000000000000000000..a598cf86c6c9e4ddef08676181bd3589c05afe77 GIT binary patch literal 95661 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 limits.zoom_min && zoom <= limits.zoom_max ) { - properties.zoom = zoom; + + // Normalize deltaY to a consistent step (e.g., 0.1 zoom per scroll) + var zoomStep = Math.sign(e.deltaY) * 0.1; // Adjust step size as needed + var newZoom = properties.zoom - zoomStep; + + // Ensure zoom stays within limits and apply rounding to avoid floating-point drift + if (wheel_enabled && newZoom >= limits.zoom_min && newZoom <= limits.zoom_max) { + properties.zoom = Math.round(newZoom * 100) / 100; // Round to 2 decimal places scaleView(properties.zoom); saveSettings(); refreshCanvas(); wheel_enabled = false; - setTimeout(enable_wheel, (1 / limits.wheel_rate_hz) * 1000); + setTimeout(function() { + wheel_enabled = true; + }, (1 / limits.wheel_rate_hz) * 1000); } -} +}; // // Canvas and Layer Routines @@ -1352,51 +1359,47 @@ function setupLayer(layer, width, height) { } var last_zoom = 1; -function scaleView(zoom) { +function scaleView(zoom, event) { // Add event parameter to capture mouse position var dimension = 3840 * properties.zoom; var dim_str = dimension.toString() + "px"; var scale = properties.zoom / last_zoom; var scroll_element = document.scrollingElement; - var scroll_top = scroll_element.scrollTop; - var scroll_left = scroll_element.scrollLeft; - var scroll_height = scroll_element.scrollHeight; - var scroll_width = scroll_element.scrollWidth; - var client_height = scroll_element.clientHeight; var client_width = scroll_element.clientWidth; - var scroll_left_ratio = scroll_left / scroll_width; - var scroll_top_ratio = scroll_top / scroll_height; - var offset_right = scroll_width - (scroll_left + client_width); - var offset_bottom = scroll_height - (scroll_top + client_height); - - scroll_element.scrollTop = scroll_height * scroll_top_ratio * scale; - scroll_element.scrollLeft = scroll_width * scroll_left_ratio * scale; + var client_height = scroll_element.clientHeight; - var new_offset_right = scroll_element.scrollWidth * scale - (scroll_element.scrollLeft + client_width); - var new_offset_bottom = scroll_element.scrollHeight * scale - (scroll_element.scrollTop + client_height); - var diff_right = offset_right - new_offset_right; - var diff_bottom = offset_bottom - new_offset_bottom; + // Get mouse position relative to the viewport + var mouseX = event ? event.clientX : client_width / 2; // Fallback to center if no event + var mouseY = event ? event.clientY : client_height / 2; - scroll_element.scrollTop = scroll_element.scrollTop - (diff_bottom / 2) / 2; - scroll_element.scrollLeft = scroll_element.scrollLeft - (diff_right / 2) / 2; + // Calculate mouse position relative to the document before scaling + var doc_mouseX = scroll_element.scrollLeft + mouseX; + var doc_mouseY = scroll_element.scrollTop + mouseY; + // Update map dimensions var base_map = document.getElementById('map'); - base_map.style.height = dim_str; base_map.style.width = dim_str; + base_map.style.height = dim_str; var ovly_map = document.getElementById('airbases'); - ovly_map.style.height = dim_str; ovly_map.style.width = dim_str; - ovly_map.useMap = "#Map"; - + ovly_map.style.height = dim_str; window.canvas.width = dimension; window.canvas.height = dimension; + // Scale bullseye coordinates bullseye.x *= scale; bullseye.y *= scale; - // Adjust the airport coordinates on the image map + // Scale the airport coordinates on the image map scaleMap(scale); + + // Calculate new scroll position to keep mouse point fixed + var new_doc_mouseX = doc_mouseX * scale; + var new_doc_mouseY = doc_mouseY * scale; + scroll_element.scrollLeft = new_doc_mouseX - mouseX; + scroll_element.scrollTop = new_doc_mouseY - mouseY; + last_zoom = properties.zoom; } diff --git a/index.html b/index.html index 67068bb..728951d 100644 --- a/index.html +++ b/index.html @@ -45,7 +45,8 @@ } .container:hover .image { - opacity: 0.7; + opacity: 0.8; + color: #000000; } font_right { @@ -118,7 +119,7 @@

Theater Maps 4.37

- Korea Theater + Korea Theater
Download
@@ -126,7 +127,7 @@

Theater Maps 4.37

- Balkans Theater + Balkans Theater
Download
@@ -134,7 +135,7 @@

Theater Maps 4.37

- Israel Theater + Israel Theater
Download
@@ -159,7 +160,7 @@

Theater Maps 4.38

- Korea Theater + Korea Theater
@@ -167,7 +168,7 @@

Theater Maps 4.38

- Balkans Theater + Balkans Theater
@@ -175,7 +176,7 @@

Theater Maps 4.38

- Israel Theater + Israel Theater
@@ -183,7 +184,7 @@

Theater Maps 4.38

- Hellenic Theater + Hellenic Theater