基于 Leaflet 的缩放功能:在最后一层瓦片缺失时进行优化

news2024/10/7 20:31:20

这里写自定义目录标题

  • 第一种方式
  • 第二种方式
  • 第三种方式

引言:Leaflet 是一个广泛使用的开源 JavaScript 库,用于创建交互式、可定制的地图应用程序。在 Leaflet 中,默认情况下,瓦片地图是通过切分成多个瓦片来展示的,这些瓦片组合在一起形成完整的地图。然而,当地图的最后一层瓦片存在缺失或不完整时,可能会导致用户在缩放时出现显示问题。本文将介绍如何优化 Leaflet 缩放功能,以便在最后一层瓦片缺失时提供更好的用户体验

第一种方式

您可以使用参数 maxNativeZoom 来定义从哪一层瓦片开始进行缩放。具体来说,maxNativeZoom 参数用于设置地图的最大本机缩放级别,即地图所使用的原始瓦片的最高缩放级别

缺点:必须指定哪一层,但是瓦片的资源,最后一层是不确定的,打个比方,深圳的最后一层是18层,舟山港口的最后一层是17层,那这就不完美了,除非地图是指定区域使用,比如惠州某园区

var tileLayer = L.tileLayer(url, {
    maxZoom: 23,
    maxNativeZoom: 18,
});

第二种方式

基于第一种方式的缺点,做了优化,基于插件
Leaflet.TileLayer.Fallback(添加链接描述)
使用此插件,您无需显式指定 maxNativezoom 选项。平铺层首先尝试获取当前缩放的平铺图像,但在服务器没有该缩放级别的图像并返回404错误的区域,平铺层将自动请求较低的缩放。

// 引用以上插件后这样设置就好
var myTileLayer = L.tileLayer.fallback(url, {
	maxZoom: 22,
});
myTileLayer.addTo(map);

第三种方式

第二种方式只能在返回404错误时监听,这就有个问题了,比如他不是返回404错误,而是返回一张错误的图片,比如
在这里插入图片描述

到这里已经技穷,所以基于Leaflet.TileLayer.Fallback 插件源码做了一点小修改,由于这张错误瓦片没有什么唯一标识,比如url和坐标都不能作为唯一标识,所以打算用图片的responseText的长度作为图片的的唯一标识,源码在最后面
在这里插入图片描述

Leaflet.TileLayer.Fallback 插件 fallback.js,做了改动后的代码,缺点是多请求了一遍瓦片

L.TileLayer.Fallback = 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;
    },

    _createCurrentCoords: function (originalCoords) {
        var currentCoords = this._wrapCoords(originalCoords);

        currentCoords.fallback = true;

        return currentCoords;
    },

    _originalTileOnError: L.TileLayer.prototype._tileOnError,

    _tileOnError: function (done, tile, e) {
        // console.log('zoule');
        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 = (tile._fallbackZoom = tile._fallbackZoom === undefined ? originalCoords.z - 1 : tile._fallbackZoom - 1),
            scale = (tile._fallbackScale = (tile._fallbackScale || 1) * 2),
            tileSize = layer.getTileSize(),
            style = tile.style,
            newUrl,
            top,
            left;

        // If no lower zoom tiles are available, fallback to errorTile.
        if (fallbackZoom < layer.options.minNativeZoom) {
            return this._originalTileOnError(done, tile, e);
        }

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

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

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

        // Compute margins to adjust position.
        top = (originalCoords.y - currentCoords.y * scale) * tileSize.y;
        style.marginTop = -top + 'px';
        left = (originalCoords.x - currentCoords.x * scale) * tileSize.x;
        style.marginLeft = -left + 'px';

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

        layer.fire('tilefallback', {
            tile: tile,
            url: tile._originalSrc,
            urlMissing: tile.src,
            urlFallback: newUrl,
        });

        tile.src = newUrl;
    },

    _tileOnLoad: function (done, tile, e) {
        var layer = this, // `this` is bound to the Tile Layer in L.TileLayer.prototype.createTile.
            originalCoords = tile._originalCoords,
            fallbackZoom = (tile._fallbackZoom = tile._fallbackZoom === undefined ? originalCoords.z - 1 : tile._fallbackZoom - 1);
        if (fallbackZoom > 17) {
            var xhr = new XMLHttpRequest();
            xhr.onload = function () {
                if (xhr.status === 200) {
                    if (xhr.responseText.length == 2423) {
                        var currentCoords = (tile._currentCoords = tile._currentCoords || layer._createCurrentCoords(originalCoords)),
                            scale = (tile._fallbackScale = (tile._fallbackScale || 1) * 2),
                            tileSize = layer.getTileSize(),
                            style = tile.style,
                            newUrl,
                            top,
                            left;
                        currentCoords.z = fallbackZoom;
                        currentCoords.x = Math.floor(currentCoords.x / 2);
                        currentCoords.y = Math.floor(currentCoords.y / 2);
                        // Generate new src path.
                        newUrl = layer.getTileUrl(currentCoords);
                        // Zoom replacement img.
                        style.width = tileSize.x * scale + 'px';
                        style.height = tileSize.y * scale + 'px';
                        // Compute margins to adjust position.
                        top = (originalCoords.y - currentCoords.y * scale) * tileSize.y;
                        style.marginTop = -top + 'px';
                        left = (originalCoords.x - currentCoords.x * scale) * tileSize.x;
                        style.marginLeft = -left + 'px';
                        // Crop (clip) image.
                        // `clip` is deprecated, but browsers support for `clip-path: inset()` is far behind.
                        // http://caniuse.com/#feat=css-clip-path
                        style.clip = 'rect(' + top + 'px ' + (left + tileSize.x) + 'px ' + (top + tileSize.y) + 'px ' + left + 'px)';
                        layer.fire('tilefallback', {
                            tile: tile,
                            url: tile._originalSrc,
                            urlMissing: tile.src,
                            urlFallback: newUrl,
                        });
                        tile.src = newUrl;
                    } else {
                        done(null, tile);
                    }
                }
            };
            // 发送请求获取瓦片文件
            xhr.open('GET', tile.src, true);
            xhr.send();
        } else {
            done(null, tile);
        }
    },
    getTileUrl: function (coords) {
        var z = (coords.z = coords.fallback ? coords.z : this._getZoomForUrl());

        var data = {
            r: L.Browser.retina ? '@2x' : '',
            s: this._getSubdomain(coords),
            x: coords.x,
            y: coords.y,
            z: z,
        };
        if (this._map && !this._map.options.crs.infinite) {
            var invertedY = this._globalTileRange.max.y - coords.y;
            if (this.options.tms) {
                data['y'] = invertedY;
            }
            data['-y'] = invertedY;
        }

        return L.Util.template(this._url, L.extend(data, this.options));
    },
});

