    import * as L from '@mapgis/leaflet'
    // @link https://github.com/Raruto/leaflet-rotate
    /**
     * L.GridLayer
     */
    const gridLayerProto = L.extend({}, L.GridLayer.prototype)

    L.GridLayer.include({
      getEvents() {
        const events = gridLayerProto.getEvents.call(this)
        if (this._map._rotate && !this.options.updateWhenIdle) {
          if (!this._onRotate) {
            this._onRotate = L.Util.throttle(
              this._onMoveEnd,
              this.options.updateInterval,
              this
            )
          }
          events.rotate = this._onRotate
        }
        return events
      },
      _initTile(tile) {
        // 解决瓦片白边的问题
        gridLayerProto._initTile.call(this, tile)
        const tileSize = this.getTileSize()
        tile.style.width = `${tileSize.x + 1}px`
        tile.style.height = `${tileSize.y + 1}px`
      },

      _getTiledPixelBounds(center) {
        if (!this._map._rotate) {
          return gridLayerProto._getTiledPixelBounds.call(this, center)
        }

        const map = this._map
        const mapZoom = map._animatingZoom
          ? Math.max(map._animateToZoom, map.getZoom())
          : map.getZoom()
        const scale = map.getZoomScale(mapZoom, this._tileZoom)
        const pixelCenter = map.project(center, this._tileZoom).floor()
        const size = map.getSize()
        const halfSize = new L.Bounds([
          map.containerPointToLayerPoint([0, 0]).floor(),
          map.containerPointToLayerPoint([size.x, 0]).floor(),
          map.containerPointToLayerPoint([0, size.y]).floor(),
          map.containerPointToLayerPoint([size.x, size.y]).floor()
        ])
          .getSize()
          .divideBy(scale * 2)

        return new L.Bounds(
          pixelCenter.subtract(halfSize),
          pixelCenter.add(halfSize)
        )
      },
      // 刷新方法
      refresh() {
        for (const key in this._tiles) {
          const tile = this._tiles[key]
          this._replaceTile(tile, this._level.el)
        }
      },
      _replaceTile(oldTile, container) {
        const coords = oldTile.coords
        const self = this
        const tilePos = this._getTilePos(coords)
        const key = this._tileCoordsToKey(coords)
        const tileReady = function (coords, err, tile) {
          L.DomUtil.remove(oldTile.el)
          self._tileReady(coords, err, tile)
        }
        const tile = this.createTile(
          this._wrapCoords(coords),
          L.Util.bind(tileReady, this, coords)
        )

        this._initTile(tile)

        // if createTile is defined with a second argument ("done" callback),
        // we know that tile is async and will be ready later; otherwise
        if (this.createTile.length < 2) {
          // mark tile as ready, but delay one frame for opacity animation to happen
          L.Util.requestAnimFrame(
            L.Util.bind(this._tileReady, this, coords, null, tile)
          )
        }

        L.DomUtil.setPosition(tile, tilePos)

        // save tile in cache
        this._tiles[key] = {
          el: tile,
          coords,
          current: true
        }

        tile.style.transition = 'opacity 0.5s ease-in-out'

        container.appendChild(tile)
      }
    })