Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Node.js proxy endpoint to access TMS tiles via XYZ url

TMS vs XYZ

Web map raster tile URL templates usally look like this: //{servername}/{somepath}/{z}/{x}/{y}.png

Z is the zoom level (0 being zoomed all the way out so the earth fits on a single 256px x 256px tile, 18 or higher getting you down to street level) X and Y are the tiles coordinates, but there are two different standards for where the origin of the Y coordinate is.

If you look at [http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/](this site) which shows the various tile coordinates, you'll see that the X's are identical for 'Google' and 'TMS', but the Ys are different. 'Google', aka 'XYZ' aka a few other names that nobody seems to agree on places the Y origin at the north end of the earth, while TMS places it in the south.

Re-serve a TMS tileset as an XYZ tileset using express.js

I was recently trying to consume a TMS service in my web app, and ended up proxying the TMS tileset through my own express.js api so I could re-serve it as an XYZ dataset. The osm2tms function converts the TMS y to an XYZ y, and we just pipe the response from the TMS service to the client. This gist by Tom Macwright has the conversion formulas. They are also mentioned in this MapboxGL issue

This proxy route also allows me to use a different file extension (the TMS service was using .png8 but I want my urls to just be .png

So, if you want to consume third party tiles but want to keep all of your URLs standardized, a few lines of javascript can do the trick.

const express = require('express');
const request = require('request');
const router = express.Router();
function osm2tms(z, y) {
return (Math.pow(2, z) - y - 1); // from https://github.com/mapbox/mapbox-gl-js/pull/2565/files
}
router.get('/doitt/tms/1.0.0/photo/:year/:z/:x/:y.png', (req, res) => {
const { year, z, x, y } = req.params;
const sourceTile = `https://maps1.nyc.gov/tms/1.0.0/photo/${year}/${z}/${x}/${osm2tms(z, y)}.png8`;
request(sourceTile).pipe(res);
});
module.exports = router;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.