(options).load(
101 | points.map((marker) => ({
102 | type: "Feature",
103 | geometry: {
104 | type: "Point",
105 | coordinates: [marker.position.longitude, marker.position.latitude],
106 | },
107 | properties: marker.properties,
108 | }))
109 | );
110 | if (this.status) {
111 | this.update(this.status);
112 | }
113 | }
114 |
115 | /**
116 | * 需要在 MapView.onCameraIdle({ nativeEvent }) 回调里调用,参数为 nativeEvent
117 | */
118 | async update(status: CameraEvent) {
119 | this.status = status;
120 | await new Promise((resolve) => setTimeout(resolve, 0));
121 | const { cameraPosition, latLngBounds } = status;
122 | const { southwest, northeast } = latLngBounds;
123 | const clusters = this.cluster!.getClusters(
124 | [southwest.longitude, southwest.latitude, northeast.longitude, northeast.latitude],
125 | Math.round(cameraPosition.zoom!)
126 | );
127 | this.setState({ clusters });
128 | }
129 |
130 | renderCluster = (cluster: ClusterParams) => {
131 | return (
132 |
139 | );
140 | };
141 |
142 | render() {
143 | const { renderCluster, renderMarker } = this.props;
144 | const render = renderCluster || this.renderCluster;
145 | return this.state.clusters.map(({ geometry, properties }) => {
146 | const position = {
147 | latitude: geometry.coordinates[1],
148 | longitude: geometry.coordinates[0],
149 | };
150 |
151 | if (properties.point_count > 0) {
152 | const { cluster_id, point_count } = properties;
153 | return render({ position, id: cluster_id, count: point_count });
154 | }
155 |
156 | return renderMarker({ position, properties });
157 | });
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/lib/src/component.ts:
--------------------------------------------------------------------------------
1 | import { PureComponent } from "react";
2 | import { findNodeHandle, UIManager } from "react-native";
3 |
4 | export default class Component extends PureComponent
{
5 | /**
6 | * 原生 View 名称,继承时必须指定
7 | */
8 | name = "";
9 | mounted = false;
10 |
11 | componentDidMount() {
12 | this.mounted = true;
13 | }
14 |
15 | componentWillUnmount() {
16 | this.mounted = false;
17 | }
18 |
19 | /**
20 | * 调用原生方法
21 | */
22 | invoke(name: string, params?: any[]) {
23 | if (!this.mounted) return;
24 |
25 | const handle = findNodeHandle(this);
26 | if (handle) {
27 | const command = UIManager.getViewManagerConfig(this.name).Commands[name];
28 | UIManager.dispatchViewManagerCommand(handle, command, params);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/src/heat-map.tsx:
--------------------------------------------------------------------------------
1 | import { requireNativeComponent } from "react-native";
2 | import { LatLng } from "./types";
3 |
4 | export interface HeatMapProps {
5 | /**
6 | * 节点坐标
7 | */
8 | data: LatLng[];
9 |
10 | /**
11 | * 半径(米)
12 | */
13 | radius?: number;
14 |
15 | /**
16 | * 透明度
17 | */
18 | opacity?: number;
19 | }
20 |
21 | export default requireNativeComponent("AMapHeatMap");
22 |
--------------------------------------------------------------------------------
/lib/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Circle } from "./circle";
2 | export { default as Cluster } from "./cluster";
3 | export { default as HeatMap } from "./heat-map";
4 | export { default as MapView } from "./map-view";
5 | export { default as Marker } from "./marker";
6 | export { default as MultiPoint } from "./multi-point";
7 | export { default as Polygon } from "./polygon";
8 | export { default as Polyline } from "./polyline";
9 | export * from "./types";
10 | export { AMapSdk };
11 | import * as AMapSdk from "./sdk";
12 |
--------------------------------------------------------------------------------
/lib/src/map-view.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import {
3 | NativeMethods,
4 | NativeSyntheticEvent,
5 | requireNativeComponent,
6 | ViewProps,
7 | } from "react-native";
8 | import Component from "./component";
9 | import { CameraPosition, LatLng, LatLngBounds, MapPoi, MapType, Point } from "./types";
10 |
11 | export interface CameraEvent {
12 | cameraPosition: CameraPosition;
13 | latLngBounds: LatLngBounds;
14 | }
15 |
16 | export interface MapViewProps extends ViewProps {
17 | /**
18 | * 地图类型
19 | */
20 | mapType?: MapType;
21 |
22 | /**
23 | * 初始状态
24 | */
25 | initialCameraPosition?: CameraPosition;
26 |
27 | /**
28 | * 是否显示当前定位
29 | */
30 | myLocationEnabled?: boolean;
31 |
32 | /**
33 | * 是否显示室内地图
34 | */
35 | indoorViewEnabled?: boolean;
36 |
37 | /**
38 | * 是否显示3D建筑
39 | */
40 | buildingsEnabled?: boolean;
41 |
42 | /**
43 | * 是否显示标注
44 | */
45 | labelsEnabled?: boolean;
46 |
47 | /**
48 | * 是否显示指南针
49 | */
50 | compassEnabled?: boolean;
51 |
52 | /**
53 | * 是否显示放大缩小按钮
54 | *
55 | * @platform android
56 | */
57 | zoomControlsEnabled?: boolean;
58 |
59 | /**
60 | * 是否显示比例尺
61 | */
62 | scaleControlsEnabled?: boolean;
63 |
64 | /**
65 | * 是否显示定位按钮
66 | *
67 | * @platform android
68 | */
69 | myLocationButtonEnabled?: boolean;
70 |
71 | /**
72 | * 是否显示路况
73 | */
74 | trafficEnabled?: boolean;
75 |
76 | /**
77 | * 最大缩放级别
78 | */
79 | maxZoom?: number;
80 |
81 | /**
82 | * 最小缩放级别
83 | */
84 | minZoom?: number;
85 |
86 | /**
87 | * 是否启用缩放手势,用于放大缩小
88 | */
89 | zoomGesturesEnabled?: boolean;
90 |
91 | /**
92 | * 是否启用滑动手势,用于平移
93 | */
94 | scrollGesturesEnabled?: boolean;
95 |
96 | /**
97 | * 是否启用旋转手势,用于调整方向
98 | */
99 | rotateGesturesEnabled?: boolean;
100 |
101 | /**
102 | * 是否启用倾斜手势,用于改变视角
103 | */
104 | tiltGesturesEnabled?: boolean;
105 |
106 | /**
107 | * 设定定位的最小更新距离
108 | *
109 | * @platform ios
110 | */
111 | distanceFilter?: number;
112 |
113 | /**
114 | * 设定最小更新角度,默认为 1 度
115 | *
116 | * @platform ios
117 | */
118 | headingFilter?: number;
119 |
120 | /**
121 | * 点击事件
122 | */
123 | onPress?: (event: NativeSyntheticEvent) => void;
124 |
125 | /**
126 | * 标注点击事件
127 | */
128 | onPressPoi?: (event: NativeSyntheticEvent) => void;
129 |
130 | /**
131 | * 长按事件
132 | */
133 | onLongPress?: (event: NativeSyntheticEvent) => void;
134 |
135 | /**
136 | * 地图状态改变事件,随地图状态变化不停地触发
137 | */
138 | onCameraMove?: (event: NativeSyntheticEvent) => void;
139 |
140 | /**
141 | * 地图状态改变事件,在停止变化后触发
142 | */
143 | onCameraIdle?: (event: NativeSyntheticEvent) => void;
144 |
145 | /**
146 | * 地图初始化完成事件
147 | */
148 | onLoad?: (event: NativeSyntheticEvent) => void;
149 |
150 | /**
151 | * 地图定位更新事件
152 | */
153 | onLocation?: (event: NativeSyntheticEvent) => void;
154 | }
155 |
156 | const name = "AMapView";
157 | const NativeMapView = requireNativeComponent(name);
158 |
159 | export default class extends Component {
160 | static defaultProps = {
161 | style: { flex: 1 },
162 | compassEnabled: true,
163 | scaleControlsEnabled: true,
164 | distanceFilter: 1,
165 | };
166 |
167 | name = name;
168 | ref?: (React.Component & NativeMethods) | null;
169 | state = { loaded: false };
170 | callbackMap: { [key: number]: (data: any) => void } = {};
171 |
172 | /**
173 | * 移动视角
174 | */
175 | moveCamera(cameraPosition: CameraPosition, duration = 0) {
176 | this.invoke("moveCamera", [cameraPosition, duration]);
177 | }
178 |
179 | /**
180 | * 点坐标转地理坐标,主要用于地图选点
181 | */
182 | getLatLng(point: Point): Promise {
183 | return this.call("getLatLng", point);
184 | }
185 |
186 | callback = ({ nativeEvent }: NativeSyntheticEvent<{ id: number; data: any }>) => {
187 | this.callbackMap[nativeEvent.id]?.call(this, nativeEvent.data);
188 | delete this.callbackMap[nativeEvent.id];
189 | };
190 |
191 | call(name: string, args: any): Promise {
192 | const id = Math.random();
193 | this.invoke("call", [id, name, args]);
194 | return new Promise((resolve) => (this.callbackMap[id] = resolve));
195 | }
196 |
197 | componentDidMount() {
198 | super.componentDidMount();
199 | // 无论如何也要在 1 秒后 setLoaded(true) ,防止 onLoad 事件不触发的情况下显示不正常
200 | // 目前只在 iOS 上低概率出现
201 | setTimeout(() => this.setState({ loaded: true }), 1000);
202 | }
203 |
204 | render() {
205 | let { style, onLoad } = this.props;
206 | if (!this.state.loaded) {
207 | style = [style, { width: 1, height: 1 }];
208 | }
209 | return (
210 | (this.ref = ref)}
213 | style={style}
214 | // @ts-ignore: 内部接口
215 | onCallback={this.callback}
216 | onPress={(event) => {
217 | if (event.nativeEvent.latitude) {
218 | this.props.onPress?.call(this, event);
219 | }
220 | }}
221 | onLoad={(event) => {
222 | // android 地图部分控件不显示的问题在重新 layout 之后会恢复正常。
223 | // 同时也能修复 ios 地图偶尔出现的 layout 异常
224 | this.setState({ loaded: true });
225 | onLoad?.call(this, event);
226 | }}
227 | />
228 | );
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/lib/src/marker.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import {
3 | ImageSourcePropType,
4 | NativeSyntheticEvent,
5 | requireNativeComponent,
6 | View,
7 | ViewStyle,
8 | } from "react-native";
9 | // @ts-ignore
10 | import resolveAssetSource from "react-native/Libraries/Image/resolveAssetSource";
11 | import Component from "./component";
12 | import { LatLng, Point } from "./types";
13 |
14 | export interface MarkerProps {
15 | /**
16 | * 坐标
17 | */ position: LatLng;
18 |
19 | /**
20 | * 图标
21 | */
22 | icon?: ImageSourcePropType;
23 |
24 | /**
25 | * 透明度 [0, 1]
26 | *
27 | * @platform android
28 | */
29 | opacity?: number;
30 |
31 | /**
32 | * 是否可拖拽
33 | */
34 | draggable?: boolean;
35 |
36 | /**
37 | * 是否平贴地图
38 | *
39 | * @platform android
40 | */
41 | flat?: boolean;
42 |
43 | /**
44 | * 层级
45 | */
46 | zIndex?: number;
47 |
48 | /**
49 | * 覆盖物锚点比例
50 | *
51 | * @link http://a.amap.com/lbs/static/unzip/Android_Map_Doc/3D/com/amap/api/maps/model/Marker.html#setAnchor-float-float-
52 | * @platform android
53 | */
54 | anchor?: Point;
55 |
56 | /**
57 | * 覆盖物偏移位置
58 | *
59 | * @link http://a.amap.com/lbs/static/unzip/iOS_Map_Doc/AMap_iOS_API_Doc_3D/interface_m_a_annotation_view.html#a78f23c1e6a6d92faf12a00877ac278a7
60 | * @platform ios
61 | */
62 | centerOffset?: Point;
63 |
64 | /**
65 | * 自定义 View
66 | */
67 | children?: React.ReactNode;
68 |
69 | /**
70 | * 点击事件
71 | */
72 | onPress?: () => void;
73 |
74 | /**
75 | * 拖放开始事件
76 | */
77 | onDragStart?: () => void;
78 |
79 | /**
80 | * 拖放进行事件,类似于 mousemove,在结束之前会不断调用
81 | */
82 | onDrag?: () => void;
83 |
84 | /**
85 | * 拖放结束事件
86 | */
87 | onDragEnd?: (event: NativeSyntheticEvent) => void;
88 | }
89 |
90 | export default class extends Component {
91 | name = name;
92 |
93 | /**
94 | * 触发自定义 view 更新
95 | *
96 | * 通常来说,不需要主动调用该方法,对于 android,如果自定义 view 存在异步更新,
97 | * 例如,包含一个引用了网络图片的 ,则需要在 view 更新后主动调用该方法触发
98 | * icon 更新。
99 | */
100 | update = () => {
101 | setTimeout(() => this.invoke("update"), 0);
102 | };
103 |
104 | componentDidUpdate() {
105 | if (this.props.children) {
106 | this.update();
107 | }
108 | }
109 |
110 | render() {
111 | const props = { ...this.props };
112 | Reflect.set(props, "latLng", props.position);
113 | // @ts-ignore android 不能用 position 作为属性,会发生冲突,也是个蛋疼的问题
114 | delete props.position;
115 | if (props.children) {
116 | props.children = (
117 |
118 | {props.children}
119 |
120 | );
121 | }
122 | return ;
123 | }
124 | }
125 |
126 | const name = "AMapMarker";
127 | const style: ViewStyle = { position: "absolute", zIndex: -1 };
128 | const NativeMarker = requireNativeComponent(name);
129 |
--------------------------------------------------------------------------------
/lib/src/multi-point.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { ImageSourcePropType, NativeSyntheticEvent, requireNativeComponent } from "react-native";
3 | // @ts-ignore
4 | import resolveAssetSource from "react-native/Libraries/Image/resolveAssetSource";
5 | import { LatLng } from "./types";
6 |
7 | const NativeMultiPoint = requireNativeComponent("AMapMultiPoint");
8 |
9 | export interface MultiPointProps {
10 | /**
11 | * 坐标点集合
12 | */
13 | items?: LatLng[];
14 |
15 | /**
16 | * 图标
17 | */
18 | icon?: ImageSourcePropType;
19 |
20 | /**
21 | * 点击事件
22 | */
23 | onPress?: (event: NativeSyntheticEvent<{ index: number }>) => void;
24 | }
25 |
26 | export default (props: MultiPointProps) => {
27 | return ;
28 | };
29 |
--------------------------------------------------------------------------------
/lib/src/polygon.tsx:
--------------------------------------------------------------------------------
1 | import { requireNativeComponent } from "react-native";
2 | import { LatLng } from "./types";
3 |
4 | export interface Polygon {
5 | /**
6 | * 节点坐标
7 | */
8 | points: LatLng[];
9 |
10 | /**
11 | * 边线宽度
12 | */
13 | strokeWidth?: number;
14 |
15 | /**
16 | * 边线颜色
17 | */
18 | strokeColor?: string;
19 |
20 | /**
21 | * 填充颜色
22 | */
23 | fillColor?: string;
24 |
25 | /**
26 | * 层级
27 | */
28 | zIndex?: number;
29 | }
30 |
31 | export default requireNativeComponent("AMapPolygon");
32 |
--------------------------------------------------------------------------------
/lib/src/polyline.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { ColorValue, Platform, processColor, requireNativeComponent } from "react-native";
3 | import { LatLng } from "./types";
4 |
5 | export interface PolylineProps {
6 | /**
7 | * 节点坐标
8 | */
9 | points: LatLng[];
10 |
11 | /**
12 | * 线段宽度
13 | */
14 | width?: number;
15 |
16 | /**
17 | * 线段颜色
18 | */
19 | color?: ColorValue;
20 |
21 | /**
22 | * 层级
23 | */
24 | zIndex?: number;
25 |
26 | /**
27 | * 多段颜色
28 | */
29 | colors: ColorValue[];
30 |
31 | /**
32 | * 是否使用颜色渐变
33 | */
34 | gradient?: boolean;
35 |
36 | /**
37 | * 是否绘制大地线
38 | */
39 | geodesic?: boolean;
40 |
41 | /**
42 | * 是否绘制虚线
43 | */
44 | dotted?: boolean;
45 |
46 | /**
47 | * 点击事件
48 | */
49 | onPress?: () => void;
50 | }
51 |
52 | export default class extends React.PureComponent {
53 | static defaultProps = { colors: [] };
54 |
55 | render() {
56 | const props = {
57 | ...this.props,
58 | ...Platform.select({ android: { colors: this.props.colors.map(processColor) } }),
59 | };
60 | // @ts-ignore
61 | return ;
62 | }
63 | }
64 |
65 | const NativePolyline = requireNativeComponent("AMapPolyline");
66 |
--------------------------------------------------------------------------------
/lib/src/sdk.ts:
--------------------------------------------------------------------------------
1 | import { NativeModules } from "react-native";
2 |
3 | const { AMapSdk } = NativeModules;
4 |
5 | export function init(apiKey?: string) {
6 | AMapSdk.initSDK(apiKey);
7 | }
8 |
9 | export function getVersion(): Promise {
10 | return AMapSdk.getVersion();
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/types.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 点坐标
3 | */
4 | export interface Point {
5 | x: number;
6 | y: number;
7 | }
8 |
9 | /**
10 | * 地理坐标
11 | */
12 | export interface LatLng {
13 | /**
14 | * 纬度
15 | */
16 | latitude: number;
17 |
18 | /**
19 | * 经度
20 | */
21 | longitude: number;
22 | }
23 |
24 | /**
25 | * 地图标注点
26 | */
27 | export interface MapPoi {
28 | /**
29 | * 标注点 ID
30 | */
31 | id: string;
32 |
33 | /**
34 | * 标注点名称
35 | */
36 | name: string;
37 |
38 | /**
39 | * 标注点坐标
40 | */
41 | position: LatLng;
42 | }
43 |
44 | /**
45 | * 矩形坐标边界
46 | */
47 | export interface LatLngBounds {
48 | /**
49 | * 西南坐标
50 | */
51 | southwest: LatLng;
52 |
53 | /**
54 | * 东北坐标
55 | */
56 | northeast: LatLng;
57 | }
58 |
59 | /**
60 | * 地图状态
61 | */
62 | export interface CameraPosition {
63 | /**
64 | * 中心坐标
65 | */
66 | target?: LatLng;
67 |
68 | /**
69 | * 缩放级别
70 | */
71 | zoom?: number;
72 |
73 | /**
74 | * 朝向、旋转角度
75 | */
76 | bearing?: number;
77 |
78 | /**
79 | * 倾斜角度
80 | */
81 | tilt?: number;
82 | }
83 |
84 | /**
85 | * 定位
86 | */
87 | export interface Location extends LatLng {
88 | /**
89 | * 精度
90 | */
91 | accuracy: number;
92 |
93 | /**
94 | * 朝向
95 | */
96 | heading: number;
97 |
98 | /**
99 | * 海拔
100 | */
101 | altitude: number;
102 |
103 | /**
104 | * 运动速度
105 | */
106 | speed: number;
107 | }
108 |
109 | /**
110 | * 地图类型
111 | */
112 | export enum MapType {
113 | /**
114 | * 标准地图
115 | */
116 | Standard,
117 |
118 | /**
119 | * 卫星地图
120 | */
121 | Satellite,
122 |
123 | /**
124 | * 夜间地图
125 | */
126 | Night,
127 |
128 | /**
129 | * 导航地图
130 | */
131 | Navi,
132 |
133 | /**
134 | * 公交地图
135 | */
136 | Bus,
137 | }
138 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 7c00
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-amap3d",
3 | "version": "0.0.0",
4 | "description": "react-native 高德地图组件,支持 Android + iOS",
5 | "author": "7c00 ",
6 | "license": "MIT",
7 | "keywords": [
8 | "react-native",
9 | "amap",
10 | "maps",
11 | "mapview"
12 | ],
13 | "main": "lib/src",
14 | "files": [
15 | "lib/src",
16 | "lib/android/src",
17 | "lib/android/build.gradle",
18 | "lib/ios",
19 | "react-native.config.js",
20 | "react-native-amap3d.podspec"
21 | ],
22 | "homepage": "https://github.com/qiuxiang/react-native-amap3d",
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/qiuxiang/react-native-amap3d"
26 | },
27 | "scripts": {
28 | "start": "react-native start",
29 | "android": "react-native run-android",
30 | "release-android": "react-native run-android --variant=release",
31 | "reload": "adb reverse tcp:8081 tcp:8081 && adb shell input text rr",
32 | "ios": "react-native run-ios"
33 | },
34 | "dependencies": {
35 | "supercluster": "^7.1.4"
36 | },
37 | "devDependencies": {
38 | "@react-native-picker/picker": "^2.4.8",
39 | "@react-navigation/native": "^6.1.3",
40 | "@react-navigation/native-stack": "^6.9.9",
41 | "@types/react-native": "^0.71.2",
42 | "@types/supercluster": "^7.1.0",
43 | "react": "18.2.0",
44 | "react-native": "^0.71.2",
45 | "react-native-safe-area-context": "^4.5.0",
46 | "react-native-screens": "^3.19.0"
47 | },
48 | "prettier": {
49 | "printWidth": 100
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/react-native-amap3d.podspec:
--------------------------------------------------------------------------------
1 | require "json"
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = "react-native-amap3d"
7 | s.version = package["version"]
8 | s.summary = package["description"]
9 | s.homepage = package["homepage"]
10 | s.license = package["license"]
11 | s.authors = package["author"]
12 |
13 | s.platforms = { :ios => "10.0" }
14 | s.source = { :git => "https://github.com/qiuxiang/react-native-amap3d.git", :tag => "#{s.version}" }
15 |
16 | s.source_files = "lib/ios/**/*.{h,m,mm,swift}"
17 |
18 | s.dependency "React-Core"
19 | s.dependency 'AMap3DMap', "~> 9.6.0"
20 | end
21 |
--------------------------------------------------------------------------------
/react-native.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | dependency: {
3 | platforms: {
4 | ios: { project: "lib/ios/react-native-amap3d.podspec" },
5 | android: { sourceDir: "lib/android" },
6 | },
7 | },
8 | dependencies: {
9 | "react-native-amap3d": {
10 | root: __dirname,
11 | platforms: {
12 | android: {
13 | sourceDir: __dirname + "/lib/android",
14 | packageImportPath: "import qiuxiang.amap3d.AMap3DPackage;",
15 | packageInstance: "new AMap3DPackage()",
16 | },
17 | },
18 | },
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # react-native-amap3d [![][version-badge]][npm] [](https://github.com/qiuxiang/react-native-amap3d/actions/workflows/build.yml)
2 |
3 | **注意:该项目目前只维护,不加新功能。**
4 |
5 | react-native 高德地图组件,使用最新 3D SDK,支持 Android + iOS,受 [react-native-maps](https://github.com/airbnb/react-native-maps) 启发,提供功能丰富且易用的接口。
6 |
7 | 相关项目推荐:
8 |
9 | - [react-native-baidumap-sdk(百度地图 SDK)](https://github.com/qiuxiang/react-native-baidumap-sdk)
10 | - [react-native-amap-geolocation(高德地图定位模块)](https://github.com/qiuxiang/react-native-amap-geolocation)
11 |
12 | ## 功能
13 |
14 | - 地图模式切换(常规、卫星、导航、夜间)
15 | - 3D 建筑、路况、室内地图
16 | - 内置地图控件的显示隐藏(指南针、比例尺、定位按钮、缩放按钮)
17 | - 手势交互控制(平移、缩放、旋转、倾斜)
18 | - 中心坐标、缩放级别、倾斜度的设置,支持动画过渡
19 | - 地图事件(onPress、onLongPress、onLocation、onCameraMove、onCameraIdle 等)
20 | - 地图标记(Marker)
21 | - 折线绘制(Polyline)
22 | - 多边形绘制(Polygon)
23 | - 圆形绘制(Circle)
24 | - 热力图(HeatMap)
25 | - 海量点(MultiPoint)
26 | - 点聚合(Cluster)
27 |
28 | ## 接口文档
29 |
30 | https://qiuxiang.github.io/react-native-amap3d/api/
31 |
32 | ## 安装
33 |
34 | ```bash
35 | npm i react-native-amap3d
36 | ```
37 |
38 | ### 添加高德 API Key
39 |
40 | 首先你需要获取高德地图 API Key:
41 |
42 | - [Aandroid](http://lbs.amap.com/api/android-sdk/guide/create-project/get-key)
43 | - [iOS](https://lbs.amap.com/api/ios-sdk/guide/create-project/get-key)
44 |
45 | 然后你需要在显示地图前调用接口设置 API key:
46 |
47 | ```js
48 | import { AMapSdk } from "react-native-amap3d";
49 | import { Platform } from "react-native";
50 |
51 | AMapSdk.init(
52 | Platform.select({
53 | android: "c52c7169e6df23490e3114330098aaac",
54 | ios: "186d3464209b74effa4d8391f441f14d",
55 | })
56 | );
57 | ```
58 |
59 | ## 用法
60 |
61 | ### 显示地图
62 |
63 | ```jsx
64 | import { MapView, MapType } from "react-native-amap3d";
65 |
66 | ;
76 | ```
77 |
78 |
79 |
80 | ### 监听地图事件
81 |
82 | ```jsx
83 | import { MapView } from "react-native-amap3d";
84 |
85 | console.log("onLoad")}
87 | onPress={({ nativeEvent }) => console.log(nativeEvent)}
88 | onCameraIdle={({ nativeEvent }) => console.log(nativeEvent)}
89 | />;
90 | ```
91 |
92 |
93 |
94 | ### 添加标记
95 |
96 | 其中 `icon` 支持 [ImageSource](https://reactnative.dev/docs/image#imagesource)。
97 |
98 | 同时支持 `children` 作为标记图标。
99 |
100 | ```jsx
101 | import { MapView, Marker } from "react-native-amap3d";
102 |
103 |
104 | alert("onPress")}
108 | />
109 |
117 |
118 |
127 | {new Date().toLocaleString()}
128 |
129 |
130 | ;
131 | ```
132 |
133 |
134 |
135 | ### 点聚合
136 |
137 | Marker 数量过多(尤其是使用自定义 View 的情况下)会导致性能问题,而且显示过于密集,这时候可以用点聚合改善。
138 |
139 | ```jsx
140 | import { Cluster, MapView, Marker } from "react-native-amap3d";
141 |
142 | const markers = Array(1000)
143 | .fill(0)
144 | .map((_, i) => ({
145 | position: { latitude: 39.5 + Math.random(), longitude: 116 + Math.random() },
146 | properties: { key: `Marker${i}` },
147 | }));
148 |
149 | (this.mapView = ref)}
151 | onLoad={() => this.mapView?.moveCamera({ zoom: 8 }, 100)}
152 | onCameraIdle={({ nativeEvent }) => {
153 | this.status = nativeEvent;
154 | this.cluster?.update(nativeEvent);
155 | }}
156 | >
157 | (this.cluster = ref)}
159 | points={markers}
160 | renderMarker={(item) => (
161 |
166 | )}
167 | />
168 | ;
169 | ```
170 |
171 |
172 |
173 |
174 |
175 | ### 更多示例
176 |
177 | 参考 [example](https://github.com/qiuxiang/react-native-amap3d/tree/master/example-app)。
178 |
179 | ## 常见问题
180 |
181 | - 尽量使用真实设备进行测试,在模拟器可能存在一些问题(常见的是 Android 模拟器因为缺少 GPU 加速而导致闪退)。
182 | - onLocation 没有返回定位数据通常是因为 key 不正确,或没有申请 PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION 权限
183 |
184 | [npm]: https://www.npmjs.com/package/react-native-amap3d
185 | [version-badge]: https://img.shields.io/npm/v/react-native-amap3d.svg
186 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "jsx": "react-native",
5 | "esModuleInterop": true,
6 | "baseUrl": ".",
7 | "paths": {
8 | "react-native-amap3d": ["lib/src"]
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------