Skip to content

Commit a80d2fb

Browse files
authored
feat: 添加Cluster图层功能 (#39)
1 parent 0b816f3 commit a80d2fb

31 files changed

+396
-176
lines changed

harmony/maps/Index.ets

+1
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ export * from './src/main/ets/AIRMaps/Geojson'
3131
export * from './src/main/ets/AIRMaps/AIRMapURLTile'
3232
export * from './src/main/ets/AIRMaps/AIRMapWMSTile'
3333
export * from './src/main/ets/AIRMaps/AIRMapOverlay'
34+
export * from './src/main/ets/AIRMaps/AIRMapCluster';

harmony/maps/src/main/cpp/ComponentDescriptors.h

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace react {
2727
using AIRMapUrlTileComponentDescriptor = ConcreteComponentDescriptor<AIRMapUrlTileShadowNode>;
2828
using AIRMapWMSTileComponentDescriptor = ConcreteComponentDescriptor<AIRMapWMSTileShadowNode>;
2929
using AIRMapOverlayComponentDescriptor = ConcreteComponentDescriptor<AIRMapOverlayShadowNode>;
30+
using AIRMapClusterComponentDescriptor = ConcreteComponentDescriptor<AIRMapClusterShadowNode>;
3031

3132
} // namespace react
3233
} // namespace facebook

harmony/maps/src/main/cpp/EventEmitters.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ namespace react {
199199
});
200200
}
201201

202+
//------------------------AIRMapCluster------------------------------
203+
void AIRMapClusterEventEmitter::onPress(onPressEvent event) const {
204+
dispatchEvent("press", [event](jsi::Runtime &runtime) {
205+
auto payload = jsi::Object(runtime);
206+
payload.setProperty(runtime, "points", event.points);
207+
return payload;
208+
});
209+
}
210+
202211
//------------------------AIRMapCallout------------------------------
203212
void AIRMapCalloutEventEmitter::onPress(onPressEvent event) const {
204213
dispatchEvent("press", [event = std::move(event)](jsi::Runtime &runtime) {

harmony/maps/src/main/cpp/EventEmitters.h

+11
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,16 @@ class JSI_EXPORT AIRMapOverlayEventEmitter : public ViewEventEmitter {
156156
void onPress(onPressEvent event) const;
157157
};
158158

159+
class JSI_EXPORT AIRMapClusterEventEmitter : public ViewEventEmitter {
160+
public:
161+
using ViewEventEmitter::ViewEventEmitter;
162+
163+
struct onPressEvent {
164+
std::string points;
165+
};
166+
167+
void onPress(onPressEvent event) const;
168+
};
169+
159170
} // namespace react
160171
} // namespace facebook

harmony/maps/src/main/cpp/MapsEventEmitRequestHandler.h

+37
Original file line numberDiff line numberDiff line change
@@ -467,4 +467,41 @@ class AIRMapOverlayEventEmitRequestHandler : public EventEmitRequestHandler {
467467
};
468468
};
469469

470+
enum AIRMapClusterEventType {
471+
CLUSTER_PRESS = 0,
472+
};
473+
474+
AIRMapClusterEventType getAIRMapClusterEventType(ArkJS &arkJs, napi_value eventObject) {
475+
auto eventType = arkJs.getString(arkJs.getObjectProperty(eventObject, "type"));
476+
if (eventType == "onPress") {
477+
return AIRMapClusterEventType::CLUSTER_PRESS;
478+
} else {
479+
throw std::runtime_error("Unknown Page event type");
480+
}
481+
}
482+
483+
class AIRMapClusterEventEmitRequestHandler : public EventEmitRequestHandler {
484+
public:
485+
void handleEvent(EventEmitRequestHandler::Context const &ctx) override {
486+
if (ctx.eventName != "AIRMapCluster") {
487+
return;
488+
}
489+
ArkJS arkJs(ctx.env);
490+
auto eventEmitter = ctx.shadowViewRegistry->getEventEmitter<react::AIRMapClusterEventEmitter>(ctx.tag);
491+
if (eventEmitter == nullptr) {
492+
return;
493+
}
494+
switch (getAIRMapClusterEventType(arkJs, ctx.payload)) {
495+
case AIRMapClusterEventType::CLUSTER_PRESS: {
496+
auto points = arkJs.getString(arkJs.getObjectProperty(ctx.payload, "points"));
497+
react::AIRMapClusterEventEmitter::onPressEvent event{points};
498+
eventEmitter->onPress(event);
499+
}
500+
break;
501+
default:
502+
break;
503+
}
504+
};
505+
};
506+
470507
} // namespace rnoh

