leaflet加载leaflet-canvas-marker图层时出现偏移问题解决

23 篇文章 0 订阅
6 篇文章 0 订阅

问题背景:
    用leaflet加载高德地图,对地图进行操作(如:放大、缩小或移动)后,再动态加载leaflet-canvas-marker图层,图层第一次(初始)叠加在地图上有偏移,对地图进行操作(如:放大、缩小或移动)后,偏移消失。[特别注意要先对地图进行操作,再加载leaflet-canvas-marker图层,否则问题不能重现]。如下图:
    第一次(初始)叠加位置:
    对地图进行操作后位置:
    初步判定为leaflet-canvas-marker的一个Bug。
问题解决:动态加载leaflet-canvas-marker图层后刷新下地图。由于没找到leaflet中Map对象刷新方法,取巧采用map.setView(map.getCenter());实现leaflet中Map对象刷新,解决以上问题。
源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>leaflet canvas marker test</title>
    <!-- <link href="leaflet.css" type="text/css" rel="stylesheet"/>
    <script src="leaflet.js"></script> -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <!-- https://github.com/tontita/Leaflet.KoreanTmsProviders/blob/master/src/Leaflet.KoreanTmsProviders.js -->
    <script src="leaflet.ChineseTmsProviders.js"></script>
</head>
<body>
<div><button onclick="addMarkers()">Add Layer</button></div>
<div id="map" style="width: 100vw;height: 100vh">
</div>
<!-- <script src="leaflet.canvas-markers.js"></script> -->
<script src="https://unpkg.com/leaflet-canvas-marker@0.2.1"></script>
<script>
L.TileLayer.ChinaProvider = L.TileLayer.extend({

    initialize: function (type, options) { // (type, Object)
        var providers = L.TileLayer.ChinaProvider.providers;

        var parts = type.split('.');

        var providerName = parts[0];
        var mapName = parts[1];
        var mapType = parts[2];

        var url = providers[providerName][mapName][mapType];
        options.subdomains = providers[providerName].Subdomains;
        options.key = options.key || providers[providerName].key;
        L.TileLayer.prototype.initialize.call(this, url, options);
    }
});

L.TileLayer.ChinaProvider.providers = {
    TianDiTu: {
        Normal: {
            Map: "http://t{s}.tianditu.com/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk={key}",
            Annotion: "http://t{s}.tianditu.com/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk={key}"
        },
        Satellite: {
            Map: "http://t{s}.tianditu.com/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk={key}",
            Annotion: "http://t{s}.tianditu.com/DataServer?T=cia_w&X={x}&Y={y}&L={z}&tk={key}"
        },
        Terrain: {
            Map: "http://t{s}.tianditu.com/DataServer?T=ter_w&X={x}&Y={y}&L={z}&tk={key}",
            Annotion: "http://t{s}.tianditu.com/DataServer?T=cta_w&X={x}&Y={y}&L={z}&tk={key}"
        },
        Subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
        key: "天地图的token key"
    },

    Mapbox: {
        streets: {
            streets: "https://api.tiles.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.png?access_token={key}"
        },
        light: {
            light: "https://api.tiles.mapbox.com/v4/mapbox.light/{z}/{x}/{y}.png?access_token={key}"
        },
        dark: {
            dark: "https://api.tiles.mapbox.com/v4/mapbox.dark/{z}/{x}/{y}.png?access_token={key}"
        },
        outdoors: {
            outdoors: "https://api.tiles.mapbox.com/v4/mapbox.outdoors/{z}/{x}/{y}.png?access_token={key}"
        },
        satellite: {
            satellite: "https://api.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.png?access_token={key}"
        },
        Subdomains: [],
        key: "mapbox的token key"
    },


    GaoDe: {
        Normal: {
            Map: 'http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
        },
        Satellite: {
            Map: 'http://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
            Annotion: 'http://webst0{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}'
        },
        Subdomains: ["1", "2", "3", "4"]
    },

    Google: {
        Normal: {
            Map: "http://www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}"
        },
        Satellite: {
            Map: "http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}"
        },
        Subdomains: []
    },

    Geoq: {
        Normal: {
            Map: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}",
            PurplishBlue: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
            Gray: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetGray/MapServer/tile/{z}/{y}/{x}",
            Warm: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetWarm/MapServer/tile/{z}/{y}/{x}",
        },
        Theme: {
            Hydro: "http://thematic.geoq.cn/arcgis/rest/services/ThematicMaps/WorldHydroMap/MapServer/tile/{z}/{y}/{x}"
        },
        Subdomains: []
    },

    OSM: {
        Normal: {
            Map: "http://{s}.tile.osm.org/{z}/{x}/{y}.png",
        },
        Subdomains: ['a', 'b', 'c']
    },

    OfflineMap: {
        Normal: {
            Map: "http://127.0.0.1:8081/offlineMap/{z}/{x}/{y}.png",
        },
        Subdomains: []
    }

};

