javascript - 为什么在传单的自定义 crs 中捏合缩放不起作用?

标签 javascript leaflet gis pinchzoom

我已经使用自定义 CRS 设置了传单 map (EPSG:32633)。 map 通常运行良好,但每当我尝试在移动设备上使用捏合缩放 map 时, map 就会卡住。

捏合缩放时发生的错误是“未捕获错误:无效的 LatLng 对象:(NaN,NaN)”。

这是一个可用于重现问题的 jsfiddle:

http://jsfiddle.net/thL5bbnv/2/

这是代码(也在 jsfiddle 中使用):

// Defining  the projection system
L.Projection.UTM33 = {
  ZONE: 33,
  R_MINOR: 6356752.3142,
  R_MAJOR: 6378137,
  DEG_TO_RAD: Math.PI / 180,
  RAD_TO_DEG: 180 / Math.PI,

  bounds: L.bounds([-2500000, 3500000], [3045984, 9045984]),

  project: function(latlng) {
    var latRad = latlng.lat * this.DEG_TO_RAD,
      longRad = latlng.lng * this.DEG_TO_RAD,
      longOriginRad = (-183 + (6 * this.ZONE)) * this.DEG_TO_RAD,
      eccs = 1 - ((this.R_MINOR / this.R_MAJOR) * (this.R_MINOR / this.R_MAJOR)),
      k0 = 0.9996,
      eccps = eccs / (1 - eccs),
      n = this.R_MAJOR / Math.sqrt(1 - eccs * Math.sin(latRad) * Math.sin(latRad)),
      t = Math.tan(latRad) * Math.tan(latRad),
      c = eccps * Math.cos(latRad) * Math.cos(latRad),
      a = Math.cos(latRad) * (longRad - longOriginRad),
      m = this.R_MAJOR * ((1 - eccs / 4 - 3 * eccs * eccs / 64 - 5 * eccs * eccs * eccs / 256) * latRad - (3 * eccs / 8 + 3 * eccs * eccs / 32 + 45 * eccs * eccs * eccs / 1024) * Math.sin(2 * latRad) + (15 * eccs * eccs / 256 + 45 * eccs * eccs * eccs / 1024) * Math.sin(4 * latRad) - (35 * eccs * eccs * eccs / 3072) * Math.sin(6 * latRad)),
      x = k0 * n * (a + (1 - t + c) * a * a * a / 6 + (5 - 18 * t + t * t + 72 * c - 58 * eccps) * a * a * a * a * a / 120) + 500000.0,
      y = k0 * (m + n * Math.tan(latRad) * (a * a / 2 + (5 - t + 9 * c + 4 * c * c) * a * a * a * a / 24.0 + (61.0 - 58 * t + t * t + 600.0 * c - 330.0 * eccps) * a * a * a * a * a * a / 720));

    return new L.Point(x, y);
  },

  unproject: function(point) {
    var eccs = 1 - ((this.R_MINOR / this.R_MAJOR) * (this.R_MINOR / this.R_MAJOR)),
      e1 = (1 - Math.sqrt(1 - eccs)) / (1 + Math.sqrt(1 - eccs)),
      k0 = 0.9996,
      x = point.x - 500000,
      y = point.y,
      longOrigin = (this.ZONE - 1) * 6 - 180 + 3,
      eccps = (eccs) / (1 - eccs),
      m = y / k0,
      mu = m / (this.R_MAJOR * (1 - eccs / 4 - 3 * eccs * eccs / 64 - 5 * eccs * eccs * eccs / 256)),
      phi1Rad = (mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu)),
      n1 = this.R_MAJOR / Math.sqrt(1 - eccs * Math.sin(phi1Rad) * Math.sin(phi1Rad)),
      t1 = Math.tan(phi1Rad) * Math.tan(phi1Rad),
      c1 = eccps * Math.cos(phi1Rad) * Math.cos(phi1Rad),
      r1 = this.R_MAJOR * (1 - eccs) / Math.pow(1 - eccs * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5),
      d = x / (n1 * k0),
      lng = ((longOrigin * this.DEG_TO_RAD + ((d - (1 + 2 * t1 + c1) * d * d * d / 6 + (5 - 2 * c1 + 28 * t1 - 3 * c1 * c1 + 8 * eccps + 24 * t1 * t1) * d * d * d * d * d / 120) / Math.cos(phi1Rad))) * this.RAD_TO_DEG),
      lat = ((phi1Rad - (n1 * Math.tan(phi1Rad) / r1) * (d * d / 2 - (5 + 3 * t1 + 10 * c1 - 4 * c1 * c1 - 9 * eccps) * d * d * d * d / 24 + (61 + 90 * t1 + 298 * c1 + 45 * t1 * t1 - 252 * eccps - 3 * c1 * c1) * d * d * d * d * d * d / 720)) * this.RAD_TO_DEG);

    return new L.LatLng(lat, lng);
  }
};

// Defining the utm crs
L.CRS.EPSG32633 = L.extend({}, L.CRS.Earth, {
  code: "EPSG:32633",
  projection: L.Projection.UTM33,
  transformation: new L.Transformation(1, 2500000, -1, 9045984),
  scale: function(zoom) {
    return 1 / (21664 / Math.pow(2, zoom));
  }
});