harmony/maps/src/main/cpp/MapsJSIBinder.h

+9
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,13 @@ namespace rnoh {
270270
}
271271
};
272272

273+
class AIRMapClusterJSIBinder : public ViewComponentJSIBinder {
274+
facebook::jsi::Object createNativeProps(facebook::jsi::Runtime &rt) override {
275+
auto object = ViewComponentJSIBinder::createNativeProps(rt);
276+
object.setProperty(rt, "distance", "int");
277+
object.setProperty(rt, "clusterItems", "array");
278+
return object;
279+
}
280+
};
281+
273282
} // namespace rnoh

harmony/maps/src/main/cpp/MapsNapiBinder.h

+15
Original file line numberDiff line numberDiff line change
@@ -285,4 +285,19 @@ return ArkJS(env)
285285
};
286286
};
287287

288+
class AIRMapClusterNapiBinder : public ViewComponentNapiBinder {
289+
public:
290+
napi_value createProps(napi_env env, facebook::react::ShadowView const shadowView) override {
291+
napi_value napiViewProps = ViewComponentNapiBinder::createProps(env, shadowView);
292+
if (auto props = std::dynamic_pointer_cast<const facebook::react::AIRMapClusterProps>(shadowView.props)) {
293+
return ArkJS(env)
294+
.getObjectBuilder(napiViewProps)
295+
.addProperty("distance", props->distance)
296+
.addProperty("clusterItems", props->clusterItems)
297+
.build();
298+
}
299+
return napiViewProps;
300+
};
301+
};
302+
288303
} //namespace rnoh

harmony/maps/src/main/cpp/MapsPackage.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ namespace rnoh {
5252
facebook::react::concreteComponentDescriptorProvider<
5353
facebook::react::AIRMapWMSTileComponentDescriptor>(),
5454
facebook::react::concreteComponentDescriptorProvider<
55-
facebook::react::AIRMapOverlayComponentDescriptor>()};
55+
facebook::react::AIRMapOverlayComponentDescriptor>(),
56+
facebook::react::concreteComponentDescriptorProvider<
57+
facebook::react::AIRMapClusterComponentDescriptor>()};
5658
};
5759

5860
ComponentJSIBinderByString createComponentJSIBinderByName() override {
@@ -66,7 +68,8 @@ namespace rnoh {
6668
{"Geojson", std::make_shared<GeojsonJSIBinder>()},
6769
{"AIRMapUrlTile", std::make_shared<AIRMapUrlTileJSIBinder>()},
6870
{"AIRMapWMSTile", std::make_shared<AIRMapWMSTileJSIBinder>()},
69-
{"AIRMapOverlay", std::make_shared<AIRMapOverlayJSIBinder>()}};
71+
{"AIRMapOverlay", std::make_shared<AIRMapOverlayJSIBinder>()},
72+
{"AIRMapCluster", std::make_shared<AIRMapClusterJSIBinder>()}};
7073
};
7174

7275
EventEmitRequestHandlers createEventEmitRequestHandlers() override {
@@ -76,6 +79,7 @@ namespace rnoh {
7679
std::make_shared<AIRMapPolylineEventEmitRequestHandler>(),
7780
std::make_shared<AIRMapCircleEventEmitRequestHandler>(),
7881
std::make_shared<AIRMapOverlayEventEmitRequestHandler>(),
82+
std::make_shared<AIRMapClusterEventEmitRequestHandler>(),
7983
std::make_shared<AIRMapCalloutEventEmitRequestHandler>(),
8084
std::make_shared<AIRMapCalloutSubviewEventEmitRequestHandler>()};
8185
};

harmony/maps/src/main/cpp/Props.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,11 @@ namespace react {
198198
tappable(convertRawProp(context, rawProps, "tappable", sourceProps.tappable, {false})),
199199
opacity(convertRawProp(context, rawProps, "opacity", sourceProps.opacity, {1.0})) {}
200200

201+
AIRMapClusterProps::AIRMapClusterProps(const PropsParserContext &context, const AIRMapClusterProps &sourceProps,
202+
const RawProps &rawProps)
203+
: ViewProps(context, sourceProps, rawProps),
204+
distance(convertRawProp(context, rawProps, "distance", sourceProps.distance, {})),
205+
clusterItems(convertRawProp(context, rawProps, "clusterItems", sourceProps.clusterItems, {})) {}
206+
201207
} // namespace react
202208
} // namespace facebook

harmony/maps/src/main/cpp/Props.h

+11
Original file line numberDiff line numberDiff line change
@@ -257,5 +257,16 @@ namespace react {
257257
float opacity{};
258258
};
259259

