Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion lib/glug/stylesheet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def initialize(base_dir: nil, params: nil, &block)
@sources = {}
@kv = {}
@layers = []
@layer_order = nil
@base_dir = base_dir || ''
@params = params || {}
@dsl = StylesheetDSL.new(self)
Expand All @@ -25,6 +26,10 @@ def source(source_name, opts = {})
@sources[source_name] = opts
end

def layer_order(order)
@layer_order = order
end

# Add a layer
# creates a new Layer object using the block supplied
def layer(id, opts = {}, &block)
Expand All @@ -41,7 +46,7 @@ def to_hash
v.delete(:default)
out['sources'][k] = v
end
out['layers'] = @layers.select(&:write?).collect(&:to_hash).compact
out['layers'] = ordered_layers.collect(&:to_hash).compact
out
end

Expand All @@ -58,5 +63,44 @@ def _add_layer(layer)
def include_file(filename)
@dsl.instance_eval(File.read(File.join(@base_dir, filename)))
end

private

def ordered_layers
writable = @layers.select(&:write?)
return writable unless @layer_order

order_strings = @layer_order.map(&:to_s)

# Include sublayers automatically if parent layer is included
groups = Hash.new { |h, k| h[k] = [] }
writable.each do |layer|
lid = layer.kv[:id].to_s
group = find_order_group(lid, order_strings)
groups[group] << layer if group
end

order_strings.flat_map { |entry| groups[entry] || [] }
end

def find_order_group(layer_id, order_strings)
return layer_id if order_strings.include?(layer_id)

# Find the longest order entry that is a prefix of this layer's ID
best = nil
order_strings.each do |entry|
best = entry if layer_id.start_with?("#{entry}__") && (best.nil? || entry.length > best.length)
end

# If a parent matched, only auto-include when no sibling sublayer
# is explicitly in the order (explicit reference opts into manual control)
if best
order_strings.each do |entry|
return nil if entry.start_with?("#{best}__")
end
end

best
end
end
end
4 changes: 4 additions & 0 deletions lib/glug/stylesheet_dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def include_file(filename)
@__impl.include_file(filename)
end

def layer_order(order)
@__impl.layer_order(order)
end

# Arbitrary properties can be defined, e.g. "foo :bar" results in a top-level "foo":"bar" in the style
def respond_to_missing?(*)
true
Expand Down
30 changes: 30 additions & 0 deletions spec/fixtures/layer_ordering.glug
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version 8
name 'My first stylesheet'
source :shortbread, type: 'vector', url: 'https://vector.openstreetmap.org/shortbread_v1/tilejson.json'

layer_order([
:first,
:second,
"third",
:nonexistant
])

# layer with symbol name
layer(:first, source: :shortbread) do
line_color 0x998877
end

# layer with symbol name, but string in ordering
layer(:third, source: :shortbread) do
line_color 0x998877
end

# layer with string name, but symbol in ordering
layer("second", source: :shortbread) do
line_color 0x998877
end

# layer that doesn't appear in ordering, and so not in output
layer(:unused, source: :shortbread) do
line_color 0x998877
end
33 changes: 33 additions & 0 deletions spec/fixtures/layer_ordering.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"version":8,
"name":"My first stylesheet",
"sources":{
"shortbread":{
"type":"vector",
"url":"https://vector.openstreetmap.org/shortbread_v1/tilejson.json"
}
},
"layers":[
{
"paint":{"line-color":"#998877"},
"source":"shortbread",
"id":"first",
"source-layer":"first",
"type":"line"
},
{
"paint":{"line-color":"#998877"},
"source":"shortbread",
"id":"second",
"source-layer":"second",
"type":"line"
},
{
"paint":{"line-color":"#998877"},
"source":"shortbread",
"id":"third",
"source-layer":"third",
"type":"line"
}
]
}
16 changes: 16 additions & 0 deletions spec/fixtures/layer_ordering_sublayers.glug
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version 8
source :shortbread, type: 'vector', url: 'https://example.com/tiles.json'

layer_order([:roads])

