1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
###
termap - Terminal Map Viewer
by Michael Strassburger <codepoet@cpan.org>
Source for VectorTiles - supports
* remote TileServer
* local MBTiles and VectorTiles
###
Promise = require 'bluebird'
userhome = require 'userhome'
fetch = require 'node-fetch'
fs = require 'fs'
Tile = require './Tile'
config = require './config'
# https://github.com/mapbox/node-mbtiles has native build dependencies (sqlite3)
# To maximize mapscii's compatibility, MBTiles support must be manually added via
# $> npm install -g mbtiles
MBTiles = try
require 'mbtiles'
catch
null
module.exports = class TileSource
cache: {}
cached: []
modes:
MBTiles: 1
VectorTile: 2
HTTP: 3
mode: null
mbtiles: null
styler: null
init: (@source) ->
if @source.startsWith "http"
@_initPersistence() if config.persistDownloadedTiles
@mode = @modes.HTTP
else if @source.endsWith ".mbtiles"
unless MBTiles
throw new Error "MBTiles support must be installed with following command: 'npm install -g mbtiles'"
@mode = @modes.MBTiles
@loadMBtils source
else
throw new Error "source type isn't supported yet"
loadMBtils: (source) ->
new Promise (resolve, reject) =>
new MBTiles source, (err, @mbtiles) =>
if err then reject err
else resolve()
useStyler: (@styler) ->
getTile: (z, x, y) ->
unless @mode
throw new Error "no TileSource defined"
z = Math.max 0, Math.floor z
if cached = @cache[[z,x,y].join("-")]
return Promise.resolve cached
if @cached.length > 4
for tile in @cached.splice 0, Math.abs(4-@cached.length)
delete @cache[tile]
switch @mode
when @modes.MBTiles then @_getMBTile z, x, y
when @modes.HTTP then @_getHTTP z, x, y
_getHTTP: (z, x, y) ->
promise =
if config.persistDownloadedTiles and tile = @_getPersited z, x, y
Promise.resolve tile
else
fetch @source+[z,x,y].join("/")+".pbf"
.then (res) => res.buffer()
.then (buffer) =>
@_persistTile z, x, y, buffer if config.persistDownloadedTiles
buffer
promise
.then (buffer) =>
@_createTile z, x, y, buffer
_getMBTile: (z, x, y) ->
new Promise (resolve, reject) =>
@mbtiles.getTile z, x, y, (err, buffer) =>
return reject err if err
resolve @_createTile z, x, y, buffer
_createTile: (z, x, y, buffer) ->
name = [z,x,y].join("-")
@cached.push name
tile = @cache[name] = new Tile @styler
tile.load buffer
_initPersistence: ->
try
@_createFolder userhome ".mapscii"
@_createFolder userhome ".mapscii", "cache"
catch error
config.persistDownloadedTiles = false
return
_persistTile: (z, x, y, buffer) ->
zoom = z.toString()
@_createFolder userhome ".mapscii", "cache", zoom
fs.writeFile userhome(".mapscii", "cache", zoom, "#{x}-#{y}.pbf"), buffer, -> null
_getPersited: (z, x, y) ->
try
fs.readFileSync userhome ".mapscii", "cache", z.toString(), "#{x}-#{y}.pbf"
catch error
false
_createFolder: (path) ->
try
fs.mkdirSync path
true
catch e
e.code is "EEXIST"
|