// Creating map with the utm crs
var map = new L.map('map', {
  crs: L.CRS.EPSG32633,
  minZoom: 0,
  maxZoom: 15,
  zoomControl: true
}).on("load", function(e) {
    // Adding utm basemap
var layer = new L.TileLayer.WMS('https://opencache.statkart.no/gatekeeper/gk/gk.open', {
  layers: "topo2",
  format: "image/png",
  transparent: false,
  attribution: "© Kartverket"
});

layer.addTo(e.target);

}).setView([65.276178, 16.683775], 3);

更新:这是我收到的错误的堆栈跟踪:

Uncaught Error: Invalid LatLng object: (NaN, NaN)
    at o.LatLng (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1d71787c7b7178695d2c332d332f" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:5:14154)
    at Object.unproject (http://fiddle.jshell.net/thL5bbnv/2/show/:105:12)
    at Object.pointToLatLng (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fa969f9b9c969f8ebacbd4cad4c8" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:5:18431)
    at e.unproject (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a1cdc4c0c7cdc4d5e1908f918f93" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:5:30126)
    at e.layerPointToLatLng (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f9959c989f959c8db9c8d7c9d7cb" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:5:30242)
    at e._fireDOMEvent (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f79b9296919b9283b7c6d9c7d9c5" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:6:3634)
    at e._handleDOMEvent (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a6cac3c7c0cac3d2e69788968894" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:6:3071)
    at HTMLDivElement.h (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="543831353238312014657a647a66" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:6:11270)
    at e._simulateEvent (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d3bfb6b2b5bfb6a793e2fde3fde1" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:8:31479)
    at e._onMove (https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="026e6763646e677642332c322c30" rel="noreferrer noopener nofollow">[email protected]</a>/dist/leaflet.js:8:31242)o.LatLng @ leaflet.js:5unproject @ (index):105pointToLatLng @ leaflet.js:5unproject @ leaflet.js:5layerPointToLatLng @ leaflet.js:5_fireDOMEvent @ leaflet.js:6_handleDOMEvent @ leaflet.js:6h @ leaflet.js:6_simulateEvent @ leaflet.js:8_onMove @ leaflet.js:8h @ leaflet.js:6
leaflet.js:5 Uncaught Error: Invalid LatLng object: (NaN, NaN)(…)o.LatLng @ leaflet.js:5unproject @ (index):105pointToLatLng @ leaflet.js:5unproject @ leaflet.js:5layerPointToLatLng @ leaflet.js:5_fireDOMEvent @ leaflet.js:6_handleDOMEvent @ leaflet.js:6h @ leaflet.js:6_simulateEvent @ leaflet.js:8_onMove @ leaflet.js:8h @ leaflet.js:6

我试图了解为什么捏合缩放失败,以及我可以采取哪些措施来解决该问题。有谁知道为什么使用自定义投影时捏合缩放会导致 Invalid LatLng 对象: (NaN, NaN) ?

最佳答案

好的,所以我已将问题追溯到对 map.getScaleZoom() 的调用:

debug screenshot

该函数直接取决于 map CRS 的 scale 方法,您已将其定义为

scale: function(zoom) {
   return 1 / (21664 / Math.pow(2, zoom));
}

现在,CRS 的 scale 方法必须实现 CRS 的 zoom 方法的inverseLeaflet API documentation for L.CRS 中是这样说的.

您没有在 L.CRS.EPSG32633 中定义 zoom 方法,但是...

L.CRS.EPSG32633 = L.extend({}, L.CRS.Earth, {

...您正在使用L.CRS.Earth.zoom()。因此,如果 x 的任何值的 scale(zoom(x)) 不为 1,事情就会失败。首先,缩放级别从 1.01 跃升至 -19.4。然后,LatLng 获取值 1e+233。然后你的投影代码接受它并开始喷出 InfinityNaN,一切最终都会陷入火焰。

修复L.CRS.EPSG32633方法的scalezoom,使其具有幂等性。


无论存在什么错误,我鼓励您使用 Proj4Leaflet 而不是自己实现投影代码。它经过测试、维护,并且支持所有已知的 EPSG 预测和 CRS。

关于javascript - 为什么在传单的自定义 crs 中捏合缩放不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40781644/

相关文章:

javascript - 如何验证具有正则表达式和一些可接受值的文本字段的值 "0"或 "00"或 "000"

javascript - jquery 高度返回 0

javascript - jQuery 触发鼠标移出事件

javascript - 在 ZoomStart 上获取当前位置

r - 使用 sf 包按多个点分割线

unit-testing - 我在哪里可以找到一些 GPS 单元测试数据?

javascript - 在滚动功能上,它使用 $(window) 而不是 $(document),为什么?

javascript - 我如何自定义传单弹出窗口的外观和感觉?

javascript - Leaflet ReactJS Map 未完全显示图 block

ruby-on-rails - 按最近的顺序排序-PostGIS,GeoRuby,spatial_adapter