L.tileLayer.chinaProvider = function (type, options) {
    return new L.TileLayer.ChinaProvider(type, options);
};

    /**  
     * 智图地图内容  
    var normalm1 = L.tileLayer.chinaProvider('Geoq.Normal.Map', {  
        maxZoom: 18,  
        minZoom: 5  
    });  
    var normalm2 = L.tileLayer.chinaProvider('Geoq.Normal.Color', {  
        maxZoom: 18,  
        minZoom: 5  
    });  
    var normalm3 = L.tileLayer.chinaProvider('Geoq.Normal.PurplishBlue', {  
        maxZoom: 18,  
        minZoom: 5  
    });  
    var normalm4 = L.tileLayer.chinaProvider('Geoq.Normal.Gray', {  
        maxZoom: 18,  
        minZoom: 5  
    });  
    var normalm5 = L.tileLayer.chinaProvider('Geoq.Normal.Warm', {  
        maxZoom: 18,  
        minZoom: 5  
    });  
    var normalm6 = L.tileLayer.chinaProvider('Geoq.Normal.Cold', {  
        maxZoom: 18,  
        minZoom: 5  
    });  
     */  

    /**  
     * 天地图内容  
     */  
    var normalm = L.tileLayer.chinaProvider('TianDiTu.Normal.Map', {  
            maxZoom: 18,  
            minZoom: 5  
        }),
        normala = L.tileLayer.chinaProvider('TianDiTu.Normal.Annotion', {  
            maxZoom: 18,  
            minZoom: 5  
        }),
        imgm = L.tileLayer.chinaProvider('TianDiTu.Satellite.Map', {  
            maxZoom: 18,  
            minZoom: 5  
        }),
        imga = L.tileLayer.chinaProvider('TianDiTu.Satellite.Annotion', {  
            maxZoom: 18,  
            minZoom: 5  
        });
  
    var normal = L.layerGroup([normalm, normala]),  
        image = L.layerGroup([imgm, imga]);  
    /**  
     * 谷歌  
    var normalMap = L.tileLayer.chinaProvider('Google.Normal.Map', {  
            maxZoom: 18,  
            minZoom: 5  
        }),  
        satelliteMap = L.tileLayer.chinaProvider('Google.Satellite.Map', {  
            maxZoom: 18,  
            minZoom: 5  
        });
     */  

    /**  
     * 高德地图  
     */  
    var Gaode = L.tileLayer.chinaProvider('GaoDe.Normal.Map', {  
        maxZoom: 18,  
        minZoom: 5  
    });
    var Gaodimgem = L.tileLayer.chinaProvider('GaoDe.Satellite.Map', {  
        maxZoom: 18,  
        minZoom: 5  
    });
    var Gaodimga = L.tileLayer.chinaProvider('GaoDe.Satellite.Annotion', {  
        maxZoom: 18,  
        minZoom: 5  
    });
    var Gaodimage = L.layerGroup([Gaodimgem, Gaodimga]);  

    /**  
     * 离线地图  
     */  
     var OfflineImage = L.tileLayer.chinaProvider('OfflineMap.Normal.Map', {  
        maxZoom: 10,  
        minZoom: 4
    });

    //mapbox
    var mb1 = L.tileLayer.chinaProvider('Mapbox.streets.streets',{
        maxZoom: 18,
        minZoom: 5
    });
    var mb2 = L.tileLayer.chinaProvider('Mapbox.light.light',{
        maxZoom: 18,
        minZoom: 5
    });
    var mb3 = L.tileLayer.chinaProvider('Mapbox.dark.dark',{
        maxZoom: 18,
        minZoom: 5
    });
    var mb4 = L.tileLayer.chinaProvider('Mapbox.outdoors.outdoors',{
        maxZoom: 18,
        minZoom: 5
    });
    var mb5 = L.tileLayer.chinaProvider('Mapbox.satellite.satellite',{
        maxZoom: 18,
        minZoom: 5
    });
  
    var baseLayers = {  
        //"智图地图": normalm1,  
        //"智图多彩": normalm2,  
        //"智图午夜蓝": normalm3,  
        //"智图灰色": normalm4,  
        //"智图暖色": normalm5,  
        //"智图冷色": normalm6,  
        "天地图": normal,  
        "天地图影像": image,  
        //"谷歌地图": normalMap,  
        //"谷歌影像": satelliteMap,  
        "高德地图": Gaode,  
        "高德影像": Gaodimage,
        //"图盒街道": mb1,
        //"图盒亮": mb2,
        //"图盒暗": mb3,
        //"图盒户外": mb4,
        //"图盒卫星": mb5,
    }

    var centerPoint = L.CRS.EPSG3857.project(L.latLng(39.906888, 116.397497))
    
    var map = L.map("map", {
        center: [39.906888, 116.397497], // 默认地图中心 L.CRS.EPSG3857.project(L.latLng(latlng.lat, latlng.lng))
        maxBounds: L.latLngBounds(L.latLng(53.55, 73.66), L.latLng(3.86, 135.05)), // 地图最大显示范围 L.latLng(53.55, 73.66), L.latLng(3.86, 135.05)
        crs: L.CRS.EPSG3857, 
        zoom: 5, //12
        layers: [Gaode], //Gaodimage  OfflineImage  Gaode
        detectRetina: true,
        preferCanvas: true,
        zoomControl: false  
    });
  
    //L.control.layers(baseLayers, null).addTo(map);
    L.control.zoom({
        zoomInTitle: '放大',
        zoomOutTitle: '缩小'
    }).addTo(map);


    function addMarkers(){
        var ciLayer = L.canvasIconLayer({}).addTo(map);
        let icon = L.icon({
            //iconUrl: 'data-icon.png',
            iconUrl: "data:image/svg+xml,%3Csvg t='1629184236836' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3737' width='48' height='48'%3E%3Cpath d='M736 32h-448c-54.4 0-96 41.6-96 96v768c0 54.4 41.6 96 96 96h448c54.4 0 96-41.6 96-96v-768c0-54.4-41.6-96-96-96z m-480 96c0-19.2 12.8-32 32-32h448c19.2 0 32 12.8 32 32v64h-512v-64z m512 768c0 19.2-12.8 32-32 32h-448c-19.2 0-32-12.8-32-32v-640h512v640z' p-id='3738'%3E%3C/path%3E%3Cpath d='M512 832m-32 0a32 32 0 1 0 64 0 32 32 0 1 0-64 0Z' p-id='3739'%3E%3C/path%3E%3C/svg%3E",
            iconSize: [20, 20],
            iconAnchor: [10, 20]
        });
        let markers = [];
        for (var i = 0; i < 3; i++) {
            var marker = L.marker([39.906888 + Math.random()*1.8, 116.397497 + Math.random()*3.6], {icon: icon}).bindPopup('我是' + i + '号站点');
            markers.push(marker);
        }
        ciLayer.addLayers(markers);
        map.setView(map.getCenter());
    }
