类名 util/extend/map/L.Map.js
import * as L from '@mapgis/leaflet'
// @link https://github.com/Raruto/leaflet-rotate
/**
 * L.Map
 */
const mapProto = L.extend({}, L.Map.prototype)

L.Map.mergeOptions({ rotate: false, bearing: 0 })

L.Map.include({
  initialize(id, options) {
    // (HTMLElement or String, Object)
    if (options.rotate) {
      this._rotate = true
      this._bearing = 0
    }
    mapProto.initialize.call(this, id, options)
    if (this.options.rotate) {
      this.setBearing(this.options.bearing)
    }
  },

  containerPointToLayerPoint(point) {
    // (Point)
    if (!this._rotate) {
      return mapProto.containerPointToLayerPoint.call(this, point)
    }
    return L.point(point)
      .subtract(this._getMapPanePos())
      .rotateFrom(-this._bearing, this._getRotatePanePos())
      .subtract(this._getRotatePanePos())
  },

  getBounds() {
    if (!this._rotate) {
      return mapProto.getBounds.call(this)
    }
    const size = this.getSize()
    const topleft = this.layerPointToLatLng(
      this.containerPointToLayerPoint([0, 0])
    )
    const topright = this.layerPointToLatLng(
      this.containerPointToLayerPoint([size.x, 0])
    )
    const bottomright = this.layerPointToLatLng(
      this.containerPointToLayerPoint([size.x, size.y])
    )
    const bottomleft = this.layerPointToLatLng(
      this.containerPointToLayerPoint([0, size.y])
    )

    // Use LatLngBounds' build-in constructor that automatically extends the bounds to fit the passed points
    return new L.LatLngBounds([topleft, topright, bottomright, bottomleft])
  },

  layerPointToContainerPoint(point) {
    // (Point)
    if (!this._rotate) {
      return mapProto.layerPointToContainerPoint.call(this, point)
    }
    return L.point(point)
      .add(this._getRotatePanePos())
      .rotateFrom(this._bearing, this._getRotatePanePos())
      .add(this._getMapPanePos())
  },

  // Rotation methods
  // setBearing will work with just the 'theta' parameter.
  setBearing(theta) {
    if (!L.Browser.any3d || !this._rotate) {
      return
    }
    // 计算旋转容器位置,如果未定义,默认为[0,0]
    let rotatePanePos = this._getRotatePanePos()
    const halfSize = this.getSize().divideBy(2)
    const mapPanePos = this._getMapPanePos()
    // 计算新的旋转点
    this._pivot = mapPanePos.clone().multiplyBy(-1).add(halfSize)
    // 还原旋转位置
    rotatePanePos = rotatePanePos.rotateFrom(-this._bearing, this._pivot)
    this._bearing = theta * L.DomUtil.DEG_TO_RAD // TODO: mod 360
    // 计算新的旋转容器位置
    this._rotatePanePos = rotatePanePos.rotateFrom(this._bearing, this._pivot)
    // 作用旋转容器
    L.DomUtil.setPositionBearing(
      this._rotatePane,
      rotatePanePos,
      this._bearing,
      this._pivot
    )
    this.fire('rotate')
  },

  getBearing() {
    return this._bearing * L.DomUtil.RAD_TO_DEG
  },

  _initPanes() {
    const panes = (this._panes = {})
    this._paneRenderers = {}

    // @section
    //
    // Panes are DOM elements used to control the ordering of layers on the map. You
    // can access panes with [`map.getPane`](#map-getpane) or
    // [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
    // [`map.createPane`](#map-createpane) method.
    //
    // Every map has the following default panes that differ only in zIndex.
    //
    // @pane mapPane: HTMLElement = 'auto'
    // Pane that contains all other map panes

    this._mapPane = this.createPane('mapPane', this._container)
    L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0))

    if (this._rotate) {
      this._rotatePane = this.createPane('rotatePane', this._mapPane)
      this._norotatePane = this.createPane('norotatePane', this._mapPane)

      // @pane tilePane: HTMLElement = 2
      // Pane for tile layers
      this.createPane('tilePane', this._rotatePane)
      // @pane overlayPane: HTMLElement = 4
      // Pane for overlays like polylines and polygons
      this.createPane('overlayPane', this._rotatePane)

      // @pane shadowPane: HTMLElement = 5
      // Pane for overlay shadows (e.g. marker shadows)
      this.createPane('shadowPane', this._norotatePane)
      // @pane markerPane: HTMLElement = 6
      // Pane for marker icons
      this.createPane('markerPane', this._norotatePane)
      // @pane tooltipPane: HTMLElement = 650
      // Pane for tooltips.
      this.createPane('tooltipPane', this._norotatePane)
      // @pane popupPane: HTMLElement = 700
      // Pane for popups.
      this.createPane('popupPane', this._norotatePane)
    } else {
      // @pane tilePane: HTMLElement = 2
      // Pane for tile layers
      this.createPane('tilePane')
      // @pane overlayPane: HTMLElement = 4
      // Pane for overlays like polylines and polygons
      this.createPane('overlayPane')
      // @pane shadowPane: HTMLElement = 5
      // Pane for overlay shadows (e.g. marker shadows)
      this.createPane('shadowPane')
      // @pane markerPane: HTMLElement = 6
      // Pane for marker icons
      this.createPane('markerPane')
      // @pane tooltipPane: HTMLElement = 650
      // Pane for tooltips.
      this.createPane('tooltipPane')
      // @pane popupPane: HTMLElement = 700
      // Pane for popups.
      this.createPane('popupPane')
    }

    if (!this.options.markerZoomAnimation) {
      L.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide')
      L.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide')
    }
  },

  // @method rotatedPointToMapPanePoint(point: Point): Point
  // Converts a coordinate from the rotated pane reference system
  // to the reference system of the not rotated map pane.
  rotatedPointToMapPanePoint(point) {
    // 旋转容器->不旋转容器
    return L.point(point).rotate(this._bearing)._add(this._getRotatePanePos())
  },

  // @method mapPanePointToRotatedPoint(point: Point): Point
  // Converts a coordinate from the not rotated map pane reference system
  // to the reference system of the rotated pane.
  mapPanePointToRotatedPoint(point) {
    // 不旋转容器->旋转容器
    return L.point(point)
      ._subtract(this._getRotatePanePos())
      .rotate(-this._bearing)
  },

  // offset of the specified place to the current center in pixels
  _getCenterOffset(latlng) {
    let centerOffset = mapProto._getCenterOffset.call(this, latlng)
    if (this._rotate) {
      centerOffset = centerOffset.rotate(this._bearing)
    }
    return centerOffset
  },

  _getRotatePanePos() {
    return this._rotatePanePos || new L.Point(0, 0)
  },

  _getNewPixelOrigin(center, zoom) {
    // 计算旋转后的像素原点
    const viewHalf = this.getSize()._divideBy(2)
    if (!this._rotate) {
      mapProto._getNewPixelOrigin.call(this, center, zoom)
    }
    return this.project(center, zoom)
      .rotate(this._bearing)
      ._subtract(viewHalf)
      ._add(this._getMapPanePos())
      ._add(this._getRotatePanePos())
      .rotate(-this._bearing)
      ._round()
  },

  _handleGeolocationResponse(pos) {
    const lat = pos.coords.latitude
    const lng = pos.coords.longitude
    // TODO: use mapProto._handleGeolocationResponse
    const hdg = pos.coords.heading
    const latlng = new L.LatLng(lat, lng)
    const bounds = latlng.toBounds(pos.coords.accuracy)
    const options = this._locateOptions

    if (options.setView) {
      const zoom = this.getBoundsZoom(bounds)
      this.setView(
        latlng,
        options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom
      )
    }

    const data = {
      latlng,
      bounds,
      timestamp: pos.timestamp,
      // TODO: use mapProto._handleGeolocationResponse
      heading: hdg
    }

    for (const i in pos.coords) {
      if (typeof pos.coords[i] === 'number') {
        data[i] = pos.coords[i]
      }
    }

    // @event locationfound: LocationEvent
    // Fired when geolocation (using the [`locate`](#map-locate) method)
    // went successfully.
    this.fire('locationfound', data)
  }
})
构造函数
成员变量
方法
事件