diff --git a/LabelBuffer.coffee b/LabelBuffer.coffee new file mode 100644 index 0000000..a8fc693 --- /dev/null +++ b/LabelBuffer.coffee @@ -0,0 +1,39 @@ +### + termap - Terminal Map Viewer + by Michael Strassburger + + Using 2D spatial indexing to avoid overlapping labels and markers + Future: to detect collision on mouse interaction +### + +rbush = require 'rbush' + +module.exports = class LabelBuffer + tree: null + margin: 5 + + constructor: (@width, @height) -> + @tree = rbush() + + clear: -> + @tree.clear() + + project: (x, y) -> + [Math.floor(x/2), Math.floor(y/4)] + + writeIfPossible: (text, x, y) -> + point = @project x, y + + if @_hasSpace text, point[0], point[1] + @tree.insert @_calculateArea text, point[0], point[1] + else + false + + _hasSpace: (text, x, y) -> + not @tree.collides @_calculateArea text, x, y, 0 + + _calculateArea: (text, x, y, margin = @margin) -> + minX: x-margin + minY: y-margin + maxX: x+margin+text.length + maxY: y+margin diff --git a/main.js b/main.js new file mode 100644 index 0000000..d8b9bb9 --- /dev/null +++ b/main.js @@ -0,0 +1,21 @@ +/*# + termap - Terminal Map Viewer + by Michael Strassburger + Discover the planet in your console! + + This scripts boots up the application. + + TODO: params parsing and so on +#*/ + +require('coffee-script/register'); + +const fs = require('fs'); +const Termap = require(__dirname+'/src/Termap'); + +termap = new Termap(); + +// TODO: abstracing this class, create loader class +data = fs.readFileSync(__dirname+"/tiles/regensburg.pbf.gz"); +termap.renderer.features = termap.renderer._getFeatures(termap.renderer._parseTile(data)); +termap._draw(); diff --git a/package.json b/package.json index 0b100fb..d554ee9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Terminal Map Viewer", "main": "termap.coffee", "scripts": { - "start": "./node_modules/coffee-script/bin/coffee termap.coffee", + "start": "node main", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ diff --git a/src/Renderer.coffee b/src/Renderer.coffee index 4e76b87..4b6080a 100644 --- a/src/Renderer.coffee +++ b/src/Renderer.coffee @@ -148,7 +148,7 @@ module.exports = class Renderer _drawFeature: (layer, feature, scale) -> # TODO: this is ugly :) need to be fixed @style - return false if feature.properties.class is "ferry" + #return false if feature.properties.class is "ferry" feature.type = "LineString" if layer is "building" or layer is "road" toDraw = [] @@ -169,16 +169,16 @@ module.exports = class Renderer continue unless visible toDraw.push projectedPoints - if style = @styler.getStyleFor layer, feature, 14 - color = style.paint['line-color'] or style.paint['fill-color'] + unless style = @styler.getStyleFor layer, feature, 14 + return false - # TODO: zoom calculation todo for perfect styling - if color instanceof Object - color = color.stops[0][1] + color = style.paint['line-color'] or style.paint['fill-color'] or style.paint['text-color'] - @canvas.fillStyle = @canvas.strokeStyle = x256 utils.hex2rgb color - else - @canvas.strokeStyle = @canvas.fillStyle = @config.layers[layer].color + # TODO: zoom calculation todo for perfect styling + if color instanceof Object + color = color.stops[0][1] + + @canvas.fillStyle = @canvas.strokeStyle = x256 utils.hex2rgb color switch feature.type when "LineString" diff --git a/src/Styler.coffee b/src/Styler.coffee index a2c8ed0..70d425b 100644 --- a/src/Styler.coffee +++ b/src/Styler.coffee @@ -47,10 +47,10 @@ module.exports = class Styler true when "==" - feature.properties[filter[0]] is filter[1] + feature.properties[filter[1]] is filter[2] when "!=" - feature.properties[filter[0]] isnt filter[1] + feature.properties[filter[2]] isnt filter[2] when "in" field = filter[1] diff --git a/src/Termap.coffee b/src/Termap.coffee index 918104b..060f8b3 100644 --- a/src/Termap.coffee +++ b/src/Termap.coffee @@ -1,6 +1,8 @@ ### termap - Terminal Map Viewer by Michael Strassburger + + UI and central command center ### keypress = require 'keypress' diff --git a/styles/basic.json b/styles/basic.json new file mode 100644 index 0000000..8b6ab1b --- /dev/null +++ b/styles/basic.json @@ -0,0 +1,867 @@ +{ + "version": 8, + "name": "Basic", + "metadata": { + "mapbox:autocomposite": true, + "mapbox:type": "template" + }, + "sources": { + "mapbox": { + "url": "mapbox://mapbox.mapbox-streets-v7", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/mapbox/basic-v9", + "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "#dedede" + }, + "interactive": true + }, + { + "id": "landuse_overlay_national_park", + "type": "fill", + "source": "mapbox", + "source-layer": "landuse_overlay", + "filter": [ + "==", + "class", + "national_park" + ], + "paint": { + "fill-color": "#d2edae", + "fill-opacity": 0.75 + }, + "interactive": true + }, + { + "id": "landuse_park", + "type": "fill", + "source": "mapbox", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "park" + ], + "paint": { + "fill-color": "#d2edae" + }, + "interactive": true + }, + { + "id": "waterway", + "type": "line", + "source": "mapbox", + "source-layer": "waterway", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "river", + "canal" + ] + ], + "paint": { + "line-color": "#a0cfdf", + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 0.5 + ], + [ + 20, + 15 + ] + ] + } + }, + "interactive": true + }, + { + "id": "water", + "type": "fill", + "source": "mapbox", + "source-layer": "water", + "paint": { + "fill-color": "#a0cfdf" + }, + "interactive": true + }, + { + "id": "building", + "type": "fill", + "source": "mapbox", + "source-layer": "building", + "paint": { + "fill-color": "#d6d6d6" + }, + "interactive": true + }, + { + "interactive": true, + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway_link", + "street", + "street_limited", + "service", + "track", + "pedestrian", + "path", + "link" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "tunnel_minor", + "paint": { + "line-color": "#efefef", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-dasharray": [ + 0.36, + 0.18 + ] + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "tunnel_major", + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + }, + "line-dasharray": [ + 0.28, + 0.14 + ] + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway_link", + "street", + "street_limited", + "service", + "track", + "pedestrian", + "path", + "link" + ], + [ + "in", + "structure", + "none", + "ford" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "road_minor", + "paint": { + "line-color": "#efefef", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + [ + "in", + "structure", + "none", + "ford" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "road_major", + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway_link", + "street", + "street_limited", + "service", + "track", + "pedestrian", + "path", + "link" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "bridge_minor case", + "paint": { + "line-color": "#dedede", + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + }, + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "bridge_major case", + "paint": { + "line-color": "#dedede", + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + }, + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway_link", + "street", + "street_limited", + "service", + "track", + "pedestrian", + "path", + "link" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "bridge_minor", + "paint": { + "line-color": "#efefef", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "bridge_major", + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source-layer": "road" + }, + { + "interactive": true, + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "<=", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ] + ] + ], + "type": "line", + "source": "mapbox", + "id": "admin_country", + "paint": { + "line-color": "#8b8a8a", + "line-width": { + "base": 1.3, + "stops": [ + [ + 3, + 0.5 + ], + [ + 22, + 15 + ] + ] + } + }, + "source-layer": "admin" + }, + { + "interactive": true, + "minzoom": 5, + "layout": { + "icon-image": "{maki}-11", + "text-offset": [ + 0, + 0.5 + ], + "text-field": "{name_en}", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 8, + "text-anchor": "top", + "text-size": 11, + "icon-size": 1 + }, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "all", + [ + "==", + "scalerank", + 1 + ], + [ + "==", + "localrank", + 1 + ] + ] + ], + "type": "symbol", + "source": "mapbox", + "id": "poi_label", + "paint": { + "text-color": "#666", + "text-halo-width": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-blur": 1 + }, + "source-layer": "poi_label" + }, + { + "interactive": true, + "layout": { + "symbol-placement": "line", + "text-field": "{name_en}", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-size": { + "base": 1.4, + "stops": [ + [ + 10, + 8 + ], + [ + 20, + 14 + ] + ] + } + }, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "type": "symbol", + "source": "mapbox", + "id": "road_major_label", + "paint": { + "text-color": "#666", + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + }, + "source-layer": "road_label" + }, + { + "interactive": true, + "minzoom": 8, + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-max-width": 6, + "text-size": { + "stops": [ + [ + 6, + 12 + ], + [ + 12, + 16 + ] + ] + } + }, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "in", + "type", + "town", + "village", + "hamlet", + "suburb", + "neighbourhood", + "island" + ] + ], + "type": "symbol", + "source": "mapbox", + "id": "place_label_other", + "paint": { + "text-color": "#666", + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "source-layer": "place_label" + }, + { + "interactive": true, + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Open Sans Bold", + "Arial Unicode MS Bold" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 16 + ] + ] + } + }, + "maxzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "type", + "city" + ] + ], + "type": "symbol", + "source": "mapbox", + "id": "place_label_city", + "paint": { + "text-color": "#666", + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "source-layer": "place_label" + }, + { + "interactive": true, + "layout": { + "text-field": "{name_en}", + "text-font": [ + "Open Sans Regular", + "Arial Unicode MS Regular" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 14 + ], + [ + 8, + 22 + ] + ] + } + }, + "maxzoom": 12, + "filter": [ + "==", + "$type", + "Point" + ], + "type": "symbol", + "source": "mapbox", + "id": "country_label", + "paint": { + "text-color": "#666", + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "source-layer": "country_label" + } + ] +} \ No newline at end of file diff --git a/styles/bright.json b/styles/bright.json index f89a7bf..e6b9cf7 100644 --- a/styles/bright.json +++ b/styles/bright.json @@ -988,7 +988,7 @@ "type": "symbol", "id": "poi_label_4", "paint": { - "text-color": "#666" + "text-color": "#aa0" }, "source-layer": "poi_label", "filter": [ @@ -1013,7 +1013,7 @@ "type": "symbol", "id": "poi_label_3", "paint": { - "text-color": "#666" + "text-color": "#cc0" }, "source-layer": "poi_label", "filter": [ @@ -1038,7 +1038,7 @@ "type": "symbol", "id": "poi_label_2", "paint": { - "text-color": "#666" + "text-color": "#ee0" }, "source-layer": "poi_label", "filter": [ @@ -1074,7 +1074,7 @@ "type": "symbol", "id": "poi_label_1", "paint": { - "text-color": "#666" + "text-color": "#ff0" }, "source-layer": "poi_label", "filter": [ @@ -1242,7 +1242,7 @@ "type": "symbol", "id": "place_label_city", "paint": { - "text-color": "#333" + "text-color": "#f00" }, "source-layer": "place_label", "filter": [ diff --git a/termap.coffee b/termap.coffee deleted file mode 100644 index 930639d..0000000 --- a/termap.coffee +++ /dev/null @@ -1,9 +0,0 @@ -fs = require 'fs' -Termap = require __dirname+'/src/Termap' - -termap = new Termap() - -# TODO: abstracing this class, create loader class -data = fs.readFileSync __dirname+"/tiles/regensburg.pbf.gz" -termap.renderer.features = termap.renderer._getFeatures termap.renderer._parseTile data -termap._draw()