🎭 more async refactoring in preperation for multitile support

pull/7/head
Michael Straßburger 2016-11-03 01:25:09 +01:00
rodzic da6c398e6d
commit 3895fd1fd3
6 zmienionych plików z 129 dodań i 93 usunięć

1
.gitignore vendored
Wyświetl plik

@ -2,3 +2,4 @@ node_modules
bundle*
*.log
tmp
mbtiles

Wyświetl plik

@ -26,6 +26,7 @@
"earcut": "^2.1.1",
"gl-matrix": "^2.3.2",
"keypress": "^0.2.1",
"mbtiles": "^0.9.0",
"pbf": "^3.0.0",
"rbush": "^2.0.1",
"sphericalmercator": "^1.0.5",

Wyświetl plik

@ -16,6 +16,7 @@ Tile = require './Tile'
utils = require './utils'
module.exports = class Renderer
cache: {}
config:
baseZoom: 4
fillPolygons: true
@ -83,7 +84,7 @@ module.exports = class Renderer
setSize: (@width, @height) ->
@canvas = new Canvas @width, @height
draw: (@center, @zoom, @degree) ->
draw: (center, zoom, rotation) ->
return Promise.reject() if @isDrawing
@isDrawing = true
@ -98,27 +99,75 @@ module.exports = class Renderer
# TODO: tiles = @_tilesInBBox @_getBBox()
z = Math.max 0, Math.floor @zoom
xyz = tilebelt.pointToTileFraction @center.lon, @center.lat, z
z = Math.max 0, Math.floor zoom
xyz = tilebelt.pointToTileFraction center.lon, center.lat, z
tile =
size: tileSize
x: Math.floor xyz[0]
y: Math.floor xyz[1]
z: z
tileSize = @config.tileSize / @_scaleAtZoom()
tileSize = @config.tileSize / @_scaleAtZoom(zoom)
position = [
@width/2-(xyz[0]-Math.floor(xyz[0]))*tileSize
@height/2-(xyz[1]-Math.floor(xyz[1]))*tileSize
@width/2-(xyz[0]-tile.x)*tileSize
@height/2-(xyz[1]-tile.y)*tileSize
]
@_renderTile tile, position
.then =>
@_getTile tile
.then (data) =>
@_renderTile data, zoom, position
@_writeFrame()
@isDrawing = false
@lastDrawAt = Date.now()
_getTile: (tile) ->
cacheKey = [tile.z, tile.x, tile.y].join "-"
# if data = @cache[cacheKey]
# console.log cacheKey
# console.log data
# return Promise.resolve data
@tileSource
.getTile tile.z, tile.x, tile.y
.then (data) =>
@cache[cacheKey] = data
_renderTile: (tile, zoom, position) ->
@canvas.reset()
@canvas.translate position[0], position[1]
scale = @_scaleAtZoom zoom
box =
minX: -position[0]*scale
minY: -position[1]*scale
maxX: (@width-position[0])*scale
maxY: (@height-position[1])*scale
# console.log box
# process.exit 0
for layer in @config.drawOrder
if layer.indexOf(':') isnt -1
[layer, filter] = layer.split /:/
[filterField, filterValue] = filter.split /=/
else
filter = false
continue unless tile.layers?[layer]
if @config.layers[layer]?.minZoom and zoom > @config.layers[layer].minZoom
continue
#features = tile.layers[layer].tree.search box
#@notify "rendering #{features.length} #{layer} features.."
for feature in tile.layers[layer].features
feature = data: feature
if not filter or feature.data.properties[filterField] is filterValue
@_drawFeature layer, feature, scale, zoom
_writeFrame: ->
unless @lastDrawAt
@_clearScreen()
@ -129,7 +178,7 @@ module.exports = class Renderer
featuresAt: (x, y) ->
@labelBuffer.featuresAt x, y
_getBBox: (center = @center, zoom = @zoom) ->
_getBBox: (center, zoom) ->
[x, y] = utils.ll2xy center.lon, center.lat
meterPerPixel = utils.metersPerPixel zoom, center.lat
@ -145,7 +194,7 @@ module.exports = class Renderer
.inverse([west+1, south])
.concat mercator.inverse([east-1, north])
_tilesInBBox: (bbox, zoom = @zoom) ->
_tilesInBBox: (bbox, zoom) ->
tiles = {}
[tiles.minX, tiles.minY] = utils.ll2tile bbox[0], bbox[1], Math.floor zoom
[tiles.maxX, tiles.maxY] = utils.ll2tile bbox[2], bbox[3], Math.floor zoom
@ -157,49 +206,11 @@ module.exports = class Renderer
_write: (output) ->
@output.write output
_renderTile: (tile, position) ->
@tileSource
.getTile tile.z, tile.x, tile.y
.then (tile) =>
@canvas.reset()
@canvas.translate position[0], position[1]
scale = @_scaleAtZoom()
box =
minX: -position[0]*scale
minY: -position[1]*scale
maxX: (@width-position[0])*scale
maxY: (@height-position[1])*scale
# console.log box
# process.exit 0
for layer in @config.drawOrder
if layer.indexOf(':') isnt -1
[layer, filter] = layer.split /:/
[filterField, filterValue] = filter.split /=/
else
filter = false
continue unless tile?[layer]
if @config.layers[layer]?.minZoom and @zoom > @config.layers[layer].minZoom
continue
features = tile[layer].tree.search box
@notify "rendering #{features.length} #{layer} features.."
for feature in features
if not filter or feature.data.properties[filterField] is filterValue
@_drawFeature layer, feature, scale
#@draw @center, @zoom+.3, @degree
_scaleAtZoom: (zoom = @zoom) ->
_scaleAtZoom: (zoom) ->
baseZoom = Math.floor Math.max 0, zoom
(@config.tileSize/@config.projectSize)/Math.pow(2, zoom-baseZoom)
_drawFeature: (layer, data, scale) ->
_drawFeature: (layer, data, scale, zoom) ->
feature = data.data
# TODO: this is ugly :) need to be fixed @style
@ -207,7 +218,7 @@ module.exports = class Renderer
feature.type = "LineString" if layer is "building" or layer is "road"
# TODO: zoom level
unless style = @styler.getStyleFor layer, feature, 19-@zoom
unless style = @styler.getStyleFor layer, feature, 19-zoom
return false
toDraw = (@_scaleAndReduce points, scale for points in feature.points)

