tilestrata-disk插件可以在磁盘中存储/检索瓦片。它可以兼顾瓦片缓存和瓦片提供两个功能,代码虽简单,但是功能十分全面,个人感觉非常的实用,很值得推荐。
用它来缓存瓦片时,一定要为每个图层使用不同的目录(例如:”tiles/layer_a”, “tiles/layer_b”)。如果设置了maxage
参数,插件会检查瓦片的最近一次修改时间,如果间隔过长,将返回null
。如果 设置maxage=0
,就相当于没有开启缓存功能。
demo 项目可以参考tilestrata-sample-code
1. 安装
$ npm install tilestrata-disk --save
|
2. 使用
const tilestrata = require('tilestrata') const mapnik = require('tilestrata-mapnik') const disk = require('tilestrata-disk') const server = tilestrata()
server .layer('world_merc') .route('tile.png') .use(disk.cache({ dir: 'tilecache/world' })) .use( mapnik({ pathname: 'style/world.xml' }) )
server .layer('province') .route('tile.png') .use(disk.cache({ maxage: 3600, dir: 'tilecache/province' })) .use( mapnik({ pathname: 'style/province.xml' }) )
server.listen(9527)
|
此外,disk 插件的功能远不止如此:
server .layer('mylayer') .route('tile.png') .use() .use( disk.cache({ dir: './tiles/mylayer', maxage: function(server, req) { if (req.z > 15) return 0 if (req.z > 13) return 3600 return 3600 * 24 } }) )
server .layer('mylayer') .route('tile.png') .use() .use(disk.cache({ path: './tiles/{layer}/{z}/{x}/{y}-{filename}' }))
server .layer('mylayer') .route('tile.png') .use() .use( disk.cache({ path: function(tile) { return './tiles/' + tile.layer + '/' + tile.z + '/' } }) )
server .layer('mylayer') .route('tile.png') .use(disk.provider('/path/to/dir/{z}/{x}/{y}/file.png'))
|
甚至在0.6.0
及其以上的 tilestrata 版本中,你还可以通过设定refreshage
来控制缓存数据的寿命,这个参数需要与maxage
一起设设置:
.use(disk.cache({ dir: './tiles/mylayer', refreshage: 3600, maxage: 3600*24*7 }));
refreshage: null refreshage: 0 refreshage: 1800
|
3. 效果
demo 项目可以参考tilestrata-sample-code
下图中设置了tilecache
缓存目录,可以看到瓦片会按照层级建立对应的目录结构并保存图片:
4. 代码浅析
因为插件即提供了cache
功能,也提供了Provider
功能,所以其实它是这两种类型插件的组合,作为Provider
还是比较简单的,核心是 serve 方法:
serve: function(server, tile, callback) { var file = template .replace('{layer}', tile.layer) .replace('{filename}', tile.filename) .replace('{x}', tile.x) .replace('{y}', tile.y) .replace('{z}', tile.z);
fs.readFile(file, function(err, buffer) { if (err) { if (err.code === 'ENOENT') { var err = new Error('File not found'); err.statusCode = 404; return callback(err); } return callback(err); } callback(null, buffer, {'Content-Type': mime(file)}); }); }
|
在cache
功能中,需要提供 get 和 set 方法,主要就是在 set 方法中保存文件,在 get 方法中判断是否过期,是否文件名命中缓存,收否需要刷新,之后再返回对应结果的内容:
FileSystemCache.prototype.set = function( server, req, buffer, headers, callback ) { var maxage = this.ageTolerance('maxage', req) if (maxage === 0) return callback() fs.outputFile(this._file(req), buffer, callback) }
|
FileSystemCache.prototype.get = function(server, req, callback) { var maxage = this.ageTolerance('maxage', req) if (maxage === 0) return done()
var self = this var file = this._file(req) fs.open(file, 'r', function(err, fd) { fs.fstat(fd, function(err, stats) { if (err) return done(err) var mtime = stats.mtime.getTime()
var shouldServe = self.shouldServe(mtime, req) if (!shouldServe) return done()
var shouldRefresh = self.shouldRefresh(mtime, req) var headers = { 'Content-Type': mime(file) } var buffer = new Buffer(stats.size)
if (!stats.size) { return done(null, buffer, headers, shouldRefresh) }
fs.read(fd, buffer, 0, stats.size, 0, function(err) { if (err) return done(err) done(null, buffer, headers, shouldRefresh) }) }) }) }
|