在微信小程序中使用开源地图组件leafletwx实现可无限放大的地图

leafletwx是基于leaflet,使用微信原生组件开发的一套开源地图组件,目标是替换小程序的原生map组件,项目开源地址:leatletwx

本示例开源地址在leafletwx的qqmap_infinite页面。

本示例使用的其他组件:
1.本示例借鉴了leaflet插件​Leaflet.TileLayer.Fallback​(以下称为Fallback)


背景及原理:

国内地图瓦片服务商提供的放大级数一般在0-18级,例如QQ地图、百度地图、高德地图、天地图等等,建筑物较小而marker较多时,会导致marker过于拥挤,而无法通过继续放大地图进行分散。

本示例主要思想是当地图放到到瓦片服务器的最大级别时,采用放大最大一级的图片大小来实现继续放大地图的效果。例如:QQ地图,原始瓦片图片的大小为256*256像素,最大18级。当放大到第19级时,将第18级图片放大到512*512;当放大到第20级时,将18级图片放大到1024*1024。

具体实现:

qqlayers.infinite.js

var L = require('../../components/zhgeo/leafletwx')


L.TileLayer.TXMapTileLayer = L.TileLayer.extend({
  options: {
    minNativeZoom: 0
  },

  initialize: function (urlTemplate, options) {
    L.TileLayer.prototype.initialize.call(this, urlTemplate, options);
  },


  createTile: function (coords, done) {
    var tile = L.TileLayer.prototype.createTile.call(this, coords, done);
    tile._originalCoords = coords;
    tile._originalSrc = tile.src;
    return tile;
  },


  _clampZoom: function (zoom) {
    var options = this.options;
    if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {
      return options.minNativeZoom;
    }  
    return zoom;
  },


  _addTile: function (coords) {
    var tile = L.TileLayer.prototype._addTile.call(this, coords);
    var options = this.options;
    var zoom = coords.z;
    if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {
      return this._tileOutError(tile);
    }
    return tile;
  },

  _createCurrentCoords: function (originalCoords) {
    var currentCoords = this._wrapCoords(originalCoords);
    currentCoords.fallback = true;
    return currentCoords;
  },

  _tileOutError: function (tile) {
    var options = this.options;
    var layer = this, // `this` is bound to the Tile Layer in L.TileLayer.prototype.createTile.
        originalCoords = tile._originalCoords,
        currentCoords = tile._currentCoords = tile._currentCoords || layer._createCurrentCoords(originalCoords),
        fallbackZoom = options.maxNativeZoom,
        scale = Math.pow(2, (originalCoords.z - options.maxNativeZoom)),
        tileSize = layer.getTileSize(),
        newUrl, top, left;


    // Modify tilePoint for replacement img.
    currentCoords.z = fallbackZoom;
    currentCoords.x = Math.floor(currentCoords.x / scale);
    currentCoords.y = Math.floor(currentCoords.y / scale);


    // Generate new src path.
    newUrl = layer.getTileUrl(currentCoords);


    // Zoom replacement img.
    tile.width = (tileSize.x * scale) + 'px';
    tile.height = (tileSize.y * scale) + 'px';


    // Compute margins to adjust position.
    top = (originalCoords.y - currentCoords.y * scale) * tileSize.y;
    tile.top = (tile.top - top);
    left = (originalCoords.x - currentCoords.x * scale) * tileSize.x;
    tile.left = (tile.left - left);

    // Crop (clip) image.
    // `clip` is deprecated, but browsers support for `clip-path: inset()` is far behind.
    // http://caniuse.com/#feat=css-clip-path
    // tile.clip = 'rect(' + top + 'px ' + (left + tileSize.x) + 'px ' + (top + tileSize.y) + 'px ' + left + 'px)';
    tile.src = newUrl;
    return tile;
  },

  getTileUrl: function (tilePoint) {
      var urlArgs,
          getUrlArgs = this.options.getUrlArgs;


      if (getUrlArgs) {
          var urlArgs = getUrlArgs(tilePoint);
      } else {
          urlArgs = {
              z: tilePoint.z,
              x: tilePoint.x,
              y: tilePoint.y,
              s: this._getSubdomain(tilePoint)
          };
      }
      if (this._map && !this._map.options.crs.infinite) {
        var invertedY = this._globalTileRange.max.y - tilePoint.y;
        if (this.options.tms) {
          urlArgs['y'] = invertedY;
        }
        urlArgs['-y'] = invertedY;
      }
      return L.Util.template(this._url, L.extend(urlArgs, this.options));
  }
});