Wyświetl plik

@ -19,7 +19,7 @@ module.exports = class Termap
input: process.stdin
output: process.stdout
source: __dirname+"/../tiles/planet.z0-z8.mbtiles"
source: __dirname+"/../mbtiles/regensburg.mbtiles"
styleFile: __dirname+"/../styles/bright.json"
zoomStep: 0.2
@ -33,15 +33,19 @@ module.exports = class Termap
tileSource: null
degree: 0
center:
#lat: 49.0189
#lon: 12.0990
lat: 54.133028
lon: 10.609505
zoom: 0
view: [0, 0]
rotation: 0
center:
# sf
# lat: 37.787946
# lon: -122.407522
# iceland
# lat: 64.124229
# lon: -21.811552
# rgbg
lat: 49.0189
lon: 12.0990
minZoom: null
@ -105,8 +109,9 @@ module.exports = class Termap
_onClick: (event) ->
if @mouseDragging and event.button is "left"
@view[0] -= (@mouseDragging.x-@mousePosition.x)<<1
@view[1] -= (@mouseDragging.y-@mousePosition.y)<<2
# TODO lat/lng based drag&drop
# @view[0] -= (@mouseDragging.x-@mousePosition.x)<<1
# @view[1] -= (@mouseDragging.y-@mousePosition.y)<<2
@_draw()
@mouseDragging = false
@ -123,8 +128,9 @@ module.exports = class Termap
# start dragging
if event.button is "left"
if @mouseDragging
@view[0] -= (@mouseDragging.x-event.x)<<1
@view[1] -= (@mouseDragging.y-event.y)<<2
# TODO lat/lng based drag&drop
# @view[0] -= (@mouseDragging.x-event.x)<<1
# @view[1] -= (@mouseDragging.y-event.y)<<2
if not @renderer.isDrawing and @renderer.lastDrawAt < Date.now()-100
@_draw()
@ -146,8 +152,8 @@ module.exports = class Termap
when "a" then @zoomBy @config.zoomStep
when "z" then @zoomBy -@config.zoomStep
when "k" then @degree += 15
when "l" then @degree -= 15
when "k" then @rotation += 15
when "l" then @rotation -= 15
when "left" then @center.lon -= 1
when "right" then @center.lon += 1
@ -165,7 +171,7 @@ module.exports = class Termap
_draw: ->
@renderer
.draw @center, @zoom, @degree
.draw @center, @zoom, @rotation
.then =>
@renderer.notify @_getFooter()

