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
|
###
termap - Terminal Map Viewer
by Michael Strassburger <codepoet@cpan.org>
Minimalistic parser and compiler for Mapbox (Studio) Map Style files
See: https://www.mapbox.com/mapbox-gl-style-spec/
Compiles layer filter instructions into a chain of true/false returning
anonymous functions to improve rendering speed compared to realtime parsing.
###
fs = require 'fs'
module.exports = class Styler
styleById: {}
styleByLayer: {}
constructor: (file) ->
json = JSON.parse fs.readFileSync(file).toString()
@styleName = json.name
@_replaceConstants json.constants, json.layers if json.constants
for style in json.layers
if style.ref and @styleById[style.ref]
for ref in ['type', 'source-layer', 'minzoom', 'maxzoom', 'filter']
if @styleById[style.ref][ref] and not style[ref]
style[ref] = @styleById[style.ref][ref]
style.appliesTo = @_compileFilter style.filter
@styleByLayer[style['source-layer']] ?= []
@styleByLayer[style['source-layer']].push style
@styleById[style.id] = style
getStyleFor: (layer, feature, zoom) ->
return false unless @styleByLayer[layer]
for style in @styleByLayer[layer]
if style.appliesTo feature
return style
return false
_replaceConstants: (constants, tree, level=0) ->
for id, node of tree
switch typeof node
when 'object'
continue if level>1
@_replaceConstants constants, node, level+1
when 'string'
if node.charAt(0) is '@'
tree[id] = constants[node]
null
_compileFilter: (filter) ->
switch filter?[0]
when "all"
filters = (@_compileFilter subFilter for subFilter in filter[1..])
(feature) ->
return false for appliesTo in filters when not appliesTo feature
true
when "any"
filters = (@_compileFilter subFilter for subFilter in filter[1..])
(feature) ->
return true for appliesTo in filters when appliesTo feature
false
when "none"
filters = (@_compileFilter subFilter for subFilter in filter[1..])
(feature) ->
return false for appliesTo in filters when appliesTo feature
true
when "=="
(feature) -> feature.properties[filter[1]] is filter[2]
when "!="
(feature) -> feature.properties[filter[1]] isnt filter[2]
when "in"
(feature) ->
return true for value in filter[2..] when feature.properties[filter[1]] is value
false
when "!in"
(feature) ->
return false for value in filter[2..] when feature.properties[filter[1]] is value
true
when "has"
(feature) -> !!feature.properties[filter[1]]
when "!has"
(feature) -> !feature.properties[filter[1]]
when ">"
(feature) -> feature.properties[filter[1]] > filter[2]
when ">="
(feature) -> feature.properties[filter[1]] >= filter[2]
when "<"
(feature) -> feature.properties[filter[1]] < filter[2]
when "<="
(feature) -> feature.properties[filter[1]] <= filter[2]
else
-> true
|