Skip to content
Merged
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
37 changes: 37 additions & 0 deletions Sources/MapConductorForMapbox/MapboxOverlayStacking.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import MapboxMaps
@_spi(MapConductorDriver) import MapConductorCore

/// オーバーレイのレイヤを、重なり順の帯(``OverlayBand``)の位置へ置くための `LayerPosition`。
///
/// 下から ラスター < グラウンドイメージ < ポリゴン < サークル < ポリライン < マーカー。
/// 追加した順・送り直した順・デザイン変更の後の作り直しの順に左右されない。
/// 以前は各描画担当が `addLayer(_:)`(一番上に積む)で足していたので、後から足したもの
/// (clearOverlays の後に送り直したグラウンドイメージなど)が上に来ていた。
///
/// ラスターだけはベースマップのラベルの下に置く(ラベルを覆わないため。従来どおり)。
/// Standard スタイルのようにベースマップが import でトップレベルのレイヤを持たないときは
/// 天井が見つからず、ほかのオーバーレイより下という帯の条件だけで置く。
enum MapboxOverlayStacking {
static func position(
for key: OverlayStackKey,
in mapboxMap: MapboxMap,
excluding layerId: String? = nil,
rasterZIndex: [String: Int] = [:]
) -> LayerPosition {
let layers = mapboxMap.allLayerIdentifiers.filter { $0.id != layerId }
let keys: [OverlayStackKey?] = layers.map { info in
guard let band = OverlayStacking.band(ofStyleLayerId: info.id) else { return nil }
return OverlayStackKey(band, zIndex: band == .rasterLayer ? (rasterZIndex[info.id] ?? 0) : 0)
}
let ceiling = key.band == .rasterLayer
? layers.firstIndex { $0.type == .symbol && OverlayStacking.band(ofStyleLayerId: $0.id) == nil }
: nil
let index = OverlayStacking.insertionIndex(for: key, among: keys, ceiling: ceiling)
return index >= layers.count ? .default : .below(layers[index].id)
}

static func add(_ layer: any Layer, _ key: OverlayStackKey, to mapboxMap: MapboxMap) {
try? mapboxMap.addLayer(layer, layerPosition: position(for: key, in: mapboxMap))
}
}
3 changes: 2 additions & 1 deletion Sources/MapConductorForMapbox/circle/CircleLayer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import MapboxMaps
@_spi(MapConductorDriver) import MapConductorCore