# If the sublayers aren't explicitly referred to in the layer_order
# then they are included automatically
layer(:roads, source: :shortbread) do
line_color 0x998877
on(5..10) do
line_width 2
end
on(10..15) do
line_width 4
end
end
31 changes: 31 additions & 0 deletions spec/fixtures/layer_ordering_sublayers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"version":8,
"sources":{"shortbread":{"type":"vector","url":"https://example.com/tiles.json"}},
"layers":[
{
"paint":{"line-color":"#998877"},
"source":"shortbread",
"id":"roads",
"source-layer":"roads",
"type":"line"
},
{
"paint":{"line-color":"#998877","line-width":2},
"source":"shortbread",
"id":"roads__1",
"source-layer":"roads",
"type":"line",
"minzoom":5,
"maxzoom":10
},
{
"paint":{"line-color":"#998877","line-width":4},
"source":"shortbread",
"id":"roads__2",
"source-layer":"roads",
"type":"line",
"minzoom":10,
"maxzoom":15
}
]
}
16 changes: 16 additions & 0 deletions spec/fixtures/layer_ordering_sublayers_explicit.glug
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version 8
source :shortbread, type: 'vector', url: 'https://example.com/tiles.json'

layer_order([:roads__2])

# If you refer to a sublayer explicitly in the layer_order
# then unreferenced sublayers are ignored
layer(:roads, source: :shortbread) do
line_color 0x998877
on(5..10) do
line_width 2
end
on(10..15) do
line_width 4
end
end
15 changes: 15 additions & 0 deletions spec/fixtures/layer_ordering_sublayers_explicit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version":8,
"sources":{"shortbread":{"type":"vector","url":"https://example.com/tiles.json"}},
"layers":[
{
"paint":{"line-color":"#998877","line-width":4},
"source":"shortbread",
"id":"roads__2",
"source-layer":"roads",
"type":"line",
"minzoom":10,
"maxzoom":15
}
]
}
16 changes: 16 additions & 0 deletions spec/fixtures/layer_ordering_sublayers_with_parent.glug
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version 8
source :shortbread, type: 'vector', url: 'https://example.com/tiles.json'

layer_order([:roads, :roads__2])

# If you refer to a sublayer explicitly in the layer_order
# then unreferenced sublayers are ignored
layer(:roads, source: :shortbread) do
line_color 0x998877
on(5..10) do
line_width 2
end
on(10..15) do
line_width 4
end
end
22 changes: 22 additions & 0 deletions spec/fixtures/layer_ordering_sublayers_with_parent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"version":8,
"sources":{"shortbread":{"type":"vector","url":"https://example.com/tiles.json"}},
"layers":[
{
"paint":{"line-color":"#998877"},
"source":"shortbread",
"id":"roads",
"source-layer":"roads",
"type":"line"
},
{
"paint":{"line-color":"#998877","line-width":4},
"source":"shortbread",
"id":"roads__2",
"source-layer":"roads",
"type":"line",
"minzoom":10,
"maxzoom":15
}
]
}
36 changes: 36 additions & 0 deletions spec/lib/glug/stylesheet_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,41 @@
output = File.read(File.join(fixture_dir, 'expression_ivars.json'))
expect(stylesheet.to_json).to eql(output.strip)
end

it 'handles explicit layer ordering' do
glug = File.read(File.join(fixture_dir, 'layer_ordering.glug'))
stylesheet = described_class.new(base_dir: fixture_dir) do
instance_eval(glug)
end
output = File.read(File.join(fixture_dir, 'layer_ordering.json'))
expect(stylesheet.to_json).to eql(output.strip)
end

it 'includes sublayers automatically when parent is in layer_order' do
glug = File.read(File.join(fixture_dir, 'layer_ordering_sublayers.glug'))
stylesheet = described_class.new(base_dir: fixture_dir) do
instance_eval(glug)
end
output = File.read(File.join(fixture_dir, 'layer_ordering_sublayers.json'))
expect(stylesheet.to_json).to eql(output.strip)
end

it 'excludes other sublayers when one is explicitly in layer_order' do
glug = File.read(File.join(fixture_dir, 'layer_ordering_sublayers_explicit.glug'))
stylesheet = described_class.new(base_dir: fixture_dir) do
instance_eval(glug)
end
output = File.read(File.join(fixture_dir, 'layer_ordering_sublayers_explicit.json'))
expect(stylesheet.to_json).to eql(output.strip)
end

it 'excludes other sublayers when one other is mentioned and parent included' do
glug = File.read(File.join(fixture_dir, 'layer_ordering_sublayers_with_parent.glug'))
stylesheet = described_class.new(base_dir: fixture_dir) do
instance_eval(glug)
end
output = File.read(File.join(fixture_dir, 'layer_ordering_sublayers_with_parent.json'))
expect(stylesheet.to_json).to eql(output.strip)
end
end
end
Loading