LeafletJS - 使用本地文件系统缓存瓦片

3

我正在实现一个 Cordova 应用程序 (3.2),我想要在其中使用 LeafletJS 和一个地图瓦片提供者以及一个本地文件系统缓存。

我的总体做法如下:

  • 扩展 Leaflet TileLayer
  • 覆盖 _loadTile 方法,从本地文件系统或远程获取瓦片

我的代码:

var StorageTileLayer = L.TileLayer.extend({
log: function (text) {
  if (this.options.log)
    this.options.log(text);
  else
    console.log("[StorageTileLayer]: " + text);
},
_setUpTile: function (tile, key, value, cache) {
  try {
    tile._layer = this;
    tile.onload = this._tileOnLoad;
    tile.onerror = this._tileOnError;

    this._adjustTilePoint(tile);
    tile.src = value;
    this.fire('tileloadstart', {
      tile: tile,
      url: tile.src
    });

    this.log("Setting url to " + tile.src);
  }
  catch (e) {
    this.log("ERROR in setUpTile: " + e.message);
  }
},

_loadTile: function (tile, tilePoint) {
  this._adjustTilePoint(tilePoint);
  var key = tilePoint.z + ',' + tilePoint.y + ',' + tilePoint.x;
  var self = this;
  var tileUrl = self.getTileUrl(tilePoint);
  console.log(tileUrl);
  console.log(typeof tileUrl);
  if (this.options.storage) {
    this.log("Load Tile with storage");
    this.options.storage.get(key, tileUrl).then(function (value) {
      self.log("Tile URL to load: " + value.url);
      self._setUpTile(tile, key, value.url, true);
    });
  } else {
    this.log("Load Tile without storage");
    self._setUpTile(tile, key, tileUrl, false);
  }
}

});

options.storage 是一个具有方法 get(key, remoteUrl) 的存储器,该方法返回本地文件存储中的缓存瓦片(实现得很好,所以这里不是问题),或者返回远程URL,但会在后台下载瓷砖,因此下一次调用时将在本地文件存储中可用。

不幸的是,当我使用 Charles (Web Debugging Proxy) 时,可以看到虽然本地地图瓦片已被加载(从日志中可以看到),但仍有几个请求发送到地图瓦片提供程序。

有人知道我做错了什么,还需要在我的 StorageTileLayer 中覆盖什么才能阻止对远程的调用吗?真正的问题是,地图也应该在离线模式下工作,但事实并非如此。

感谢您的帮助。

环境中的库:

  • Leaflet (0.7.3)
  • angularJS (1.2.16)
  • Cordova (3.2)

嗨,我正在处理一个非常类似的问题,即Chrome应用程序不允许远程图像调用。我需要停止远程调用,检查是否已经下载到本地文件系统,如果没有,则执行XhrHttpRrequest来获取瓦片。你有成功让你的版本工作吗? - user1541413
1个回答

4
我基本上用这段代码修复了它(angular js):
(function (window, L) {
  var isDebug = false;
  var StorageTileLayer = L.TileLayer.extend({

    log: function (text) {
      if (!isDebug)
        return;
      if (this.options.log)
        this.options.log(text);
      else
        console.log("[StorageTileLayer]: " + text);
    },
    _setUpTile: function (tile, key, value, cache) {
      try {
        tile._layer = this;
        tile.onload = this._tileOnLoad;
        tile.onerror = this._tileOnError;

        this._adjustTilePoint(tile);
        tile.src = value;
        this.fire('tileloadstart', {
          tile: tile,
          url: tile.src
        });
      }
      catch (e) {
        this.log("ERROR in setUpTile: " + e.message);
      }
    },

    _loadTile: function (tile, tilePoint) {
      this._adjustTilePoint(tilePoint);
      var key = tilePoint.z + ',' + tilePoint.y + ',' + tilePoint.x;
      var self = this;
      var tileUrl = self.getTileUrl(tilePoint);
      if (isNaN(tilePoint.x) || isNaN(tilePoint.y)) {
        this.log("TilePoint x or y is nan: " + tilePoint.x + "-" + tilePoint.y);
        return;
      }
      if (this.options.storage) {
        this.options.storage.get(key, tileUrl).then(function (value) {
          self.log("Tile URL to load: " + value.url);
          self._setUpTile(tile, key, value.url, true);
        });
      } else {
        this.log("Load Tile without storage");
        self._setUpTile(tile, key, tileUrl, false);
      }
    }
  });

  window.StorageTileLayer = StorageTileLayer;
})(window, L);

将瓦片图层添加到 Leaflet 地图是非常重要的一步!您需要防止负载均衡器为每个瓦片获取不同的 URL。我通过将瓦片图层的 URL 设置为固定值来实现:

var url = 'https://a.tiles.mapbox.com/v3/<<YOUR ACCESS CODE>>/{z}/{x}/{y}.png';
    var layer = new StorageTileLayer(url, {
      storage: TileStorage
    });

当然,在我的情况下,您仍然需要实现TileStorage。它有一个单一的方法get(key, url),并返回一个被解决为本地可用文件的$q-defer。如果文件在本地存储中不可用,则会下载该文件,然后解决承诺。
不幸的是,这个TileStorage并不是公开可用的,因为它是我们公司内部开发的,所以我不能分享它。
尽管如此,我希望这能对您有所帮助。

你怎样将瓦片图层与leaflet地图联系起来? - TimoSolo
你需要做的总是:layer.addTo(map); 如何创建图层可以在上面的帖子中看到。 - Sebastian
啊,谢谢!我正在使用Angular指令,所以花了一些时间来弄清楚如何获取地图: leafletData.getMap().then(function(map) { ... - TimoSolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接