/// Draws circles as "fill (FillLayer) + stroke (LineLayer)".
///
Expand Down Expand Up @@ -46,7 +47,7 @@ final class CircleLayer {
if !mapboxMap.layerExists(withId: layerId) {
var fillLayer = FillLayer(id: layerId, source: sourceId)
fillLayer.fillColor = .expression(Exp(.toColor) { Exp(.get) { Prop.fillColor } })
try? mapboxMap.addLayer(fillLayer)
MapboxOverlayStacking.add(fillLayer, OverlayStackKey(.circle), to: mapboxMap)
}

if !mapboxMap.layerExists(withId: strokeLayerId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation
import MapboxMaps
import MapConductorCore
@_spi(MapConductorDriver) import MapConductorCore
import UIKit

@MainActor
Expand Down Expand Up @@ -115,7 +115,7 @@ final class MapboxGroundImageOverlayRenderer: AbstractGroundImageOverlayRenderer

var layer = RasterLayer(id: layerId, source: sourceId)
layer.rasterOpacity = .constant(opacity.clampedOpacity)
try? mapboxMap.addLayer(layer)
MapboxOverlayStacking.add(layer, OverlayStackKey(.groundImage), to: mapboxMap)
}

private func removeSourceAndLayerIfExists(mapboxMap: MapboxMap, sourceId: String, layerId: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,8 @@ final class MapboxMarkerController: AbstractMarkerController<Feature, MapboxMark
try? mapboxMap.addSource(source)

let layer = RasterLayer(id: layerId, source: sourceId)
try? mapboxMap.addLayer(layer)
// マーカーのタイルはマーカーと同じ帯。
MapboxOverlayStacking.add(layer, OverlayStackKey(.marker), to: mapboxMap)
}

private func subscribeToMarker(_ state: MarkerState) {
Expand Down
3 changes: 2 additions & 1 deletion Sources/MapConductorForMapbox/marker/MarkerLayer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import MapboxMaps
@_spi(MapConductorDriver) import MapConductorCore

final class MarkerLayer {
enum Prop {
Expand Down Expand Up @@ -68,7 +69,7 @@ final class MarkerLayer {
Double(1)
}
)
try? mapboxMap.addLayer(layer)
MapboxOverlayStacking.add(layer, OverlayStackKey(.marker), to: mapboxMap)
}

func setFeatures(_ features: [Feature], mapboxMap: MapboxMap) {
Expand Down
5 changes: 3 additions & 2 deletions Sources/MapConductorForMapbox/polygon/PolygonLayer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import MapboxMaps
@_spi(MapConductorDriver) import MapConductorCore

final class PolygonLayer {
enum Prop {
Expand Down Expand Up @@ -40,7 +41,7 @@ final class PolygonLayer {
if !mapboxMap.layerExists(withId: fillLayerId) {
var fillLayer = FillLayer(id: fillLayerId, source: sourceId)
fillLayer.fillColor = .expression(Exp(.toColor) { Exp(.get) { Prop.fillColor } })
try? mapboxMap.addLayer(fillLayer)
MapboxOverlayStacking.add(fillLayer, OverlayStackKey(.polygon), to: mapboxMap)
}

if !mapboxMap.layerExists(withId: lineLayerId) {
Expand All @@ -49,7 +50,7 @@ final class PolygonLayer {
lineLayer.lineWidth = .expression(Exp(.toNumber) { Exp(.get) { Prop.strokeWidth } })
lineLayer.lineJoin = .constant(.round)
lineLayer.lineCap = .constant(.round)
try? mapboxMap.addLayer(lineLayer)
MapboxOverlayStacking.add(lineLayer, OverlayStackKey(.polygon), to: mapboxMap)
}
}

Expand Down
3 changes: 2 additions & 1 deletion Sources/MapConductorForMapbox/polyline/PolylineLayer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import MapboxMaps
@_spi(MapConductorDriver) import MapConductorCore

final class PolylineLayer {
enum Prop {
Expand Down Expand Up @@ -40,7 +41,7 @@ final class PolylineLayer {
layer.lineWidth = .expression(Exp(.toNumber) { Exp(.get) { Prop.strokeWidth } })
layer.lineJoin = .constant(.round)
layer.lineCap = .constant(.round)
try? mapboxMap.addLayer(layer)
MapboxOverlayStacking.add(layer, OverlayStackKey(.polyline), to: mapboxMap)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import MapboxMaps
import MapConductorCore
@_spi(MapConductorDriver) import MapConductorCore

@MainActor
final class MapboxRasterLayerOverlayRenderer: AbstractRasterLayerOverlayRenderer<MapboxRasterLayer> {
Expand Down Expand Up @@ -45,7 +45,16 @@ final class MapboxRasterLayerOverlayRenderer: AbstractRasterLayerOverlayRenderer
NSLog("[MapConductor] RasterLayer debug mode: id=%@", current.state.id)
}
if finger.zIndex != prevFinger.zIndex {
try? mapboxMap.moveLayer(withId: layer.layerId, to: current.state.zIndex > 0 ? .at(current.state.zIndex) : .default)
zIndexByLayerId[layer.layerId] = current.state.zIndex
try? mapboxMap.moveLayer(
withId: layer.layerId,
to: MapboxOverlayStacking.position(
for: OverlayStacking.rasterKey(stateId: current.state.id, zIndex: current.state.zIndex),
in: mapboxMap,
excluding: layer.layerId,
rasterZIndex: zIndexByLayerId
)
)
}
if finger.opacity != prevFinger.opacity {
try? mapboxMap.updateLayer(withId: layer.layerId, type: MapboxMaps.RasterLayer.self) { l in
Expand Down Expand Up @@ -113,28 +122,22 @@ final class MapboxRasterLayerOverlayRenderer: AbstractRasterLayerOverlayRenderer
try? mapboxMap.addLayer(layer, layerPosition: layerPosition)
}

/// A raster overlay goes above the basemap's geometry but **below its
/// labels**.
/// 帯の順の位置(ラスターの帯の中は zIndex、ベースマップのラベルの下)。``MapboxOverlayStacking`` を参照。
///
/// Added at the top of the style instead, it covers the place names, road
/// names and shields the backend draws -- a vector tile layer's own roads
/// run straight through them, which is what "the labels are under the
/// lines" looks like. Every raster overlay we add has the same problem, so
/// the rule lives here rather than in each of them.
///
/// An explicit zIndex still wins: a caller that has said where the layer
/// goes has said it for a reason. Our own layers are skipped when looking
/// for the anchor -- markers are a symbol layer too, and anchoring to them
/// would put the raster back above the labels.
/// 以前は `zIndex > 0` をスタイル全体の生の添字(`.at(zIndex)`)として使っていて、
/// ベースマップのレイヤの間(多くは地図の下)へ入っていた。
private func layerPosition(for state: RasterLayerState, mapboxMap: MapboxMap) -> LayerPosition {
if state.zIndex > 0 { return .at(state.zIndex) }
let anchor = mapboxMap.allLayerIdentifiers.first {
$0.type == .symbol && !$0.id.hasPrefix("mapconductor-")
}
guard let anchor else { return .default }
return .below(anchor.id)
zIndexByLayerId["mapconductor-raster-layer-\(state.id)"] = state.zIndex
return MapboxOverlayStacking.position(
for: OverlayStacking.rasterKey(stateId: state.id, zIndex: state.zIndex),
in: mapboxMap,
rasterZIndex: zIndexByLayerId
)
}

/// 差し込み位置を決めるための、載せているラスターの zIndex(スタイルのレイヤは zIndex を持たない)。
private var zIndexByLayerId: [String: Int] = [:]

private func removeIfExists(mapboxMap: MapboxMap, sourceId: String, layerId: String) {
if mapboxMap.layerExists(withId: layerId) { try? mapboxMap.removeLayer(withId: layerId) }
if mapboxMap.sourceExists(withId: sourceId) { try? mapboxMap.removeSource(withId: sourceId) }
Expand Down