L.tileLayer.txMapTileLayer = function (type, options) {
  var getUrlArgs, url, subdomain = '012';
  if (type == 'Normal') { //地图带路线轮廓 有轮廓/有路线
      url = 'http://rt1.map.gtimg.com/realtimerender/?z={z}&x={x}&y={y}&type=vector&style=1&v=1.1.1'; //ok //普通地图
      getUrlArgs = function (tilePoint) {
          return {
              //地图
              z: tilePoint.z,
              x: tilePoint.x,
              y: Math.pow(2, tilePoint.z) - 1 - tilePoint.y
          };
      }
  } else if (type == 'Satellite') { //卫星图,无轮廓/无路线
      url = 'http://p3.map.gtimg.com/sateTiles/{z}/{x}/{y}/{G}_{H}.jpg?version=229';
      getUrlArgs = function (tilePoint) {
          return {
              //卫星图
              z: tilePoint.z,
              x: Math.floor(tilePoint.x / 16),
              y: Math.floor((Math.pow(2, tilePoint.z) - 1 - tilePoint.y) / 16),
              G: tilePoint.x,
              H: Math.pow(2, tilePoint.z) - 1 - tilePoint.y
          };
      }
  }  else if (type=='Landform') {//地形图,有轮廓/有路线
      url = 'http://rt1.map.gtimg.com/tile?z={z}&x={x}&y={y}&type=vector&styleid=3&version=263' //ok //地形地图
      getUrlArgs = function (tilePoint) {
          return {
              //地形图
              z: tilePoint.z,
              x: tilePoint.x,
              y: Math.pow(2, tilePoint.z) - 1 - tilePoint.y
          };
      }
  }
  options = L.extend(options, {
      subdomain:'012',
      getUrlArgs:getUrlArgs,
  })
  return new L.TileLayer.TXMapTileLayer(url, options);
};


qqmap_infinite.js

// pages/qqmap/qqmap_infinite.js
var L = require('../../components/zhgeo/leafletwx')
require('./qqlayers.infinite')
import {createMap} from '../../components/zhgeo/base.map'
import {DefaultIcons} from '../../components/zhgeo/config.js';
const defaultIcons = new DefaultIcons();

Page({
  onLoad(options) {
    const container = this.selectComponent('#qq-leafletwx')
    let min_zoom = 17
    let max_zoom = 20
    createMap(container,  {
      }, function(map) {
      console.log(map)
      var Normal = L.tileLayer.txMapTileLayer("Normal", {        
        minNativeZoom: 3,   // 瓦片服务器最小级别
        maxNativeZoom: 18,  // 瓦片服务器最大级别
        minZoom: min_zoom, // 用户地图最小级别
        maxZoom: max_zoom, // 用户地图最大级别
      }); //调用 腾讯地图
      Normal.addTo(map)
      map.setView([31.294516,120.625814], 18);
      // 限定地图范围
      var corner1 = L.latLng(31.29571,120.623941),
      corner2 = L.latLng(31.289586,120.63455),
      bounds = L.latLngBounds(corner1, corner2);
      map.setMaxBounds(bounds);

      // 添加marker
      let m = L.marker([31.2948516,120.625814], {
        src: defaultIcons.locationNow,
        width: 32,
        height: 32,
        showInCenter: false,
      }).addTo(map);
      // 删除marer
      // map.removeLayer( m );

      // popup      
      m.bindPopup("这是个弹框", {
        width: 60,
      });


      // 添加路线      
      let l = L.polyline([[31.293516,120.625814], [31.294516,120.625214], [31.294516,120.626114]], {color: '#ff0000', weight: 3}).addTo(map);
      // 删除线路
      // map.removeLayer( l );


      // 添加区域
      let y = L.polygon([[31.2930516,120.625814], [31.2940516,120.625214], [31.2940516,120.626114]], {color: '#ff0000', weight: 4}).addTo(map);
      // 删除区域
      // map.removeLayer( y );
      
      m = L.marker([31.2944516,120.625814], {
        src: defaultIcons.location,
        width: 32,
        height: 32,
        title: '沧浪亭',
        showFooter: true,
        footerWidth: 60,
        footerPosition: 1,  // 0:左 1:右 2:上 3:下
        left_badge: '左', //  为空时不显示
        right_badge: '右',  // 为空时不显示
        showInCenter: true, // ture: 图标中心在POI中心 false:图标下边缘中心位于POI中心
      }).addTo(map);
      // 删除线路
      // map.removeLayer( l );
    });
  },
})


效果展示(QQ地图第19级):

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卓伙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值