260+
class JSI_EXPORT AIRMapClusterProps final : public ViewProps {
261+
public:
262+
AIRMapClusterProps() = default;
263+
AIRMapClusterProps(const PropsParserContext &context, const AIRMapClusterProps &sourceProps,
264+
const RawProps &rawProps);
265+
266+
#pragma mark - Props
267+
int distance{};
268+
folly::dynamic clusterItems{};
269+
};
270+
260271
} // namespace react
261272
} // namespace facebook

harmony/maps/src/main/cpp/ShadowNodes.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,7 @@ namespace react {
3535

3636
extern const char AIRMapOverlayComponentName[] = "AIRMapOverlay";
3737

38+
extern const char AIRMapClusterComponentName[] = "AIRMapCluster";
39+
3840
} // namespace react
3941
} // namespace facebook

harmony/maps/src/main/cpp/ShadowNodes.h

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ JSI_EXPORT extern const char AIRMapWMSTileComponentName[];
4040

4141
JSI_EXPORT extern const char AIRMapOverlayComponentName[];
4242

43+
JSI_EXPORT extern const char AIRMapClusterComponentName[];
44+
4345
/*
4446
* `ShadowNode` for <AIRMap> component.
4547
*/
@@ -65,5 +67,7 @@ using AIRMapWMSTileShadowNode = ConcreteViewShadowNode<AIRMapWMSTileComponentNam
6567

6668
using AIRMapOverlayShadowNode = ConcreteViewShadowNode<AIRMapOverlayComponentName, ViewProps, AIRMapOverlayEventEmitter>;
6769

70+
using AIRMapClusterShadowNode = ConcreteViewShadowNode<AIRMapClusterComponentName, ViewProps, AIRMapClusterEventEmitter>;
71+
6872
} // namespace react
6973
} // namespace facebook

harmony/maps/src/main/cpp/States.h

+5
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,10 @@ class AIRMapOverlayState {
6666
AIRMapOverlayState() = default;
6767
};
6868

69+
class AIRMapClusterState {
70+
public:
71+
AIRMapClusterState() = default;
72+
};
73+
6974
} // namespace react
7075
} // namespace facebook

harmony/maps/src/main/ets/AIRMaps/AIRMap.ets

+11-7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export struct AIRMap {
5151
@BuilderParam public renderChildren: () => void
5252
@State descriptor: AIRMapDescriptor = {} as AIRMapDescriptor
5353
@State loadingEnabled: boolean = false;
54+
@State initCompleted: boolean = false;
5455
protected cleanUpCallbacks: (() => void)[] = []
5556
private callback?: AsyncCallback<map.MapComponentController>;
5657
private mapController?: map.MapComponentController = undefined;
@@ -165,6 +166,7 @@ export struct AIRMap {
165166
}
166167
}
167168
MapsManager.getInstance().initMapComponentController(this.mapController)
169+
this.initCompleted = true;
168170

