Smooth scroll geoguessr map

Makes the leaflet map in openguessr scroll more smoothly

  1. // ==UserScript==
  2. // @name Smooth scroll geoguessr map
  3. // @match https://openguessr.com/*
  4. // @grant none
  5. // @version 1.0
  6. // @author ItsPi3141
  7. // @description Makes the leaflet map in openguessr scroll more smoothly
  8. // @run-at document-start
  9. // @license MIT
  10. // @namespace https://greasyfork.org/users/1334015
  11. // ==/UserScript==
  12.  
  13. let injected = false;
  14. const originalFunctionCall = Function.prototype.call;
  15. Function.prototype.call = function (...args) {
  16. if (!injected && args[0]?._leaflet_id) {
  17. inject();
  18. applyStyles();
  19. injected = true;
  20. }
  21.  
  22. return originalFunctionCall.apply(this, args);
  23. };
  24.  
  25. // https://github.com/mutsuyuki/Leaflet.SmoothWheelZoom
  26. const inject = () => {
  27. L.Map.mergeOptions({
  28. scrollWheelZoom: false,
  29. smoothWheelZoom: true,
  30. smoothSensitivity: 2,
  31. });
  32.  
  33. L.Map.SmoothWheelZoom = L.Handler.extend({
  34. addHooks: function () {
  35. L.DomEvent.on(this._map._container, "wheel", this._onWheelScroll, this);
  36. },
  37.  
  38. removeHooks: function () {
  39. L.DomEvent.off(this._map._container, "wheel", this._onWheelScroll, this);
  40. },
  41.  
  42. _onWheelScroll: function (e) {
  43. if (!this._isWheeling) {
  44. this._onWheelStart(e);
  45. }
  46. this._onWheeling(e);
  47. },
  48.  
  49. _onWheelStart: function (e) {
  50. var map = this._map;
  51. this._isWheeling = true;
  52. this._wheelMousePosition = map.mouseEventToContainerPoint(e);
  53. this._centerPoint = map.getSize()._divideBy(2);
  54. this._startLatLng = map.containerPointToLatLng(this._centerPoint);
  55. this._wheelStartLatLng = map.containerPointToLatLng(
  56. this._wheelMousePosition,
  57. );
  58. this._startZoom = map.getZoom();
  59. this._moved = false;
  60. this._zooming = true;
  61.  
  62. map._stop();
  63. if (map._panAnim) map._panAnim.stop();
  64.  
  65. this._goalZoom = map.getZoom();
  66. this._prevCenter = map.getCenter();
  67. this._prevZoom = map.getZoom();
  68.  
  69. this._zoomAnimationId = requestAnimationFrame(
  70. this._updateWheelZoom.bind(this),
  71. );
  72. },
  73.  
  74. _onWheeling: function (e) {
  75. var map = this._map;
  76.  
  77. this._goalZoom =
  78. this._goalZoom +
  79. L.DomEvent.getWheelDelta(e) * 0.003 * map.options.smoothSensitivity;
  80. if (
  81. this._goalZoom < map.getMinZoom() ||
  82. this._goalZoom > map.getMaxZoom()
  83. ) {
  84. this._goalZoom = map._limitZoom(this._goalZoom);
  85. }
  86. this._wheelMousePosition = this._map.mouseEventToContainerPoint(e);
  87.  
  88. clearTimeout(this._timeoutId);
  89. this._timeoutId = setTimeout(this._onWheelEnd.bind(this), 200);
  90.  
  91. L.DomEvent.preventDefault(e);
  92. L.DomEvent.stopPropagation(e);
  93. },
  94.  
  95. _onWheelEnd: function (e) {
  96. this._isWheeling = false;
  97. cancelAnimationFrame(this._zoomAnimationId);
  98. this._map._moveEnd(true);
  99. },
  100.  
  101. _updateWheelZoom: function () {
  102. var map = this._map;
  103.  
  104. if (
  105. !map.getCenter().equals(this._prevCenter) ||
  106. map.getZoom() != this._prevZoom
  107. )
  108. return;
  109.  
  110. this._zoom = map.getZoom() + (this._goalZoom - map.getZoom()) * 0.3;
  111. this._zoom = Math.floor(this._zoom * 100) / 100;
  112.  
  113. var delta = this._wheelMousePosition.subtract(this._centerPoint);
  114. if (delta.x === 0 && delta.y === 0) return;
  115.  
  116. if (map.options.smoothWheelZoom === "center") {
  117. this._center = this._startLatLng;
  118. } else {
  119. this._center = map.unproject(
  120. map.project(this._wheelStartLatLng, this._zoom).subtract(delta),
  121. this._zoom,
  122. );
  123. }
  124.  
  125. if (!this._moved) {
  126. map._moveStart(true, false);
  127. this._moved = true;
  128. }
  129.  
  130. map._move(this._center, this._zoom);
  131. this._prevCenter = map.getCenter();
  132. this._prevZoom = map.getZoom();
  133.  
  134. this._zoomAnimationId = requestAnimationFrame(
  135. this._updateWheelZoom.bind(this),
  136. );
  137. },
  138. });
  139.  
  140. L.Map.addInitHook("addHandler", "smoothWheelZoom", L.Map.SmoothWheelZoom);
  141. };
  142.  
  143. const applyStyles = () => {
  144. const styles = document.createElement("style");
  145. styles.innerHTML = `.leaflet-zoom-animated {
  146. transition: 0.1s transform ease-out;
  147. }
  148. .leaflet-layer :is([style*='z-index: 17']) {
  149. opacity: 0 !important;
  150. }`;
  151. document.head.appendChild(styles);
  152. };