基于leaflet.js实现修改地图主题样式

今天遇到了一点点的小情况,我自己根据leaflet.js做了一个离线地图,公司要用来做态势,但是地图的底图用的是高德的原图,样式是下面这样的:
在这里插入图片描述
但是态势的主题是如下的这种淡蓝色:
在这里插入图片描述
这就造成了本次的需求,需要可以修改样式的主题,由于本人是个后端小佬,前端菜鸡,所以实现起来发生了一些困难,这里简单介绍下实现的路程。
首先看下效果:
在这里插入图片描述
然后介绍下艰辛的过程:
首先,需要用到一个基于leaflet.js的插件:
https://github.com/hnrchrdl/leaflet-tilelayer-colorizr
但是在使用这个插件的时候出现了一些问题,这里不赘述了,大致就是我加载的地图瓦片是其他的服务器,但是这个插件似乎不能支持跨域,废了很大的心思我终于解决了这个问题。
这里我先提供解决的方式:

/*
 * L.TileLayer.Colorizr is a regular tilelayer with mapped colors.

 */

(function () {


    // L.TileLayer.Colorizr = 
    var Colorizr = L.TileLayer.extend({

        initialize: function (url, options) {
            options = L.extend({}, L.TileLayer.prototype.options, {
                colorize: function (pixel) {
                    return pixel;
                },
                crossOrigin: 'Anonymous'
            }, options);
            L.TileLayer.prototype.initialize.call(this, url, options);
            L.setOptions(this, options);

            this.setColorizr(this.options.colorize);

            this.on('tileload', function (e) {
                this._colorize(e.tile);
            });
        },

        setColorizr: function (colorizrFactory) {
            if (!colorizrFactory || typeof colorizrFactory !== 'function') {
                throw 'The colorize option should be a function and return an object with at least one of "r", "g", "b", or "a" properties. Got:' +
                typeof colorizrFactory;
            } else {
                this.options.colorize = colorizrFactory;
            }

            this.redraw(false);
        },

        _createTile: function () {
            var tile = L.TileLayer.prototype._createTile.call(this);
            tile.crossOrigin = "Anonymous";
            return tile;
        },

        _colorize: function (img) {
            if (img.getAttribute('data-colorized')) {
                img.hidden = false;
                return;
            }else {
                img.hidden = true;
            }
            var _img = img;
            var img = new Image();
            img.crossOrigin = 'Anonymous';
            img.src = _img.src;
            var _this = this;
            img.onload = function () {
                var canvas = document.createElement("canvas");
                canvas.width = img.width;
                canvas.height = img.height;
                var ctx = canvas.getContext("2d");
                ctx.drawImage(img, 0, 0);
                var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
                var pix = imgd.data;
                for (var i = 0, n = pix.length; i < n; i += 4) {

                    var pixel = _this.options.colorize({r: pix[i], g: pix[i + 1], b: pix[i + 2], a: pix[i + 3]});

                    if (!!!pixel || pixel !== Object(pixel) || Object.prototype.toString.call(pixel) === '[object Array]') {

                        if (i === 0) {
                            throw 'The colorize option should return an object with at least one of "r", "g", "b", or "a" properties.';
                        }

                    } else {

                        if (pixel.hasOwnProperty('r') && typeof pixel.r === 'number') {
                            pix[i] = pixel.r;
                        }
                        if (pixel.hasOwnProperty('g')) {
                            pix[i + 1] = pixel.g;
                        }
                        if (pixel.hasOwnProperty('b')) {
                            pix[i + 2] = pixel.b;
                        }
                        if (pixel.hasOwnProperty('a')) {
                            pix[i + 3] = pixel.a;
                        }
                    }

                }
                ctx.putImageData(imgd, 0, 0);
                _img.setAttribute('data-colorized', true);
                _img.src = canvas.toDataURL();
            };
        }
    });

    (function (factory, window) {

        // define an AMD module that relies on 'leaflet'
        if (typeof define === 'function' && define.amd) {
            define(['leaflet'], factory);

            // define a Common JS module that relies on 'leaflet'
        } else if (typeof exports === 'object') {
            module.exports = factory(require('leaflet'));
        }

        // attach your plugin to the global 'L' variable
        if (typeof window !== 'undefined' && window.L) {
            window.L.tileLayer.colorizr = factory(L);
        }
    }(function (L) {
        return function (url, options) {
            return new Colorizr(url, options);
        };
    }, window));


})()

用上面的代码直接顶替掉下面这个js插件中的所有代码
在这里插入图片描述
以下是使用的方式:

    var map = L.map("map", {
        center: [34.694, 113.587],
        renderer: L.svg(),
        zoom: 16,
        zoomControl: false, // + -号放大缩小
        attributionControl: false // 右下角leaflet.js图标
    });
    // http://192.168.0.105:9090/img/{z}/{x}/{y}.png // 这个是瓦片地图的地址
    L.tileLayer.colorizr("http://localhost:9090/img/{z}/{x}/{y}.png", {
        maxZoom: 18,
        minZoom: 3,
        colorize: function (pixel) {
            // 这个方法用来调整所有的图片上的rgb值,pixel是图片原有的rgb值
            pixel.r += 13;
            pixel.g += 17;
            pixel.b += 90;
            return pixel;
        }
    }).addTo(map);

需要注意的是,可以配合着给图片加滤镜来做:

.leaflet-zoom-animated img {
            -webkit-filter: invert(50%) grayscale(0) saturate(0.5) brightness(1.6) opacity(1) hue-rotate(334deg) sepia(10%) !important;
            -ms-filter: invert(1) grayscale(0) saturate(0.5) brightness(1.6) opacity(1) hue-rotate(334deg) sepia(10%) !important;
            -moz-filter: invert(1) grayscale(0) saturate(0.5) brightness(1.6) opacity(1) hue-rotate(334deg) sepia(10%) !important;
            filter: invert(1) grayscale(0) saturate(0.5) brightness(1.6) opacity(1) hue-rotate(334deg) sepia(1%) !important;
        } 

通过修改colorize的返回值就可以实现修改地图的样式了。
总结下实现思路: 这种方法主要是通过拦截地图瓦片数据,然后通过canvas(本人后端,不是太懂,反正这东西能操作图片)操作图片来修改图片的rgb值,从而达到修改地图样式的目的。

福利

附上一个好用的离线地图,能够进行瓦片下载和交互,支持街道图、卫星图、内置的有开发手册,亲测可用
https://download.csdn.net/download/weixin_43464964/72332736

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老司机张师傅

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

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

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

打赏作者

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

抵扣说明:

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

余额充值