169171
// mapview
170172
this.mapController.on("mapLoad", () => {
@@ -414,13 +416,15 @@ export struct AIRMap {
414416
Stack() {
415417
// 调用MapComponent组件初始化地图
416418
MapComponent({ mapOptions: this.mapOptions, mapCallback: this.callback }).width('100%').height('100%');
417-
ForEach(this.descriptor.childrenTags, (tag: Tag) => {
418-
// this.ctx.wrappedRNChildrenBuilder.builder(this.ctx, tag)
419-
mapsComponentFactoryBuilder(
420-
this.ctx,
421-
tag,
422-
this.ctx.rnInstance.getComponentNameFromDescriptorType(this.ctx.descriptorRegistry.getDescriptor(tag)?.type))
423-
}, (tag: Tag) => tag.toString())
419+
if (this.initCompleted) {
420+
ForEach(this.descriptor.childrenTags, (tag: Tag) => {
421+
mapsComponentFactoryBuilder(
422+
this.ctx,
423+
tag,
424+
this.ctx.rnInstance.getComponentNameFromDescriptorType(this.ctx.descriptorRegistry.getDescriptor(tag)?.type))
425+
}, (tag: Tag) => tag.toString())
426+
}
427+
424428
if (this.loadingEnabled) {
425429
LoadingProgress()
426430
.color(this.descriptor.rawProps.loadingIndicatorColor)

harmony/maps/src/main/ets/AIRMaps/AIRMapCallout.ets

+1-7
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,7 @@ export struct AIRMapCallout {
4444
this.descriptor = (newDescriptor as AIRMapCalloutDescriptor)
4545
}
4646
)
47-
if (MapsManager.getInstance().isInitMapController()) {
48-
MapsManager.getInstance().addCallout(this);
49-
}else {
50-
setTimeout(()=>{
51-
MapsManager.getInstance().addCallout(this);
52-
}, 500)
53-
}
47+
MapsManager.getInstance().addCallout(this);
5448
}
5549

5650
aboutToDisappear() {

harmony/maps/src/main/ets/AIRMaps/AIRMapCalloutSubview.ets

+1-3
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ export struct AIRMapCalloutSubview {
4545
}
4646
)
4747

48-
setTimeout(()=>{
49-
MapsManager.getInstance().addCalloutSubview(this.descriptor);
50-
}, 500)
48+
MapsManager.getInstance().addCalloutSubview(this.descriptor);
5149
}
5250

5351
aboutToDisappear() {

harmony/maps/src/main/ets/AIRMaps/AIRMapCircle.ets

-10
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,6 @@ export struct AIRMapCircle {
5555
}
5656
)
5757

58-
if (MapsManager.getInstance().isInitMapController()) {
59-
this.setInstance();
60-
} else {
61-
setTimeout(()=>{
62-
this.setInstance();
63-
}, 500)
64-
}
65-
}
66-
67-
setInstance() {
6858
MapsManager.getInstance().addCircle(this.descriptor, this.ctx)?.then(instance => {
6959
this.instance = instance;
7060
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (C) 2024 Huawei Device Co., Ltd.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
import { map } from '@kit.MapKit';
23+
import { RNComponentContext, ComponentBuilderContext } from '@rnoh/react-native-openharmony';
24+
import { MapsManager } from '../MapsManager';
25+
import { AIRMapClusterDescriptor } from './AIRMapDescriptorTypes';
26+
27+
export const AIR_MAP_CLUSTER_TYPE: string = 'AIRMapCluster';
28+
29+
@Component
30+
export struct AIRMapCluster {
31+
ctx!: RNComponentContext;
32+
tag: number = 0;
33+
@BuilderParam buildCustomComponent: (componentBuilderContext: ComponentBuilderContext) => void;
34+
@State descriptor: AIRMapClusterDescriptor = {} as AIRMapClusterDescriptor;
35+
private unregisterDescriptorChangesListener?: () => void = undefined;
36+
private instance?: map.ClusterOverlay;
37+
38+
aboutToAppear() {
39+
this.descriptor = this.ctx.descriptorRegistry.getDescriptor<AIRMapClusterDescriptor>(this.tag);
40+
this.unregisterDescriptorChangesListener = this.ctx.descriptorRegistry.subscribeToDescriptorChanges(this.tag,
41+
(newDescriptor) => {
42+
this.descriptor = (newDescriptor as AIRMapClusterDescriptor);
43+
}
44+
);
45+
46+
MapsManager.getInstance().addCluster(this.descriptor, this.ctx)?.then(instance => {
47+
this.instance = instance;
48+
});
49+
}
50+
51+
aboutToDisappear() {
52+
this.unregisterDescriptorChangesListener?.();
53+
this.instance?.off('click');
54+
this.instance?.remove();
55+
}
56+
57+
build() {
58+
}
59+
}

harmony/maps/src/main/ets/AIRMaps/AIRMapDescriptorTypes.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,11 @@ export interface AIRMapOverlayRawProps extends ViewRawProps {
202202
tappable: boolean;
203203
opacity: number;
204204
}
205-
export type AIRMapOverlayDescriptor = Descriptor<"AIRMapOverlay", ViewBaseProps, AIRMapOverlayState, AIRMapOverlayRawProps>
205+
export type AIRMapOverlayDescriptor = Descriptor<"AIRMapOverlay", ViewBaseProps, AIRMapOverlayState, AIRMapOverlayRawProps>
206+
207+
export interface AIRMapClusterState {}
208+
export interface AIRMapClusterRawProps extends ViewRawProps {
209+
distance: number;
210+
clusterItems: Array<{ position: LatLng }>;
211+
}
212+
export type AIRMapClusterDescriptor = Descriptor<"AIRMapCluster", ViewBaseProps, AIRMapClusterState, AIRMapClusterRawProps>

harmony/maps/src/main/ets/AIRMaps/AIRMapMarker.ets

+1-7
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,7 @@ export struct AIRMapMarker {
8181
}
8282
}));
8383

84-
if (MapsManager.getInstance().isInitMapController()) {
85-
this.setInstance();
86-
} else {
87-
setTimeout(()=>{
88-
this.setInstance();
89-
}, 500)
90-
}
84+
this.setInstance();
9185
}
9286

9387
setInstance() {

0 commit comments

Comments
 (0)