@react-native-kakao/map 2.2.7 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +5 -38
- package/RNCKakaoMap.podspec +16 -52
- package/android/build.gradle +12 -107
- package/android/consumer-rules.pro +2 -0
- package/android/src/main/AndroidManifest.xml +3 -1
- package/android/src/main/java/net/mjstudio/rnkakao/map/CameraOptions.kt +61 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/KakaoMapModule.kt +131 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/KakaoMapView.kt +1257 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapCameraCommands.kt +306 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapDimScreen.kt +431 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapGui.kt +899 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapImageLoader.kt +232 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapLabels.kt +1572 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapOptions.kt +360 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapRoutes.kt +805 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapShapes.kt +1096 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapUtilities.kt +495 -0
- package/expo-module.config.json +5 -0
- package/ios/CameraOptions.swift +41 -0
- package/ios/KakaoMapModule.swift +204 -0
- package/ios/KakaoMapView.swift +1018 -0
- package/ios/MapCameraCommands.swift +451 -0
- package/ios/MapDimScreen.swift +463 -0
- package/ios/MapGui.swift +1099 -0
- package/ios/MapImageLoader.swift +177 -0
- package/ios/MapLabels.swift +1676 -0
- package/ios/MapOptions.swift +374 -0
- package/ios/MapRoutes.swift +903 -0
- package/ios/MapShapes.swift +1294 -0
- package/ios/MapUnits.swift +20 -0
- package/ios/MapUtilities.swift +365 -0
- package/lib/commonjs/index.js +180 -29
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +18 -0
- package/lib/commonjs/index.web.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types-assets.js +2 -0
- package/lib/commonjs/types-assets.js.map +1 -0
- package/lib/commonjs/types-camera.js +6 -0
- package/lib/commonjs/types-camera.js.map +1 -0
- package/lib/commonjs/types-dim.js +6 -0
- package/lib/commonjs/types-dim.js.map +1 -0
- package/lib/commonjs/types-gui.js +6 -0
- package/lib/commonjs/types-gui.js.map +1 -0
- package/lib/commonjs/types-labels.js +6 -0
- package/lib/commonjs/types-labels.js.map +1 -0
- package/lib/commonjs/types-routes.js +6 -0
- package/lib/commonjs/types-routes.js.map +1 -0
- package/lib/commonjs/types-shapes.js +6 -0
- package/lib/commonjs/types-shapes.js.map +1 -0
- package/lib/commonjs/types-utilities.js +6 -0
- package/lib/commonjs/types-utilities.js.map +1 -0
- package/lib/commonjs/types.js +6 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/index.js +180 -22
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +13 -0
- package/lib/module/index.web.js.map +1 -0
- package/lib/module/types-assets.js +2 -0
- package/lib/module/types-assets.js.map +1 -0
- package/lib/module/types-camera.js +4 -0
- package/lib/module/types-camera.js.map +1 -0
- package/lib/module/types-dim.js +4 -0
- package/lib/module/types-dim.js.map +1 -0
- package/lib/module/types-gui.js +4 -0
- package/lib/module/types-gui.js.map +1 -0
- package/lib/module/types-labels.js +4 -0
- package/lib/module/types-labels.js.map +1 -0
- package/lib/module/types-routes.js +4 -0
- package/lib/module/types-routes.js.map +1 -0
- package/lib/module/types-shapes.js +4 -0
- package/lib/module/types-shapes.js.map +1 -0
- package/lib/module/types-utilities.js +4 -0
- package/lib/module/types-utilities.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/src/index.d.ts +59 -9
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types-assets.d.ts +9 -0
- package/lib/typescript/src/types-assets.d.ts.map +1 -0
- package/lib/typescript/src/types-camera.d.ts +123 -0
- package/lib/typescript/src/types-camera.d.ts.map +1 -0
- package/lib/typescript/src/types-dim.d.ts +54 -0
- package/lib/typescript/src/types-dim.d.ts.map +1 -0
- package/lib/typescript/src/types-gui.d.ts +189 -0
- package/lib/typescript/src/types-gui.d.ts.map +1 -0
- package/lib/typescript/src/types-labels.d.ts +246 -0
- package/lib/typescript/src/types-labels.d.ts.map +1 -0
- package/lib/typescript/src/types-routes.d.ts +162 -0
- package/lib/typescript/src/types-routes.d.ts.map +1 -0
- package/lib/typescript/src/types-shapes.d.ts +253 -0
- package/lib/typescript/src/types-shapes.d.ts.map +1 -0
- package/lib/typescript/src/types-utilities.d.ts +130 -0
- package/lib/typescript/src/types-utilities.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +222 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +24 -77
- package/src/index.tsx +322 -0
- package/src/index.web.tsx +46 -0
- package/src/types-assets.ts +8 -0
- package/src/types-camera.ts +97 -0
- package/src/types-dim.ts +54 -0
- package/src/types-gui.ts +171 -0
- package/src/types-labels.ts +207 -0
- package/src/types-routes.ts +118 -0
- package/src/types-shapes.ts +244 -0
- package/src/types-utilities.ts +115 -0
- package/src/types.ts +223 -0
- package/android/gradle.properties +0 -1
- package/android/src/main/AndroidManifestNew.xml +0 -2
- package/android/src/main/java/net/mjstudio/rnkakao/map/RNCKakaoMapModule.kt +0 -25
- package/android/src/main/java/net/mjstudio/rnkakao/map/RNCKakaoMapPackage.kt +0 -35
- package/android/src/newarch/KakaoMapSpec.kt +0 -7
- package/android/src/oldarch/KakaoMapSpec.kt +0 -14
- package/ios/Component/Map/RNCKakaoMapView.h +0 -23
- package/ios/Component/Map/RNCKakaoMapView.mm +0 -209
- package/ios/Component/Map/RNCKakaoMapViewManager.mm +0 -19
- package/ios/NativeModule/RNCKakaoMap.h +0 -7
- package/ios/NativeModule/RNCKakaoMap.mm +0 -19
- package/ios/NativeModule/RNCKakaoMapManager.swift +0 -7
- package/ios/Util/Util.h +0 -97
- package/lib/commonjs/component/KakaoMapView.js +0 -54
- package/lib/commonjs/component/KakaoMapView.js.map +0 -1
- package/lib/commonjs/spec/NativeKakaoMap.js +0 -9
- package/lib/commonjs/spec/NativeKakaoMap.js.map +0 -1
- package/lib/commonjs/spec/RNCKakaoMapViewNativeComponent.js +0 -15
- package/lib/commonjs/spec/RNCKakaoMapViewNativeComponent.js.map +0 -1
- package/lib/commonjs/type/type.js +0 -2
- package/lib/commonjs/type/type.js.map +0 -1
- package/lib/commonjs/util/Const.js +0 -14
- package/lib/commonjs/util/Const.js.map +0 -1
- package/lib/commonjs/util/Util.js +0 -15
- package/lib/commonjs/util/Util.js.map +0 -1
- package/lib/module/component/KakaoMapView.js +0 -48
- package/lib/module/component/KakaoMapView.js.map +0 -1
- package/lib/module/spec/NativeKakaoMap.js +0 -3
- package/lib/module/spec/NativeKakaoMap.js.map +0 -1
- package/lib/module/spec/RNCKakaoMapViewNativeComponent.js +0 -10
- package/lib/module/spec/RNCKakaoMapViewNativeComponent.js.map +0 -1
- package/lib/module/type/type.js +0 -2
- package/lib/module/type/type.js.map +0 -1
- package/lib/module/util/Const.js +0 -8
- package/lib/module/util/Const.js.map +0 -1
- package/lib/module/util/Util.js +0 -9
- package/lib/module/util/Util.js.map +0 -1
- package/lib/typescript/src/component/KakaoMapView.d.ts +0 -25
- package/lib/typescript/src/component/KakaoMapView.d.ts.map +0 -1
- package/lib/typescript/src/spec/NativeKakaoMap.d.ts +0 -7
- package/lib/typescript/src/spec/NativeKakaoMap.d.ts.map +0 -1
- package/lib/typescript/src/spec/RNCKakaoMapViewNativeComponent.d.ts +0 -32
- package/lib/typescript/src/spec/RNCKakaoMapViewNativeComponent.d.ts.map +0 -1
- package/lib/typescript/src/type/type.d.ts +0 -8
- package/lib/typescript/src/type/type.d.ts.map +0 -1
- package/lib/typescript/src/util/Const.d.ts +0 -8
- package/lib/typescript/src/util/Const.d.ts.map +0 -1
- package/lib/typescript/src/util/Util.d.ts +0 -3
- package/lib/typescript/src/util/Util.d.ts.map +0 -1
- package/src/component/KakaoMapView.tsx +0 -82
- package/src/index.ts +0 -43
- package/src/spec/NativeKakaoMap.ts +0 -8
- package/src/spec/RNCKakaoMapViewNativeComponent.ts +0 -38
- package/src/type/type.ts +0 -7
- package/src/util/Const.ts +0 -7
- package/src/util/Util.ts +0 -11
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import CoreFoundation
|
|
2
|
+
import KakaoMapsSDK
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
private let mapDimInvalidArgument = "ERR_KAKAO_MAP_DIM_INVALID_ARGUMENT"
|
|
6
|
+
private let mapDimNotFound = "ERR_KAKAO_MAP_DIM_NOT_FOUND"
|
|
7
|
+
private let mapDimUnsupported = "ERR_KAKAO_MAP_UNSUPPORTED_PLATFORM_FEATURE"
|
|
8
|
+
|
|
9
|
+
final class MapDimScreen {
|
|
10
|
+
typealias EventEmitter = ([String: Any]) -> Void
|
|
11
|
+
|
|
12
|
+
private weak var map: KakaoMap?
|
|
13
|
+
private let emit: EventEmitter
|
|
14
|
+
private var geographicHighlights: [String: MapPolygonShape] = [:]
|
|
15
|
+
private var modelHighlights: [String: PolygonShape] = [:]
|
|
16
|
+
private var animations: [String: ShapeAnimator] = [:]
|
|
17
|
+
private var styleFingerprints: [String: String] = [:]
|
|
18
|
+
private var isDisposed = false
|
|
19
|
+
|
|
20
|
+
init(map: KakaoMap, emit: @escaping EventEmitter) {
|
|
21
|
+
self.map = map
|
|
22
|
+
self.emit = emit
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func apply(_ options: [String: Any]) throws {
|
|
26
|
+
guard !isDisposed, let dimScreen = map?.dimScreen else {
|
|
27
|
+
throw KakaoMapException(mapDimNotFound, "The map is no longer available.")
|
|
28
|
+
}
|
|
29
|
+
let parsed = try parse(options)
|
|
30
|
+
var stylesToAdd: [(id: String, fingerprint: String, native: PolygonStyleSet)] = []
|
|
31
|
+
for style in parsed.styleSets {
|
|
32
|
+
let id = try string(style, "id")
|
|
33
|
+
let fingerprint = try fingerprint(style)
|
|
34
|
+
if let current = styleFingerprints[id], current != fingerprint {
|
|
35
|
+
throw exception(
|
|
36
|
+
"Dim-screen style \(id) cannot be replaced during a map engine lifetime; use a new style ID."
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
if styleFingerprints[id] == nil {
|
|
40
|
+
try stylesToAdd.append((id, fingerprint, mapShapePolygonStyleSet(style)))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
let availableStyleIds = Set(styleFingerprints.keys).union(stylesToAdd.map(\.id))
|
|
44
|
+
let highlightIds = try Set(parsed.highlights.map { try string($0, "id") })
|
|
45
|
+
try parsed.highlights
|
|
46
|
+
.forEach { try validateHighlight($0, availableStyleIds: availableStyleIds) }
|
|
47
|
+
try parsed.animations.forEach { animation in
|
|
48
|
+
_ = try mapShapeWaveEffect(animation)
|
|
49
|
+
let id = try string(animation, "animationId")
|
|
50
|
+
let shapeIds = try strings(animation, "shapeIds")
|
|
51
|
+
guard !shapeIds.isEmpty
|
|
52
|
+
else { throw exception("Dim-screen animation \(id) requires a target.") }
|
|
53
|
+
try unique(shapeIds, name: "animation target")
|
|
54
|
+
for shapeId in shapeIds where !highlightIds.contains(shapeId) {
|
|
55
|
+
throw exception("Dim-screen animation \(id) references unknown highlight \(shapeId).")
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
clearObjects()
|
|
59
|
+
do {
|
|
60
|
+
for style in stylesToAdd {
|
|
61
|
+
dimScreen.addPolygonStyleSet(style.native)
|
|
62
|
+
styleFingerprints[style.id] = style.fingerprint
|
|
63
|
+
}
|
|
64
|
+
for highlight in parsed.highlights {
|
|
65
|
+
try addHighlight(highlight, to: dimScreen)
|
|
66
|
+
}
|
|
67
|
+
for animation in parsed.animations {
|
|
68
|
+
try addAnimation(animation, to: dimScreen)
|
|
69
|
+
}
|
|
70
|
+
dimScreen.color = try color(parsed.color)
|
|
71
|
+
dimScreen.cover = try cover(parsed.cover)
|
|
72
|
+
dimScreen.isEnabled = parsed.enabled
|
|
73
|
+
} catch {
|
|
74
|
+
clearObjects()
|
|
75
|
+
throw error
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func setHighlightVisible(id: String, visible: Bool) throws {
|
|
80
|
+
guard !isDisposed, map != nil else {
|
|
81
|
+
throw KakaoMapException(mapDimNotFound, "The dim-screen manager was disposed.")
|
|
82
|
+
}
|
|
83
|
+
if let shape = geographicHighlights[id] {
|
|
84
|
+
visible ? shape.show() : shape.hide()
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
if let shape = modelHighlights[id] {
|
|
88
|
+
visible ? shape.show() : shape.hide()
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
throw KakaoMapException(mapDimNotFound, "Dim-screen highlight \(id) was not found.")
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func startAnimation(id: String) throws {
|
|
95
|
+
try requireAnimation(id).start()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func stopAnimation(id: String) throws {
|
|
99
|
+
try requireAnimation(id).stop()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func status() throws -> [String: Any] {
|
|
103
|
+
guard let dimScreen = map?.dimScreen else {
|
|
104
|
+
throw KakaoMapException(mapDimNotFound, "The map is no longer available.")
|
|
105
|
+
}
|
|
106
|
+
let geographic = (dimScreen.getAllHighlightMapPolygonShapes() ?? []).map { shape in
|
|
107
|
+
[
|
|
108
|
+
"id": shape.shapeID,
|
|
109
|
+
"visible": shape.isShow,
|
|
110
|
+
"geometryType": "geographicPolygon"
|
|
111
|
+
] as [String: Any]
|
|
112
|
+
}
|
|
113
|
+
let model = (dimScreen.getAllHighlightPolygonShapes() ?? []).map { shape in
|
|
114
|
+
[
|
|
115
|
+
"id": shape.shapeID,
|
|
116
|
+
"visible": shape.isShow,
|
|
117
|
+
"geometryType": "modelPolygon"
|
|
118
|
+
] as [String: Any]
|
|
119
|
+
}
|
|
120
|
+
let animationStatus = animations.keys.sorted().compactMap { id -> [String: Any]? in
|
|
121
|
+
guard let animation = dimScreen.getShapeAnimator(animatorID: id) else { return nil }
|
|
122
|
+
return ["id": animation.animatorID, "running": animation.isStart]
|
|
123
|
+
}
|
|
124
|
+
return [
|
|
125
|
+
"enabled": dimScreen.isEnabled,
|
|
126
|
+
"color": colorString(dimScreen.color),
|
|
127
|
+
"cover": coverName(dimScreen.cover),
|
|
128
|
+
"highlights": (geographic + model).sorted {
|
|
129
|
+
($0["id"] as? String ?? "") < ($1["id"] as? String ?? "")
|
|
130
|
+
},
|
|
131
|
+
"animations": animationStatus,
|
|
132
|
+
"counts": [
|
|
133
|
+
"highlights": geographic.count + model.count,
|
|
134
|
+
"animations": animationStatus.count
|
|
135
|
+
],
|
|
136
|
+
"capabilities": [
|
|
137
|
+
"coversRoute": false,
|
|
138
|
+
"modelHighlights": true,
|
|
139
|
+
"modelOrientation": true,
|
|
140
|
+
"animations": true,
|
|
141
|
+
"animationDuration": true,
|
|
142
|
+
"animationState": true,
|
|
143
|
+
"nativeConfigurationState": true
|
|
144
|
+
]
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
func dispose() {
|
|
149
|
+
guard !isDisposed else { return }
|
|
150
|
+
isDisposed = true
|
|
151
|
+
map?.dimScreen.isEnabled = false
|
|
152
|
+
clearObjects()
|
|
153
|
+
map = nil
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private func addHighlight(_ value: [String: Any], to dimScreen: DimScreen) throws {
|
|
157
|
+
let id = try string(value, "id")
|
|
158
|
+
let styleSetId = try string(value, "styleSetId")
|
|
159
|
+
guard styleFingerprints[styleSetId] != nil else {
|
|
160
|
+
throw exception("Highlight \(id) references unknown style set \(styleSetId).")
|
|
161
|
+
}
|
|
162
|
+
let zIndex = try integer(value, "zIndex", default: 0)
|
|
163
|
+
let isVisible = try boolean(value, "visible", default: true)
|
|
164
|
+
let geometry = try dictionary(value, "geometry")
|
|
165
|
+
let type = try string(geometry, "type")
|
|
166
|
+
let parts = try dictionaries(geometry, "parts")
|
|
167
|
+
guard !parts.isEmpty
|
|
168
|
+
else { throw exception("Highlight \(id) requires at least one polygon part.") }
|
|
169
|
+
switch type {
|
|
170
|
+
case "geographicPolygon":
|
|
171
|
+
let option = MapPolygonShapeOptions(shapeID: id, styleID: styleSetId, zOrder: zIndex)
|
|
172
|
+
option.polygons = try parts.map(mapShapeMapPolygon)
|
|
173
|
+
guard let shape = dimScreen.addHighlightMapPolygonShape(option) else {
|
|
174
|
+
throw exception("Could not add geographic dim-screen highlight \(id).")
|
|
175
|
+
}
|
|
176
|
+
isVisible ? shape.show() : shape.hide()
|
|
177
|
+
geographicHighlights[id] = shape
|
|
178
|
+
case "modelPolygon":
|
|
179
|
+
let option = PolygonShapeOptions(shapeID: id, styleID: styleSetId, zOrder: zIndex)
|
|
180
|
+
let base = try dictionary(geometry, "base")
|
|
181
|
+
option.basePosition = try mapPoint(base)
|
|
182
|
+
option.polygons = try parts.map(mapShapeModelPolygon)
|
|
183
|
+
guard let shape = dimScreen.addHighlightPolygonShape(option) else {
|
|
184
|
+
throw exception("Could not add model dim-screen highlight \(id).")
|
|
185
|
+
}
|
|
186
|
+
shape.orientation = try orientation(geometry) * .pi / 180
|
|
187
|
+
isVisible ? shape.show() : shape.hide()
|
|
188
|
+
modelHighlights[id] = shape
|
|
189
|
+
default:
|
|
190
|
+
throw exception("Dim-screen highlights require geographicPolygon or modelPolygon geometry.")
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private func validateHighlight(_ value: [String: Any], availableStyleIds: Set<String>) throws {
|
|
195
|
+
let id = try string(value, "id")
|
|
196
|
+
let styleSetId = try string(value, "styleSetId")
|
|
197
|
+
guard availableStyleIds.contains(styleSetId) else {
|
|
198
|
+
throw exception("Highlight \(id) references unknown style set \(styleSetId).")
|
|
199
|
+
}
|
|
200
|
+
_ = try boolean(value, "visible", default: true)
|
|
201
|
+
_ = try integer(value, "zIndex", default: 0)
|
|
202
|
+
let geometry = try dictionary(value, "geometry")
|
|
203
|
+
let type = try string(geometry, "type")
|
|
204
|
+
let parts = try dictionaries(geometry, "parts")
|
|
205
|
+
guard !parts.isEmpty
|
|
206
|
+
else { throw exception("Highlight \(id) requires at least one polygon part.") }
|
|
207
|
+
switch type {
|
|
208
|
+
case "geographicPolygon": _ = try parts.map(mapShapeMapPolygon)
|
|
209
|
+
case "modelPolygon":
|
|
210
|
+
_ = try mapPoint(dictionary(geometry, "base"))
|
|
211
|
+
_ = try orientation(geometry)
|
|
212
|
+
_ = try parts.map(mapShapeModelPolygon)
|
|
213
|
+
default: throw exception(
|
|
214
|
+
"Dim-screen highlights require geographicPolygon or modelPolygon geometry."
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private func addAnimation(_ value: [String: Any], to dimScreen: DimScreen) throws {
|
|
220
|
+
let id = try string(value, "animationId")
|
|
221
|
+
guard let animator = try dimScreen.addShapeAnimator(
|
|
222
|
+
animatorID: id,
|
|
223
|
+
effect: mapShapeWaveEffect(value)
|
|
224
|
+
) else {
|
|
225
|
+
throw exception("Could not add dim-screen animation \(id).")
|
|
226
|
+
}
|
|
227
|
+
let shapeIds = try strings(value, "shapeIds")
|
|
228
|
+
guard !shapeIds.isEmpty
|
|
229
|
+
else { throw exception("Dim-screen animation \(id) requires a target.") }
|
|
230
|
+
for shapeId in shapeIds {
|
|
231
|
+
if let shape = geographicHighlights[shapeId] {
|
|
232
|
+
animator.addMapPolygonShape(shape)
|
|
233
|
+
} else if let shape = modelHighlights[shapeId] {
|
|
234
|
+
animator.addPolygonShape(shape)
|
|
235
|
+
} else {
|
|
236
|
+
throw exception("Dim-screen animation \(id) references unknown highlight \(shapeId).")
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
let animatorIdentity = ObjectIdentifier(animator)
|
|
240
|
+
animator.setStopCallback { [weak self] _ in
|
|
241
|
+
guard let self, !self.isDisposed,
|
|
242
|
+
let active = animations[id],
|
|
243
|
+
ObjectIdentifier(active) == animatorIdentity
|
|
244
|
+
else { return }
|
|
245
|
+
emit(["type": "animationStopped", "id": id])
|
|
246
|
+
}
|
|
247
|
+
animations[id] = animator
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private func clearObjects() {
|
|
251
|
+
guard let dimScreen = map?.dimScreen else { return }
|
|
252
|
+
let removedAnimations = Array(animations.values)
|
|
253
|
+
animations.removeAll()
|
|
254
|
+
removedAnimations.forEach { $0.stop() }
|
|
255
|
+
dimScreen.clearAllShapeAnimators()
|
|
256
|
+
dimScreen.clearAllHighlightShapes()
|
|
257
|
+
geographicHighlights.removeAll()
|
|
258
|
+
modelHighlights.removeAll()
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private func requireAnimation(_ id: String) throws -> ShapeAnimator {
|
|
262
|
+
guard !isDisposed, map != nil else {
|
|
263
|
+
throw KakaoMapException(mapDimNotFound, "The dim-screen manager was disposed.")
|
|
264
|
+
}
|
|
265
|
+
guard let animation = animations[id] else {
|
|
266
|
+
throw KakaoMapException(mapDimNotFound, "Dim-screen animation \(id) was not found.")
|
|
267
|
+
}
|
|
268
|
+
return animation
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private func parse(_ value: [String: Any]) throws -> (
|
|
272
|
+
enabled: Bool,
|
|
273
|
+
color: String,
|
|
274
|
+
cover: String,
|
|
275
|
+
styleSets: [[String: Any]],
|
|
276
|
+
highlights: [[String: Any]],
|
|
277
|
+
animations: [[String: Any]]
|
|
278
|
+
) {
|
|
279
|
+
let enabled = try boolean(value, "enabled")
|
|
280
|
+
if value["zIndex"] != nil {
|
|
281
|
+
throw KakaoMapException(
|
|
282
|
+
mapDimUnsupported,
|
|
283
|
+
"iOS SDK 2.12.19 does not expose dim-screen z-order."
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
let color = try string(value, "color")
|
|
287
|
+
_ = try self.color(color)
|
|
288
|
+
let cover = try string(value, "cover")
|
|
289
|
+
if cover == "mapAndRoute" {
|
|
290
|
+
throw KakaoMapException(
|
|
291
|
+
mapDimUnsupported,
|
|
292
|
+
"iOS SDK 2.12.19 does not support mapAndRoute dimming."
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
_ = try self.cover(cover)
|
|
296
|
+
let styleSets = try optionalDictionaries(value, "styleSets")
|
|
297
|
+
let highlights = try optionalDictionaries(value, "highlights")
|
|
298
|
+
let animations = try optionalDictionaries(value, "animations")
|
|
299
|
+
try unique(styleSets.map { try string($0, "id") }, name: "dim-screen style")
|
|
300
|
+
try unique(highlights.map { try string($0, "id") }, name: "dim-screen highlight")
|
|
301
|
+
try unique(animations.map { try string($0, "animationId") }, name: "dim-screen animation")
|
|
302
|
+
return (enabled, color, cover, styleSets, highlights, animations)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private func cover(_ value: String) throws -> DimScreenCover {
|
|
306
|
+
switch value {
|
|
307
|
+
case "map": .map
|
|
308
|
+
case "mapAndLabel": .mapAndLabels
|
|
309
|
+
case "all": .all
|
|
310
|
+
case "mapAndRoute": throw KakaoMapException(
|
|
311
|
+
mapDimUnsupported,
|
|
312
|
+
"iOS SDK 2.12.19 does not support mapAndRoute dimming."
|
|
313
|
+
)
|
|
314
|
+
default: throw exception("Unknown dim-screen cover: \(value).")
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private func coverName(_ value: DimScreenCover) -> String {
|
|
319
|
+
switch value {
|
|
320
|
+
case .map: "map"
|
|
321
|
+
case .mapAndLabels: "mapAndLabel"
|
|
322
|
+
case .all: "all"
|
|
323
|
+
default: "map"
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private func mapPoint(_ value: [String: Any]) throws -> MapPoint {
|
|
328
|
+
guard let latitude = value["latitude"] as? Double,
|
|
329
|
+
let longitude = value["longitude"] as? Double,
|
|
330
|
+
latitude.isFinite, longitude.isFinite,
|
|
331
|
+
(-90 ... 90).contains(latitude), (-180 ... 180).contains(longitude)
|
|
332
|
+
else { throw exception("Invalid dim-screen base coordinate.") }
|
|
333
|
+
return MapPoint(longitude: longitude, latitude: latitude)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private func orientation(_ geometry: [String: Any]) throws -> Double {
|
|
337
|
+
guard let raw = geometry["orientation"] else { return 0 }
|
|
338
|
+
guard let numeric = raw as? NSNumber,
|
|
339
|
+
CFGetTypeID(numeric) != CFBooleanGetTypeID()
|
|
340
|
+
else { throw exception("Model-polygon orientation must be numeric degrees.") }
|
|
341
|
+
let orientation = numeric.doubleValue
|
|
342
|
+
guard orientation.isFinite else {
|
|
343
|
+
throw exception("Model-polygon orientation must be finite degrees.")
|
|
344
|
+
}
|
|
345
|
+
return orientation
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private func color(_ value: String) throws -> UIColor {
|
|
349
|
+
guard value.hasPrefix("#") else {
|
|
350
|
+
throw exception("Colors must use #RRGGBB or #RRGGBBAA.")
|
|
351
|
+
}
|
|
352
|
+
let hex = String(value.dropFirst())
|
|
353
|
+
guard [6, 8].contains(hex.count), let number = UInt64(hex, radix: 16) else {
|
|
354
|
+
throw exception("Colors must use #RRGGBB or #RRGGBBAA.")
|
|
355
|
+
}
|
|
356
|
+
let alpha = hex.count == 8 ? CGFloat(number & 0xFF) / 255 : 1
|
|
357
|
+
let rgb = hex.count == 8 ? number >> 8 : number
|
|
358
|
+
return UIColor(
|
|
359
|
+
red: CGFloat((rgb >> 16) & 0xFF) / 255,
|
|
360
|
+
green: CGFloat((rgb >> 8) & 0xFF) / 255,
|
|
361
|
+
blue: CGFloat(rgb & 0xFF) / 255,
|
|
362
|
+
alpha: alpha
|
|
363
|
+
)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private func colorString(_ value: UIColor) -> String {
|
|
367
|
+
var red: CGFloat = 0
|
|
368
|
+
var green: CGFloat = 0
|
|
369
|
+
var blue: CGFloat = 0
|
|
370
|
+
var alpha: CGFloat = 0
|
|
371
|
+
guard value.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { return "#00000000" }
|
|
372
|
+
return String(
|
|
373
|
+
format: "#%02X%02X%02X%02X",
|
|
374
|
+
Int(red * 255), Int(green * 255), Int(blue * 255), Int(alpha * 255)
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private func fingerprint(_ value: [String: Any]) throws -> String {
|
|
379
|
+
guard JSONSerialization.isValidJSONObject(value) else {
|
|
380
|
+
throw exception("Dim-screen styles must contain serializable finite values.")
|
|
381
|
+
}
|
|
382
|
+
do {
|
|
383
|
+
let data = try JSONSerialization.data(withJSONObject: value, options: [.sortedKeys])
|
|
384
|
+
return data.base64EncodedString()
|
|
385
|
+
} catch {
|
|
386
|
+
throw exception("Dim-screen styles could not be serialized: \(error.localizedDescription)")
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
private func string(_ value: [String: Any], _ key: String) throws -> String {
|
|
391
|
+
guard let result = value[key] as? String, !result.isEmpty else {
|
|
392
|
+
throw exception("\(key) must be a nonempty string.")
|
|
393
|
+
}
|
|
394
|
+
return result
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private func strings(_ value: [String: Any], _ key: String) throws -> [String] {
|
|
398
|
+
guard let result = value[key] as? [String]
|
|
399
|
+
else { throw exception("\(key) must be a string array.") }
|
|
400
|
+
return result
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private func integer(_ value: [String: Any], _ key: String, default fallback: Int) throws -> Int {
|
|
404
|
+
guard let number = value[key] else { return fallback }
|
|
405
|
+
guard let numeric = number as? NSNumber,
|
|
406
|
+
CFGetTypeID(numeric) != CFBooleanGetTypeID()
|
|
407
|
+
else { throw exception("\(key) must be an integer.") }
|
|
408
|
+
let double = numeric.doubleValue
|
|
409
|
+
guard double.isFinite, double.rounded() == double,
|
|
410
|
+
double >= Double(Int32.min), double <= Double(Int32.max)
|
|
411
|
+
else { throw exception("\(key) must be a 32-bit integer.") }
|
|
412
|
+
return Int(double)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private func dictionary(_ value: [String: Any], _ key: String) throws -> [String: Any] {
|
|
416
|
+
guard let result = value[key] as? [String: Any]
|
|
417
|
+
else { throw exception("\(key) must be an object.") }
|
|
418
|
+
return result
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private func dictionaries(_ value: [String: Any], _ key: String) throws -> [[String: Any]] {
|
|
422
|
+
guard let result = value[key] as? [[String: Any]]
|
|
423
|
+
else { throw exception("\(key) must be an object array.") }
|
|
424
|
+
return result
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
private func optionalDictionaries(
|
|
428
|
+
_ value: [String: Any],
|
|
429
|
+
_ key: String
|
|
430
|
+
) throws -> [[String: Any]] {
|
|
431
|
+
guard let raw = value[key] else { return [] }
|
|
432
|
+
guard let items = raw as? [Any] else { throw exception("\(key) must be an object array.") }
|
|
433
|
+
return try items.map { item in
|
|
434
|
+
guard let object = item as? [String: Any] else {
|
|
435
|
+
throw exception("\(key) must contain only objects.")
|
|
436
|
+
}
|
|
437
|
+
return object
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
private func boolean(
|
|
442
|
+
_ value: [String: Any],
|
|
443
|
+
_ key: String,
|
|
444
|
+
default fallback: Bool? = nil
|
|
445
|
+
) throws -> Bool {
|
|
446
|
+
guard let raw = value[key] else {
|
|
447
|
+
guard let fallback else { throw exception("\(key) must be a boolean.") }
|
|
448
|
+
return fallback
|
|
449
|
+
}
|
|
450
|
+
guard let numeric = raw as? NSNumber,
|
|
451
|
+
CFGetTypeID(numeric) == CFBooleanGetTypeID()
|
|
452
|
+
else { throw exception("\(key) must be a boolean.") }
|
|
453
|
+
return numeric.boolValue
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private func unique(_ values: [String], name: String) throws {
|
|
457
|
+
guard Set(values).count == values.count else { throw exception("Duplicate \(name) ID.") }
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private func exception(_ message: String) -> KakaoMapException {
|
|
461
|
+
KakaoMapException(mapDimInvalidArgument, message)
|
|
462
|
+
}
|
|
463
|
+
}
|