leaflet上下卷帘

2023-12-27 17:42:31

leaflet上下卷帘

1.功能背景

本功能来自一个产品经理的奇怪需求,要求左右、上下可以切换的卷帘对比。
在这里插入图片描述

2.前置条件

Leaflet开源插件中,有一个卷帘插件
Github地址:https://github.com/digidem/leaflet-side-by-side
具体使用方法都又详细说明和示例,不在赘述,但是这个插件只有左右卷帘,下载代码后发现可以根据他的方法来修改为上下卷帘

3.功能开发

3.1.修改_updateClip

打开leaflet-side-by-side.js,搜索_updateClip方法,可以看到左右卷帘实现的方法。

_updateClip: function () {
    var map = this._map
    var nw = map.containerPointToLayerPoint([0, 0])
    var se = map.containerPointToLayerPoint(map.getSize())
    var clipX = nw.x + this.getPosition()
    var dividerX = this.getPosition()

    this._divider.style.left = dividerX + 'px'
    this.fire('dividermove', {x: dividerX})
    var clipLeft = 'rect(' + [nw.y, clipX, se.y, nw.x].join('px,') + 'px)'
    var clipRight = 'rect(' + [nw.y, se.x, se.y, clipX].join('px,') + 'px)'
    if (this._leftLayer) {
      this._leftLayer.getContainer().style.clip = clipLeft
    }
    if (this._rightLayer) {
      this._rightLayer.getContainer().style.clip = clipRight
    }
  },

左右卷帘原理是通过获取地图容器大小,然后根据中心点去切割两个图层的dom。原理并不难理解,根据源码拓展上下卷帘,修改后的代码:

_updateClip: function () {
    var map = this._map
    var nw = map.containerPointToLayerPoint([0, 0])
    var se = map.containerPointToLayerPoint(map.getSize())
    this.fire('dividermove', {x: dividerX})
    if (this.mod === "leftright") {
      var dividerX = this.getPosition()
      this._divider.style.left = dividerX + 'px'
      var clipX = nw.x + this.getPosition()
      var clipLeft = 'rect(' + [nw.y, clipX, se.y, nw.x].join('px,') + 'px)'
      var clipRight = 'rect(' + [nw.y, se.x, se.y, clipX].join('px,') + 'px)'
    } else if (this.mod === "topbottom"){
      var dividerY = this.getPositionY()
      this._divider.style.top = dividerY + 'px'
      var clipY = nw.y + this.getPositionY()
      var clipLeft = 'rect(' + [nw.y, se.x,clipY, nw.x].join('px,') + 'px)'
      var clipRight = 'rect(' + [clipY, se.x,se.y, nw.x].join('px,') + 'px)'
    }
    if (this._leftLayer) {
      this._leftLayer.getContainer().style.clip = clipLeft
    }
    if (this._rightLayer) {
      this._rightLayer.getContainer().style.clip = clipRight
    }
  },

我加了一个mod参数用于切换上下和左右卷帘。leftright为左右,topbottom为上下。

3.2.添加getPositionY方法

找到getPosition方法,这个方法是在拖动卷帘时计算左右卷帘裁剪像素的参数,我们可以根据该方法,添加一个拖动卷帘计算上下裁剪裁剪像素的参数的方法。

 getPositionY: function () {
    var rangeValue = this._range.value
    var offset = (0.5 - rangeValue) * (2 * this.options.padding + this.options.thumbSize)
    return this._map.getSize().y * rangeValue + offset
  },

3.3.添加上下卷帘range和divider

功能实现,还需要在添加一个横向的按钮和横线,用于拖动和分割上下图层。
找到addTo方法,可以看到相关方法。

 addTo: function (map) {
      this.remove()
      this._map = map
  
      var container = this._container = L.DomUtil.create('div', 'leaflet-sbs', map._controlContainer)
  
      this._divider = L.DomUtil.create('div', 'leaflet-sbs-divider', container)
      var range = this._range = L.DomUtil.create('input', 'leaflet-sbs-range', container)
      range.type = 'range'
      range.min = 0
      range.max = 1
      range.step = 'any'
      range.value = 0.5
      range.style.paddingLeft = range.style.paddingRight = this.options.padding + 'px'
      this._addEvents()
      this._updateLayers()
      return this
    },

根据该方法,修改为下面代码。

  addTo: function (map) {
    this.remove()
    this._map = map
    var container = this._container = L.DomUtil.create('div', 'leaflet-sbs', map._controlContainer)
    this._divider = L.DomUtil.create('div', 'leaflet-sbs-divider', container)
    var range = this._range = L.DomUtil.create('input', 'leaflet-sbs-range', container)
    range.type = 'range'
    range.min = 0
    range.max = 1
    range.step = 'any'
    range.value = 0.5
    range.style.paddingLeft = range.style.paddingRight = this.options.padding + 'px'
    this._addEvents()
    this._updateLayers()
    var clientWidth = document.getElementById('map').clientWidth
    var clientHeight = document.getElementById('map').clientHeight
    if (this.mod === "topbottom"){
      document.getElementsByClassName('leaflet-sbs-range')[0].style.transform = "rotate(90deg)"
      document.getElementsByClassName('leaflet-sbs-range')[0].style.width = clientHeight + 'px'
      document.getElementsByClassName('leaflet-sbs-range')[0].style.margin = '0 ' + (clientWidth - clientHeight)/2 + 'px'
      document.getElementsByClassName('leaflet-sbs-divider')[0].style.width = "100%"
      document.getElementsByClassName('leaflet-sbs-divider')[0].style.height = '4px'
      document.getElementsByClassName('leaflet-sbs-divider')[0].style.left = '0'
      this._map.on("resize", ()=>{
        clientWidth = document.getElementById('map').clientWidth
        clientHeight = document.getElementById('map').clientHeight
        document.getElementsByClassName('leaflet-sbs-range')[0].style.width = clientHeight + 'px'
        document.getElementsByClassName('leaflet-sbs-range')[0].style.margin = '0 ' + (clientWidth - clientHeight)/2 + 'px'
      })
    } else {
      clientWidth = this._map.getSize().x
      document.getElementsByClassName('leaflet-sbs-range')[0].style.width = clientWidth + 'px'
      this._map.on("resize", ()=>{
        clientWidth = this._map.getSize().x
        document.getElementsByClassName('leaflet-sbs-range')[0].style.width = clientWidth + 'px'
      })
    }
    return this
  },

其中也是踩了不少坑,最后的效果还可以。最后把改好的js和示例代码放在这里,如果有bug可以在评论区里面说一下。

示例下载链接 https://download.csdn.net/download/weixin_42066016/88669339

文章来源:https://blog.csdn.net/weixin_42066016/article/details/135244480
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。