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

}
.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值,从而达到修改地图样式的目的。
最后,感谢下友好的国际友人(虽然没能帮到我),嘻嘻。
可以看看我们有趣的聊天记录总结下实现思路:聊天记录最后的最后,给大家附上一个我自己基于leaflet。js实现的离线地图服务器(下载与部署一体)离线地图服务器总结总结总结