</script>
</body>
</html>


备注:加载leaflet原生canvas图层没有偏移问题,测试代码如下:

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas test</title>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/leaflet/1.7.1/leaflet.min.css"/>
    <script src="https://cdn.bootcdn.net/ajax/libs/leaflet/1.7.1/leaflet.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/zrender/5.2.1/zrender.js"></script>
    <style>
      *{
        margin: 0;
      }
      html, body, .map-wrapper, #map{
        height: 100%;
        width: 100%;
      }
      .map-wrapper {
        position: relative;
      }
      .image-coordinates-container {
        position: absolute;
        left: 8px;
        bottom: 8px;
        z-index: 1000;
        color: #666;
      }
      .canvas-layer {
        position: absolute;
        right: 8px;
        top: 8px;
        z-index: 1000;
        color: #666;
        background-color: whitesmoke;
      }
    </style>
  </head>
  <body>
    <div class="map-wrapper">
      <div id="map"></div>
      <div id="imageCoordinates" class="image-coordinates-container"></div>
      <div id="canvasLayer" class="canvas-layer"><span onclick="addCanvas();">Add canvas layer</span></div>
    </div>
    <script>
      const center = [37.7, 112.7];
      const map = L.map('map', {
        center:center,
        zoom: 6,
      });

      //Add GaoDe map layer
      L.tileLayer(
        'https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
        {
          subdomains: '1234',
          maxZoom: 21,
          minZoom: 3,
          coordType: 'gcj02',
        }
      ).addTo(map);

      function addCanvas(){
        //New canvas shape renderer
        const myRenderer = L.canvas({ padding: 0 });
        //Add canvas render layer
        myRenderer.addTo(map);
        //LatLng to container point
        const addPoint = [32.7, 105.7];
        const { x: cx, y: cy } = map.latLngToContainerPoint(addPoint);
        const { _ctx: ctx, _container: container } = myRenderer;
        const r = 15;
        //New zrender instance
        const zr = zrender.init(container);
        //New circle instance
        const circle = new zrender.Circle({
          shape: {
            cx,
            cy,
            r,
          },
          style: {
            fill: 'transparent',
            stroke: 'red',
          },
          silent: true,
        });
        zr.add(circle);
        //New circle animation
        const animator = circle
          .animate('shape', true)
          .when(1000, { r: 0 })
          .when(2000, { r })
          .start();
        
        myRenderer.on('update', ({ target }) => {
          const { x: cx, y: cy } = map.latLngToContainerPoint(addPoint);
          circle.attr({
            shape: {
              cx,
              cy,
            },
          });
        });
        //map.setView(map.getCenter());
      }
    </script>
  </body>
</html>

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值