diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc49c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +bundle* +*.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..5e9eee6 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# termap - Terminal Map + +Discover the world in your console - render vector tile maps from any source! + +## TODOs +* [ ] mapping of view to tiles to show +* [ ] tile request system + * [ ] from local mbtiles + * [ ] from remote url +* [ ] label drawing +* [ ] center+zoom based viewport +* [ ] zoom while keeping center +* [ ] API + * [ ] setCenter + * [ ] setZoom +* [x] accurate mouse drag&drop + +## Wishlist +* node-gyp binding to [libdrawille](https://github.com/Huulivoide/libdrawille) for speed refactor possibilities + filled polygons diff --git a/package.json b/package.json new file mode 100644 index 0000000..d79f586 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "termap", + "version": "0.1.0", + "description": "OSM Terminal Map", + "main": "termap.coffee", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "console", + "map", + "terminal", + "map", + "osm", + "vector", + "tiles", + "mbtiles" + ], + "author": "Michael Straßburger ", + "license": "MIT", + "dependencies": { + "drawille-canvas-blessed-contrib": "^0.1.3", + "keypress": "^0.2.1", + "pbf": "^3.0.0", + "term-mouse": "^0.1.1", + "vector-tile": "^1.3.0" + } +} diff --git a/termap.coffee b/termap.coffee new file mode 100644 index 0000000..4e82247 --- /dev/null +++ b/termap.coffee @@ -0,0 +1,114 @@ +Canvas = require 'drawille-canvas-blessed-contrib' +VectorTile = require('vector-tile').VectorTile +Protobuf = require 'pbf' +keypress = require 'keypress' +fs = require 'fs' +zlib = require 'zlib' +mouse = require('term-mouse')() + +keypress process.stdin + +width = Math.floor((process.stdout.columns-1)/2)*2*2; +height = Math.ceil(process.stdout.rows/4)*4*4; + +drawOrder = ["admin", "water", "landuse", "building", "road"] +layers = + road: "white" + landuse: "green" + water: "blue" + admin: "red" + building: 8 + +canvas = new Canvas width, height + +features = {} +data = fs.readFileSync __dirname+"/tiles/regensburg.pbf.gz" +zlib.gunzip data, (err, buffer) -> + throw new Error err if err + + tile = new VectorTile new Protobuf buffer + for name,layer of tile.layers + if layers[name] + features[name] = [] + for i in [0...layer.length] + features[name].push layer.feature(i).loadGeometry() + + draw() + +zoom = 0 +view = [-400, -80] +size = 4 + +flush = -> + process.stdout.write canvas._canvas.frame() + +draw = -> + canvas.clearRect(0, 0, width, height) + + canvas.save() + + canvas.translate view[0], view[1] + for layer in drawOrder + continue unless features[layer] + + canvas.strokeStyle = layers[layer] + for feature in features[layer] + for line in feature + found = false + points = for point in line + p = [point.x/size, point.y/size] + if not found and p[0]+view[0]>=0 and p[0]+view[0]=0 and p[1]+view[1] + # TODO: file bug @keypress, fails after x>95 / sequence: '\u001b[M#B' + if info.x > 2048 + info.x = 100 + + switch info.scroll + when -1 + size -= .2 + when 1 + size += .2 + + if info.button is 0 + moving = info + + else if moving and info.release + view[0] -= (moving.x-info.x)*2 + view[1] -= (moving.y-info.y)*4 + moving = null + + draw() + +process.stdin.on 'keypress', (ch, key) -> + result = switch key?.name + when "q" + process.exit 0 + + when "a" then size += 1 + when "z" then size -= 1 + when "left" then view[0] += 5 + when "right" then view[0] -= 5 + when "up" then view[1]+= 5 + when "down" then view[1]-= 5 + + else + false + + draw() if result + +process.stdin.setRawMode(true) +process.stdin.resume() diff --git a/tiles/regensburg.pbf.gz b/tiles/regensburg.pbf.gz new file mode 100644 index 0000000..7c26d47 Binary files /dev/null and b/tiles/regensburg.pbf.gz differ diff --git a/tiles/world.pbf.gz b/tiles/world.pbf.gz new file mode 100644 index 0000000..6c06011 Binary files /dev/null and b/tiles/world.pbf.gz differ