ZXY to WMS Proxy

I’ve been moving GeoPortal to Mapbox GL JS, and one of the pain points I hit is the lack of WMS support. That’s one of those I don’t like it but I understand things. There’s nothing about this URL:

1
http://maps.co.mecklenburg.nc.us/geoserver/wms?SERVICE=WMS&REQUEST=GetMap&VERSION=1.1.1&LAYERS=postgis%3Aview_regulated_floodplains%2Cpostgis%3Awater_quality_buffers&STYLES=&FORMAT=image%2Fpng&TRANSPARENT=true&HEIGHT=256&WIDTH=256&SRS=EPSG%3A3857&BBOX=-8990217.51878929,4197921.593421882,-8989606.022563009,4198533.089648162

that screams please use me.

But for convenience sake I still want to flop down WMS layers from time to time. You can make a proxy in node to translate a ZXY request to WMS and return the image using the sphericalmercator and request packages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var Hapi = require('hapi'),
server = new Hapi.Server(),
SphericalMercator = require('sphericalmercator'),
sm = new SphericalMercator({ size: 256 }),
prequest = require('request').defaults({ encoding: null });

var wmsURL = "http://maps.co.mecklenburg.nc.us/geoserver/wms?SERVICE=WMS&REQUEST=GetMap&VERSION=1.1.1&STYLES=&FORMAT=image%2Fpng&TRANSPARENT=true&HEIGHT=256&WIDTH=256&SRS=EPSG%3A3857";

server.connection({
host: 'localhost',
port: 8125,
routes: {
cors: true
}
});

// Tile canon
server.route({
method: 'GET',
path: '/{layers}/{z}/{x}/{y}.png',
handler: function (request, reply) {
var bbox = sm.bbox(request.params.x, request.params.y, request.params.z, false, '900913');
var theUrl = `${wmsURL}&BBOX=${bbox.join(',')}&LAYERS=${decodeURIComponent(request.params.layers)}`;
prequest.get(theUrl, function (err, res, body) {
reply(body)
.header('Cache-Control', 'public, max-age=2629000')
.header('Content-Type', 'image/png');
});
}
});

// Unleash the hounds
server.start(function(){
console.log('Server running at:', server.info.uri);
});

In a nutshell, you’re hitting your favorite WMS server and jacking in the layers you want and the bounding box, the latter translated from ZXY. From there it’s a matter of adding a source and layer to the map, using raster-opacity to make see-through adjustments for polygons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
map.addSource('overlay', {
"type": "raster",
"tiles": [`http://maps.co.mecklenburg.nc.us/zxy2wms/${layers.join(",")}/{z}/{x}/{y}.png`],
"tileSize": 256,
"maxzoom": 18
});
map.addLayer({
"id": "overlay",
"type": "raster",
"source": "overlay",
"minzoom": 15,
"maxzoom": 22,
"paint": {
"raster-opacity": 0.5
}
});