// Supply with a factory for consistency with Leaflet.
L.tileLayer.fallback = function (urlTemplate, options) {
    return new L.TileLayer.Fallback(urlTemplate, options);
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/692099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为防火墙之NAT技术

1.源NAT 源NAT技术对IP报文的源地址进行转换&#xff0c;将私网IP地址转换成公网IP地址&#xff0c;使大量私网用户可以利用少量公网IP地址访问Internet&#xff0c;大大减少了对公网IP地址的消耗。 源NAT转换的过程如下图所示&#xff0c;当私网用户访问Internet的报文到达防…

Ubuntu终端最大化的3种方法

摘要&#xff1a;Ubuntu 系统下&#xff0c;使用Ctrl Alt T 快捷键唤醒终端时默认大小为 80 列 x 24 行。在某些测试中我们需要更大的窗口&#xff0c;而通过鼠标将窗口最大化太慢了&#xff0c;所以本文介绍了快速实现终端窗口最大化的 3 种方法。 声明&#xff1a;本文所有…

java安全——Java 默认沙箱

Java安全 Java 默认沙箱 程序设计者或者管理员通过改变沙箱的参数从而完成权限的变动更新 Java默认沙箱的设计目的是为了保护系统和用户的安全。Java虚拟机提供了一种机制&#xff0c;让Java应用程序在一个受限的环境中运行&#xff0c;也就是“沙箱”。这个沙箱能够在应用程序…

微信支付证书过期了怎么办

什么是商户API证书&#xff1f;如何获取商户API证书&#xff1f; 微信原文档&#xff1a;https://kf.qq.com/faq/161222NneAJf161222U7fARv.html 注&#xff1a;正常情况下&#xff0c;微信商户平台的密钥不需要更新重置&#xff0c;站点妥善保存密钥&#xff0c;定期更新证书即…

【adb指令】

一、什么是adb adb的全称为Android Debug Bridge&#xff0c;官方提供的用于操作安卓设备的工具。 二、adb用来干什么&#xff1f; 在电脑终端通过命令行&#xff1a; 打开收手机应用&#xff1b;传输文件&#xff1b;点击、输入、滑动等&#xff1b;硬件操作、返回、回到首…

踩坑记录:nuxt3 - ssg 重构我的前端导航网站

一、&#x1f4a5; 背景故事 不久前我利用周末搭建了个 万能导航网站&#xff0c;当时还写了篇文章&#xff1a;# 我给自己搭建的前端导航网站&#xff0c;你们都别用&#x1f92a;。本来我以为不会有太大的访问量&#xff0c;主要是方便自己用。没想到用的人还不少&#xff0…

maven 远程仓库 查找jar mvnrepository.com

https://mvnrepository.com 搜索包 找到指定版本 下载包或者配置文件引用

WORDPRESS REST API 学习

WORDPRESS 的 REST API 本身是没有身份验证的&#xff0c;我安装了 miniOrange 的 WordPress REST API Authentication 免费部分只有 Basic Authentication 和 JWT Authentication &#xff0c; 作为学习 REST API 够用了。 一般使用 postman 测试 api &#xff0c;后来卸载了…

通用分页【上】之后端代码

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于通用分页的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 导读&#xff1a; &#x1f4a1;辉辉小…

git创建分支提示fatal: not a valid object name: ‘master‘解决方案

文章目录 1. 背景描述&#xff1a;2. 原因分析&#xff1a;3. 解决方案&#xff1a; 1. 背景描述&#xff1a; 在本地使用 git init初始化一个空的git项目后&#xff0c;想使用git branch创建分支时&#xff0c;提示fatal: not a valid object name: ‘master’。 2. 原因分…

【react全家桶学习】react的 (新/旧) 生命周期(重点)

目录 生命周期&#xff08;旧&#xff09; 挂载时的生命周期 constructor&#xff08;props&#xff09; componentWillMount&#xff08;&#xff09;-------------新生命周期已替换 render&#xff08;&#xff09; componentDidMount&#xff08;&#xff09;--- 组件…

【MHA高可用配置及故障切换】

目录 一、案例概述1、传统的MySQL主从架构存在的问题1.1、单点故障 2、HMA的简介2.1、HMA的概述2.2、HMA的组成2.3、MHA 的特点 三、搭建MySQL HMA1、实验思路1、进入主服务器进行修改配置文件2、启动服务&#xff0c;并在从服务器上配置计划性任务进行时间同步 2、修改 Master…

人声克隆技术:So-Vits-Svc项目解析

SO-VITs-SVC 本文是该系列的第一篇&#xff0c;采用倒序的方式&#xff0c;先从推理过程开始介绍人声克隆的工作流&#xff0c;以及各个模型的功能&#xff0c;之后再去详细介绍各个模型&#xff0c;因此不涉及具体的使用方法&#xff0c;这个官方文档里面已经讲的很清楚了&…

相机成像原理【第一节】

文章目录 1、胶片摄影与数码摄影2、相机的组成2.1 只有传感器相机的成像 3、小孔成像3.1 小孔相机的参数和成像结果3.2 关于小孔成像的两个问题 1、胶片摄影与数码摄影 胶片摄影是把光学镜头的光信号投射到胶片上&#xff0c; 数码摄影是把光学镜头的光信号投射到传感器上&…

「又是干货」史诗级漏洞挖掘的过程快get一下

前言 本文记录了针对前台RCE的挖掘过程&#xff0c;由于该CMS前几天才做了修复&#xff0c;所以将挖掘过程写出来 接着直接来看代码&#xff0c;首先目标仍然是解析if标签的代码块&#xff0c;看一下三个正则 /\{pboot:if\(([^}^\$])\)\}([\s\S]*?)\{\/pboot:if\}//([\w])(…

零基础也能轻松制作电子邀请函教程

随着互联网技术的发展&#xff0c;电子邀请函已经逐渐取代传统的纸质邀请函成为一种趋势。不仅可以节省纸张和邮寄的成本&#xff0c;还能够更加个性化和创意化地展现活动。自己制作电子邀请函&#xff0c;百利而无一害&#xff0c;如果你也想自己动手制作一份电子邀请函&#…

VTK 悬浮显示 actor详细

需求&#xff1a;场景中一个actor&#xff0c;鼠标悬浮时 显示此actor的信息。 效果&#xff1a; 实现&#xff1a; 1&#xff0c;利用vtkInteractorStyleTrackballCamera 的OnMouseMove 事件 判断是否处于悬浮状态 2&#xff0c;判断悬浮后&#xff0c;首先将世界坐标转为…

10分钟教你学会使用ab 进行并发压力测试

目录 ab全称为&#xff1a;apache bench。 安装ab命令&#xff1a; 使用&#xff1a; 测试结果&#xff1a; 结果分析&#xff1a; 总结&#xff1a; ab全称为&#xff1a;apache bench。 是apache自带的压力测试工具。ab非常实用&#xff0c;它不仅可以对apache服务器进…

离子风枪的功能特点及应用领域

除静电离子风枪是一种常见的设备&#xff0c;被广泛应用于各个领域的生产线上&#xff0c;其作用是通过产生离子气流&#xff0c;有效地去除物体表面的静电。在现代工业生产中&#xff0c;静电可能引发诸多问题&#xff0c;如引起电子元器件损坏、拖尘吸附、产品互粘等。除静电…

如何使用Wu10Man启用或禁用自动更新

使用Wu10Man启用或禁用自动更新 启用自动更新禁用自动更新Windows 10 将在你设置为自动维护时自动检查新的 Windows 更新。默认情况下,Windows 10 将自动下载并安装重要和关键更新。 某些更新不是自动安装的。这包括可选更新和要求你接受新使用条款的更新。当这些更新可用时,…