Wyświetl plik

@ -7,32 +7,41 @@
VectorTile = require('vector-tile').VectorTile
Protobuf = require 'pbf'
Promise = require 'bluebird'
zlib = require 'zlib'
Rbush = require 'rbush'
rbush = require 'rbush'
module.exports = class Tile
tree: null
class Tile
layers: {}
constructor: (buffer, @styler = null) ->
@tree = new Rbush()
@tile = @_loadTile buffer
@_loadFeatures()
load: (buffer) ->
@_unzipIfNeeded buffer
.then (data) => @_loadTile data
.then (tile) => @_loadLayers tile
.then => this
_loadTile: (buffer) ->
buffer = zlib.gunzipSync buffer if @_isGzipped buffer
new VectorTile new Protobuf buffer
@tile = new VectorTile new Protobuf buffer
_unzipIfNeeded: (buffer) ->
new Promise (resolve, reject) =>
if @_isGzipped buffer
zlib.gunzip buffer, (err, data) ->
return reject err if err
resolve data
else
resolve buffer
_isGzipped: (buffer) ->
buffer.slice(0,2).indexOf(Buffer.from([0x1f, 0x8b])) is 0
_loadFeatures: ->
for name, layer of @tile.layers
tree = new Rbush()
_loadLayers: (tile) ->
layers = {}
for name, layer of tile.layers
tree = rbush()
features = for i in [0...layer.length]
# TODO: caching of similar attributes to avoid looking up the style each time
continue if @styler and not @styler.getStyleFor layer, feature
#continue if @styler and not @styler.getStyleFor layer, feature
feature = layer.feature i
@ -48,7 +57,9 @@ module.exports = class Tile
@_addToTree tree, data
data
@layers[name] = tree: tree, features: features
layers[name] = tree: tree, features: features
@layers = layers
_addToTree: (tree, data) ->
[minX, maxX, minY, maxY] = [Infinity, -Infinity, Infinity, -Infinity]
@ -65,3 +76,5 @@ module.exports = class Tile
minY: minY
maxY: maxY
data: data
module.exports = Tile

Wyświetl plik

@ -13,12 +13,12 @@ MBTiles = require 'mbtiles'
Tile = require './Tile'
module.exports = class TileSource
cache: {}
modes:
MBTiles: 1
VectorTile: 2
mode: null
cache: {}
mbtiles: null
@ -32,8 +32,8 @@ module.exports = class TileSource
loadMBtils: (source) ->
new Promise (resolve, reject) =>
new MBTiles source, (err, @mbtiles) =>
return reject err if err
resolve()
if err then reject err
else resolve()
getTile: (z, x, y) ->
unless @mode
@ -41,12 +41,16 @@ module.exports = class TileSource
z = Math.max 0, Math.floor z
cacheKey = [z, x, y].join "-"
if cached = @cache[[z,x,y].join("-")]
return Promise.resolve cached
return if cached = @cache[cacheKey]
Promise.resolve cached
else if @mode is @modes.MBTiles
new Promise (resolve, reject) =>
@mbtiles.getTile z, x, y, (err, tileData) =>
return reject err if err
resolve @cache[cacheKey] = new Tile tileData
if @mode is @modes.MBTiles
@_getMBTile z, x, y
_getMBTile: (z, x, y) ->
new Promise (resolve, reject) =>
@mbtiles.getTile z, x, y, (err, tileData) =>
return reject err if err
tile = @cache[[z,x,y].join("-")] = new Tile()
resolve tile.load tileData