WME Satellite Imagery Shifter 2

Adjusts the position and transparency of satellite imagery in WME (supports movement in all directions with arrow keys and buttons, maintains position during zoom)

  1. // ==UserScript==
  2. // @name WME Satellite Imagery Shifter 2
  3. // @version 1.7.9
  4. // @description Adjusts the position and transparency of satellite imagery in WME (supports movement in all directions with arrow keys and buttons, maintains position during zoom)
  5. // @match https://beta.waze.com/*editor*
  6. // @match https://www.waze.com/*editor*
  7. // @grant none
  8. // @author Blue Rabbit
  9. // @icon https://img.icons8.com/?size=48&id=36210&format=png
  10. // @namespace https://www.waze.com/forum/viewtopic.php?t=53022
  11. // @contributor berestovskyy, iainhouse, ragacs
  12. // ==/UserScript==
  13.  
  14. function initializeAerialShifter() {
  15. console.log("WME Satellite Imagery Shifter: Initializing...");
  16.  
  17. // Register sidebar tab
  18. const { tabLabel, tabPane } = W.userscripts.registerSidebarTab("wme-aerial-shifter");
  19.  
  20. tabLabel.innerText = 'Satellite Adjust';
  21. tabLabel.title = 'Adjust satellite imagery position';
  22.  
  23. tabPane.innerHTML = `
  24. <div style="padding: 10px; text-align: center; font-size: 16px;">
  25. <div style="margin-bottom: 15px;">
  26. <label style="font-size: 18px;">Horizontal Shift (m):</label><br>
  27. <input type="number" id="was_sx" min="-100000" max="100000" step="10" value="0" style="margin: 0 auto; display: block; font-size: 16px; padding: 5px;">
  28. </div>
  29. <div style="margin-bottom: 15px;">
  30. <label style="font-size: 18px;">Vertical Shift (m):</label><br>
  31. <input type="number" id="was_sy" min="-100000" max="100000" step="10" value="0" style="margin: 0 auto; display: block; font-size: 16px; padding: 5px;">
  32. </div>
  33. <div style="margin-bottom: 15px;">
  34. <label style="font-size: 18px;">Transparency (%):</label><br>
  35. <input type="number" id="was_opacity" min="0" max="100" step="10" value="100" style="margin: 0 auto; display: block; font-size: 16px; padding: 5px;">
  36. </div>
  37. <div style="margin: 15px 0;">
  38. <button id="was_upleft" style="font-size: 24px; padding: 10px 15px;">↖</button>
  39. <button id="was_up" style="font-size: 24px; padding: 10px 15px;">↑</button>
  40. <button id="was_upright" style="font-size: 24px; padding: 10px 15px;">↗</button>
  41. <br>
  42. <button id="was_left" style="font-size: 24px; padding: 10px 15px;">←</button>
  43. <button id="was_right" style="font-size: 24px; padding: 10px 15px;">→</button>
  44. <br>
  45. <button id="was_downleft" style="font-size: 24px; padding: 10px 15px;">↙</button>
  46. <button id="was_down" style="font-size: 24px; padding: 10px 15px;">↓</button>
  47. <button id="was_downright" style="font-size: 24px; padding: 10px 15px;">↘</button>
  48. </div>
  49. <div>
  50. <button id="was_reset" style="font-size: 18px; padding: 5px 10px;">Reset</button>
  51. </div>
  52. </div>
  53. `;
  54.  
  55. W.userscripts.waitForElementConnected(tabPane).then(() => {
  56. console.log("WME Satellite Imagery Shifter: UI loaded.");
  57.  
  58. // Add event listeners to input fields
  59. const inputs = ['was_sx', 'was_sy', 'was_opacity'];
  60. inputs.forEach(id => {
  61. document.getElementById(id).addEventListener('input', applyChanges);
  62. });
  63.  
  64. // Add event listeners to buttons
  65. document.getElementById("was_up").addEventListener("click", () => moveLayer(0, -10));
  66. document.getElementById("was_down").addEventListener("click", () => moveLayer(0, 10));
  67. document.getElementById("was_left").addEventListener("click", () => moveLayer(-10, 0));
  68. document.getElementById("was_right").addEventListener("click", () => moveLayer(10, 0));
  69. document.getElementById("was_upleft").addEventListener("click", () => moveLayer(-7.07, -7.07));
  70. document.getElementById("was_upright").addEventListener("click", () => moveLayer(7.07, -7.07));
  71. document.getElementById("was_downleft").addEventListener("click", () => moveLayer(-7.07, 7.07));
  72. document.getElementById("was_downright").addEventListener("click", () => moveLayer(7.07, 7.07));
  73. document.getElementById("was_reset").addEventListener("click", resetDefaults);
  74.  
  75. // Monitor zoom events
  76. W.map.events.register("zoomend", null, applyChanges);
  77.  
  78. loadSettings();
  79. applyChanges();
  80. });
  81. }
  82.  
  83. function moveLayer(deltaX, deltaY) {
  84. // Move layer with button clicks
  85. let shiftX = (parseInt(document.getElementById("was_sx").value) || 0) + deltaX;
  86. let shiftY = (parseInt(document.getElementById("was_sy").value) || 0) + deltaY;
  87. document.getElementById("was_sx").value = Math.round(shiftX);
  88. document.getElementById("was_sy").value = Math.round(shiftY);
  89. applyChanges();
  90. }
  91.  
  92. function applyChanges() {
  93. // Apply changes
  94. let shiftX = parseInt(document.getElementById("was_sx").value, 10) || 0;
  95. let shiftY = parseInt(document.getElementById("was_sy").value, 10) || 0;
  96. let opacity = parseInt(document.getElementById("was_opacity").value, 10) || 100;
  97.  
  98. // Calculate meters per pixel
  99. let metersPerPixel = W.map.getResolution() * 39.37; // Dynamic calculation based on zoom level
  100.  
  101. // Get satellite layer
  102. let satLayer = W.map.getLayersBy("CLASS_NAME", "OpenLayers.Layer.Google")[0];
  103.  
  104. if (!satLayer || !satLayer.div) {
  105. console.error("WME Satellite Imagery Shifter: Satellite layer not found.");
  106. return;
  107. }
  108.  
  109. // Apply shift and opacity (convert meters to pixels)
  110. satLayer.div.style.transform = `translate(${Math.round(shiftX / metersPerPixel)}px, ${Math.round(shiftY / metersPerPixel)}px)`;
  111. satLayer.div.style.opacity = opacity / 100;
  112.  
  113. saveSettings(shiftX, shiftY, opacity);
  114. }
  115.  
  116. function resetDefaults() {
  117. // Reset to default values
  118. document.getElementById("was_sx").value = 0;
  119. document.getElementById("was_sy").value = 0;
  120. document.getElementById("was_opacity").value = 100;
  121. applyChanges();
  122. }
  123.  
  124. function loadSettings() {
  125. // Load settings
  126. let settings = JSON.parse(localStorage.getItem("wme_aerial_shifter_settings"));
  127. if (settings) {
  128. document.getElementById("was_sx").value = settings.shiftX || 0;
  129. document.getElementById("was_sy").value = settings.shiftY || 0;
  130. document.getElementById("was_opacity").value = settings.opacity || 100;
  131. }
  132. }
  133.  
  134. function saveSettings(shiftX, shiftY, opacity) {
  135. // Save settings
  136. localStorage.setItem("wme_aerial_shifter_settings", JSON.stringify({
  137. shiftX,
  138. shiftY,
  139. opacity
  140. }));
  141. }
  142.  
  143. // Run script when WME is ready
  144. if (W?.userscripts?.state.isReady) {
  145. initializeAerialShifter();
  146. } else {
  147. document.addEventListener("wme-ready", initializeAerialShifter, { once: true });
  148. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址