react-native-map4d-map-dtqg 0.1.1 → 0.1.2
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/README.md +64 -19
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
- package/android/src/main/java/com/reactnativemap4dmap/RMFMapViewManager.java +5 -0
- package/ios/RMFMapViewManager.m +15 -0
- package/lib/commonjs/components/MFBanDoSo.js +109 -0
- package/lib/commonjs/components/MFBanDoSo.js.map +1 -0
- package/lib/commonjs/components/MFMapView.js +20 -1
- package/lib/commonjs/components/MFMapView.js.map +1 -1
- package/lib/commonjs/components/extends/AreaFocusManager.js +205 -0
- package/lib/commonjs/components/extends/AreaFocusManager.js.map +1 -0
- package/lib/commonjs/components/extends/AreaFocuser.js +19 -257
- package/lib/commonjs/components/extends/AreaFocuser.js.map +1 -1
- package/lib/commonjs/components/extends/BoundHelper.js +36 -0
- package/lib/commonjs/components/extends/BoundHelper.js.map +1 -0
- package/lib/commonjs/components/extends/area/AreaFocusAreas.js +167 -0
- package/lib/commonjs/components/extends/area/AreaFocusAreas.js.map +1 -0
- package/lib/commonjs/components/extends/area/AreaFocusGeometryUtils.js +164 -0
- package/lib/commonjs/components/extends/area/AreaFocusGeometryUtils.js.map +1 -0
- package/lib/commonjs/components/extends/area/AreaFocusSession.js +100 -0
- package/lib/commonjs/components/extends/area/AreaFocusSession.js.map +1 -0
- package/lib/commonjs/components/extends/area/AreaFocusTypes.js +40 -0
- package/lib/commonjs/components/extends/area/AreaFocusTypes.js.map +1 -0
- package/lib/commonjs/components/internal/DefaultRoadmapStyle.js +2288 -0
- package/lib/commonjs/components/internal/DefaultRoadmapStyle.js.map +1 -0
- package/lib/commonjs/components/internal/GeojsonStyleUtils.js +139 -0
- package/lib/commonjs/components/internal/GeojsonStyleUtils.js.map +1 -0
- package/lib/commonjs/index.js +8 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/MFBanDoSo.js +92 -0
- package/lib/module/components/MFBanDoSo.js.map +1 -0
- package/lib/module/components/MFMapView.js +19 -1
- package/lib/module/components/MFMapView.js.map +1 -1
- package/lib/module/components/extends/AreaFocusManager.js +193 -0
- package/lib/module/components/extends/AreaFocusManager.js.map +1 -0
- package/lib/module/components/extends/AreaFocuser.js +19 -257
- package/lib/module/components/extends/AreaFocuser.js.map +1 -1
- package/lib/module/components/extends/BoundHelper.js +29 -0
- package/lib/module/components/extends/BoundHelper.js.map +1 -0
- package/lib/module/components/extends/area/AreaFocusAreas.js +156 -0
- package/lib/module/components/extends/area/AreaFocusAreas.js.map +1 -0
- package/lib/module/components/extends/area/AreaFocusGeometryUtils.js +153 -0
- package/lib/module/components/extends/area/AreaFocusGeometryUtils.js.map +1 -0
- package/lib/module/components/extends/area/AreaFocusSession.js +93 -0
- package/lib/module/components/extends/area/AreaFocusSession.js.map +1 -0
- package/lib/module/components/extends/area/AreaFocusTypes.js +33 -0
- package/lib/module/components/extends/area/AreaFocusTypes.js.map +1 -0
- package/lib/module/components/internal/DefaultRoadmapStyle.js +2281 -0
- package/lib/module/components/internal/DefaultRoadmapStyle.js.map +1 -0
- package/lib/module/components/internal/GeojsonStyleUtils.js +130 -0
- package/lib/module/components/internal/GeojsonStyleUtils.js.map +1 -0
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/MFBanDoSo.js +124 -0
- package/src/components/MFMapView.js +19 -2
- package/src/components/extends/AreaFocusManager.js +196 -0
- package/src/components/extends/AreaFocuser.js +17 -294
- package/src/components/extends/BoundHelper.js +32 -0
- package/src/components/extends/area/AreaFocusAreas.js +164 -0
- package/src/components/extends/area/AreaFocusGeometryUtils.js +164 -0
- package/src/components/extends/area/AreaFocusSession.js +100 -0
- package/src/components/extends/area/AreaFocusTypes.js +36 -0
- package/src/components/internal/DefaultRoadmapStyle.js +3365 -0
- package/src/components/internal/GeojsonStyleUtils.js +143 -0
- package/src/index.js +2 -0
- package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/9.0-milestone-1/checksums/checksums.lock +0 -0
- package/android/.gradle/9.0-milestone-1/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/9.0-milestone-1/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/9.0-milestone-1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.0-milestone-1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.0-milestone-1/gc.properties +0 -0
- package/android/.gradle/config.properties +0 -2
- package/android/.idea/AndroidProjectSystem.xml +0 -6
- package/android/.idea/caches/deviceStreaming.xml +0 -1570
- package/android/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/android/.idea/gradle.xml +0 -12
- package/android/.idea/migrations.xml +0 -10
- package/android/.idea/misc.xml +0 -10
- package/android/.idea/runConfigurations.xml +0 -17
- package/android/.idea/vcs.xml +0 -6
- package/android/local.properties +0 -8
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import { MFMapView } from './MFMapView';
|
|
3
|
+
import {
|
|
4
|
+
buildGeojsonStyle,
|
|
5
|
+
createCategoryItemsSignature,
|
|
6
|
+
} from './internal/GeojsonStyleUtils';
|
|
7
|
+
|
|
8
|
+
const FilterStylePropType = PropTypes.shape({
|
|
9
|
+
kind: PropTypes.oneOfType([
|
|
10
|
+
PropTypes.string,
|
|
11
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
12
|
+
]),
|
|
13
|
+
kind_detail: PropTypes.oneOfType([
|
|
14
|
+
PropTypes.string,
|
|
15
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
16
|
+
]),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const DrawLinePropType = PropTypes.shape({
|
|
20
|
+
color: PropTypes.string,
|
|
21
|
+
width: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const DrawFillPropType = PropTypes.shape({
|
|
25
|
+
color: PropTypes.string,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const DrawSymbolPropType = PropTypes.shape({
|
|
29
|
+
icon_image: PropTypes.string,
|
|
30
|
+
icon_index: PropTypes.number,
|
|
31
|
+
icon_color: PropTypes.string,
|
|
32
|
+
use_direct_icon_url: PropTypes.bool,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const CategoryStylePropType = PropTypes.shape({
|
|
36
|
+
line: PropTypes.arrayOf(
|
|
37
|
+
PropTypes.shape({
|
|
38
|
+
layer: PropTypes.string,
|
|
39
|
+
filter: FilterStylePropType,
|
|
40
|
+
draw: DrawLinePropType,
|
|
41
|
+
})
|
|
42
|
+
),
|
|
43
|
+
fill: PropTypes.arrayOf(
|
|
44
|
+
PropTypes.shape({
|
|
45
|
+
layer: PropTypes.string,
|
|
46
|
+
filter: FilterStylePropType,
|
|
47
|
+
draw: DrawFillPropType,
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
symbol: PropTypes.arrayOf(
|
|
51
|
+
PropTypes.shape({
|
|
52
|
+
layer: PropTypes.string,
|
|
53
|
+
filter: FilterStylePropType,
|
|
54
|
+
draw: DrawSymbolPropType,
|
|
55
|
+
})
|
|
56
|
+
),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const CategoryItemPropType = PropTypes.shape({
|
|
60
|
+
key: PropTypes.string,
|
|
61
|
+
title: PropTypes.string,
|
|
62
|
+
group: PropTypes.string,
|
|
63
|
+
order: PropTypes.number,
|
|
64
|
+
checked: PropTypes.bool,
|
|
65
|
+
style: CategoryStylePropType,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
class MFBanDoSo extends MFMapView {
|
|
69
|
+
constructor(props) {
|
|
70
|
+
super(props);
|
|
71
|
+
this._appliedGeojsonStyle = null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
componentDidMount() {
|
|
75
|
+
this._syncGeojsonStyle();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
componentDidUpdate(prevProps, prevState) {
|
|
79
|
+
const mapReadyChanged = prevState.isReady !== this.state.isReady;
|
|
80
|
+
const mapStyleChanged = prevProps.mapStyle !== this.props.mapStyle;
|
|
81
|
+
const sourceUrlChanged = prevProps.sourceUrl !== this.props.sourceUrl;
|
|
82
|
+
const itemsChanged =
|
|
83
|
+
createCategoryItemsSignature(prevProps.items) !==
|
|
84
|
+
createCategoryItemsSignature(this.props.items);
|
|
85
|
+
|
|
86
|
+
if (
|
|
87
|
+
mapReadyChanged ||
|
|
88
|
+
mapStyleChanged ||
|
|
89
|
+
sourceUrlChanged ||
|
|
90
|
+
itemsChanged
|
|
91
|
+
) {
|
|
92
|
+
this._syncGeojsonStyle();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_syncGeojsonStyle() {
|
|
97
|
+
if (!this.state.isReady) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const items = this.props.items || [];
|
|
102
|
+
|
|
103
|
+
const geojsonStyle = buildGeojsonStyle(
|
|
104
|
+
this.props.mapStyle,
|
|
105
|
+
this.props.sourceUrl,
|
|
106
|
+
items
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (!geojsonStyle || geojsonStyle === this._appliedGeojsonStyle) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this._appliedGeojsonStyle = geojsonStyle;
|
|
114
|
+
this._runCommand('setMapStyle', [geojsonStyle]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
MFBanDoSo.propTypes = {
|
|
119
|
+
...MFMapView.propTypes,
|
|
120
|
+
items: PropTypes.arrayOf(CategoryItemPropType),
|
|
121
|
+
sourceUrl: PropTypes.string.isRequired,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export { MFBanDoSo };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import {ViewPropTypes, ColorPropType} from 'deprecated-react-native-prop-types';
|
|
4
|
+
import {AreaFocusManager} from './extends/AreaFocusManager';
|
|
4
5
|
import {AreaFocuser} from './extends/AreaFocuser';
|
|
5
6
|
import {MFPolygon} from './MFPolygon';
|
|
6
7
|
import {
|
|
@@ -144,13 +145,15 @@ const propTypes = {
|
|
|
144
145
|
* Callback that is called when user taps on location Button
|
|
145
146
|
*/
|
|
146
147
|
onMyLocationButtonPress: PropTypes.func,
|
|
148
|
+
|
|
147
149
|
};
|
|
148
150
|
|
|
149
151
|
|
|
150
152
|
class MFMapView extends React.Component {
|
|
151
153
|
constructor(props) {
|
|
152
154
|
super(props);
|
|
153
|
-
this.
|
|
155
|
+
this.areaFocusManager = new AreaFocusManager(this);
|
|
156
|
+
this.areaFocuser = new AreaFocuser(this.areaFocusManager);
|
|
154
157
|
this.state = {
|
|
155
158
|
isReady: Platform.OS === 'ios',
|
|
156
159
|
managedPolygons: {},
|
|
@@ -361,6 +364,21 @@ class MFMapView extends React.Component {
|
|
|
361
364
|
return Promise.reject('coordinateForPoint not supported on this platform');
|
|
362
365
|
}
|
|
363
366
|
|
|
367
|
+
focusArea(focusOptions) {
|
|
368
|
+
if (!this.areaFocusManager) {
|
|
369
|
+
return Promise.resolve(null)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return this.areaFocusManager.focus(focusOptions)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
clearFocusedArea() {
|
|
376
|
+
if (!this.areaFocusManager) {
|
|
377
|
+
return
|
|
378
|
+
}
|
|
379
|
+
this.areaFocusManager.clear()
|
|
380
|
+
}
|
|
381
|
+
|
|
364
382
|
_getHandle() {
|
|
365
383
|
return findNodeHandle(this.map);
|
|
366
384
|
}
|
|
@@ -399,7 +417,6 @@ class MFMapView extends React.Component {
|
|
|
399
417
|
return NativeModules[`RMFMapView`][name];
|
|
400
418
|
}
|
|
401
419
|
|
|
402
|
-
|
|
403
420
|
render() {
|
|
404
421
|
let props;
|
|
405
422
|
const { children, ...restProps } = this.props;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import {AreaFocusSession} from './area/AreaFocusSession'
|
|
2
|
+
import {ProvinceArea, IndustrialEconomicArea} from './area/AreaFocusAreas'
|
|
3
|
+
import {IndustrialEconomicType} from './area/AreaFocusTypes'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {'normal' | 'highlight'} FocusDisplay
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {{left?: number, right?: number, top?: number, bottom?: number}} FocusPadding
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {'province' | 'industrialZone' | 'economicZone' | 'ecoIndustrialZone' | 'freeTradeZone' | 'nonTariffZone' | 'otherZoneModel' | number} FocusType
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} FocusOptions
|
|
19
|
+
* @property {FocusType} type
|
|
20
|
+
* @property {number=} id
|
|
21
|
+
* @property {string=} name
|
|
22
|
+
* @property {FocusDisplay=} display
|
|
23
|
+
* @property {FocusPadding=} padding
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const VIETNAM_MAINLAND_BOUNDS = {
|
|
27
|
+
minLat: 8.18,
|
|
28
|
+
minLng: 102.14,
|
|
29
|
+
maxLat: 23.4,
|
|
30
|
+
maxLng: 109.47,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const FOCUS_TYPE_TO_INDUSTRIAL_ECONOMIC_TYPE = {
|
|
34
|
+
industrialZone: IndustrialEconomicType.INDUSTRIAL_ZONE,
|
|
35
|
+
economicZone: IndustrialEconomicType.ECONOMIC_ZONE,
|
|
36
|
+
ecoIndustrialZone: IndustrialEconomicType.ECO_INDUSTRIAL_ZONE,
|
|
37
|
+
freeTradeZone: IndustrialEconomicType.FREE_TRADE_ZONE,
|
|
38
|
+
nonTariffZone: IndustrialEconomicType.NON_TARIFF_ZONE,
|
|
39
|
+
otherZoneModel: IndustrialEconomicType.OTHER_ZONE_MODEL,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class AreaFocusManager {
|
|
43
|
+
constructor(mapView) {
|
|
44
|
+
this.mapView = mapView
|
|
45
|
+
this.currentSession = null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async _focusArea(area, options) {
|
|
49
|
+
this.clear()
|
|
50
|
+
|
|
51
|
+
if (!area) {
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
if (!(await area.load())) {
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const focusOptions = {...(options || {})}
|
|
61
|
+
const bounds = area.getBounds() || VIETNAM_MAINLAND_BOUNDS
|
|
62
|
+
|
|
63
|
+
this._fitBounds(bounds, focusOptions)
|
|
64
|
+
|
|
65
|
+
this.currentSession = new AreaFocusSession(this.mapView, area, focusOptions)
|
|
66
|
+
this.currentSession.render()
|
|
67
|
+
|
|
68
|
+
return this.currentSession
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error('Cannot focus area:', error)
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async _focusProvince(options) {
|
|
77
|
+
const provinceId = this._getProvinceId(options)
|
|
78
|
+
const provinceName = this._getProvinceName(options)
|
|
79
|
+
|
|
80
|
+
if (provinceId == null && !provinceName) {
|
|
81
|
+
this.clear()
|
|
82
|
+
return null
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const area = provinceId != null ? new ProvinceArea(provinceId) : ProvinceArea.fromName(provinceName)
|
|
86
|
+
const display = options && options.display === 'highlight' ? 'highlight' : 'normal'
|
|
87
|
+
|
|
88
|
+
return this._focusArea(area, {
|
|
89
|
+
display,
|
|
90
|
+
padding: options ? options.padding : undefined,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {FocusOptions | null | undefined} focusOptions
|
|
96
|
+
* @returns {Promise<AreaFocusSession | null>}
|
|
97
|
+
*/
|
|
98
|
+
async focus(focusOptions) {
|
|
99
|
+
if (focusOptions == null) {
|
|
100
|
+
this.clear()
|
|
101
|
+
return null
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (focusOptions.type === 'province') {
|
|
105
|
+
return this._focusProvince(focusOptions)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (focusOptions.id == null) {
|
|
109
|
+
console.warn('Focus options must include an id for non-province types:', focusOptions)
|
|
110
|
+
this.clear()
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const industrialEconomicType = this._getIndustrialEconomicType(focusOptions.type)
|
|
115
|
+
|
|
116
|
+
if (industrialEconomicType != null) {
|
|
117
|
+
return this._focusArea(new IndustrialEconomicArea(industrialEconomicType, focusOptions.id), {
|
|
118
|
+
display: focusOptions.display,
|
|
119
|
+
padding: focusOptions.padding,
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.warn('Unsupported focus type:', focusOptions.type)
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_getIndustrialEconomicType(type) {
|
|
128
|
+
if (typeof type === 'number') {
|
|
129
|
+
const values = Object.values(IndustrialEconomicType)
|
|
130
|
+
return values.includes(type) ? type : null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (typeof type !== 'string') {
|
|
134
|
+
return null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return FOCUS_TYPE_TO_INDUSTRIAL_ECONOMIC_TYPE[type] || null
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
clear() {
|
|
141
|
+
if (this.currentSession) {
|
|
142
|
+
this.currentSession.destroy()
|
|
143
|
+
this.currentSession = null
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
_fitBounds(bounds, options) {
|
|
148
|
+
if (!this.mapView || typeof this.mapView.fitBounds !== 'function' || !bounds) {
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.mapView.fitBounds({
|
|
153
|
+
bounds: {
|
|
154
|
+
southWest: {
|
|
155
|
+
latitude: bounds.minLat,
|
|
156
|
+
longitude: bounds.minLng,
|
|
157
|
+
},
|
|
158
|
+
northEast: {
|
|
159
|
+
latitude: bounds.maxLat,
|
|
160
|
+
longitude: bounds.maxLng,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
padding: options ? options.padding : undefined,
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
_getProvinceName(options) {
|
|
168
|
+
if (options == null || typeof options !== 'object') {
|
|
169
|
+
return null
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (typeof options.name === 'string') {
|
|
173
|
+
const name = options.name.trim()
|
|
174
|
+
return name.length > 0 ? name : null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const optionKeys = Object.keys(options)
|
|
178
|
+
const unsupportedKeys = optionKeys.filter((key) => key !== 'type' && key !== 'id' && key !== 'name' && key !== 'display' && key !== 'padding')
|
|
179
|
+
|
|
180
|
+
if (unsupportedKeys.length > 0) {
|
|
181
|
+
console.warn(
|
|
182
|
+
`[AreaFocusManager] focusProvince expects options like { type: 'province', name: 'Ha Noi', display: 'highlight' }. Unsupported keys: ${unsupportedKeys.join(', ')}`
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return null
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_getProvinceId(options) {
|
|
190
|
+
if (options == null || typeof options !== 'object') {
|
|
191
|
+
return null
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return typeof options.id === 'number' ? options.id : null
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -1,105 +1,37 @@
|
|
|
1
1
|
export class AreaFocuser {
|
|
2
2
|
|
|
3
|
-
constructor(
|
|
4
|
-
this.
|
|
5
|
-
this.highlightPaths = []
|
|
6
|
-
this.highlightPolygonId = 'area-focuser-highlight-polygon'
|
|
3
|
+
constructor(areaFocusManager) {
|
|
4
|
+
this._areaFocusManager = areaFocusManager
|
|
7
5
|
}
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* @param {{name?: string, highlight?: boolean}=} options
|
|
11
9
|
*/
|
|
12
10
|
async focusProvince(options) {
|
|
13
|
-
const provinceName = this.
|
|
14
|
-
const shouldHighlight = this.
|
|
11
|
+
const provinceName = this._getProvinceName(options)
|
|
12
|
+
const shouldHighlight = this._shouldHighlight(options)
|
|
15
13
|
|
|
16
14
|
if (!provinceName) {
|
|
17
|
-
this.
|
|
18
|
-
this.clearHighlightPolygon()
|
|
15
|
+
this._clear()
|
|
19
16
|
return
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!response.ok) {
|
|
29
|
-
return
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const data = await response.json()
|
|
33
|
-
|
|
34
|
-
if (data.code !== 'ok') {
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const feature =
|
|
39
|
-
data.result && data.result.features && data.result.features.length > 0 ? data.result.features[0] : null
|
|
40
|
-
|
|
41
|
-
if (!feature) {
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const geometry = feature.geometry
|
|
46
|
-
if (!geometry) {
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let bounds = null
|
|
51
|
-
|
|
52
|
-
const viewbox =
|
|
53
|
-
feature.properties && feature.properties.viewbox ? feature.properties.viewbox : null
|
|
54
|
-
|
|
55
|
-
if (viewbox != null && viewbox.trim() != '') {
|
|
56
|
-
bounds = this.parseViewbox(viewbox)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!bounds) {
|
|
60
|
-
bounds = this.getViewboxFromGeometry(geometry)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!bounds) {
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.mapView.fitBounds({
|
|
68
|
-
bounds: {
|
|
69
|
-
southWest: {
|
|
70
|
-
latitude: bounds[0],
|
|
71
|
-
longitude: bounds[1],
|
|
72
|
-
},
|
|
73
|
-
northEast: {
|
|
74
|
-
latitude: bounds[2],
|
|
75
|
-
longitude: bounds[3],
|
|
76
|
-
},
|
|
77
|
-
}
|
|
19
|
+
if (this._areaFocusManager) {
|
|
20
|
+
await this._areaFocusManager.focus({
|
|
21
|
+
type: 'province',
|
|
22
|
+
name: provinceName,
|
|
23
|
+
display: shouldHighlight ? 'highlight' : 'normal',
|
|
78
24
|
})
|
|
79
|
-
|
|
80
|
-
this.createHighlightPaths(geometry)
|
|
81
|
-
|
|
82
|
-
if (shouldHighlight) {
|
|
83
|
-
const polygon = this.getHighlightPolygonProps()
|
|
84
|
-
|
|
85
|
-
if (polygon) {
|
|
86
|
-
this.mapView._addPolygon({
|
|
87
|
-
...polygon,
|
|
88
|
-
id: this.highlightPolygonId,
|
|
89
|
-
zIndex: 999,
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
this.clearHighlightPolygon()
|
|
95
|
-
}
|
|
96
25
|
}
|
|
97
|
-
|
|
98
|
-
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_clear() {
|
|
29
|
+
if (this._areaFocusManager) {
|
|
30
|
+
this._areaFocusManager.clear()
|
|
99
31
|
}
|
|
100
32
|
}
|
|
101
33
|
|
|
102
|
-
|
|
34
|
+
_getProvinceName(options) {
|
|
103
35
|
if (options == null || typeof options !== 'object') {
|
|
104
36
|
return null
|
|
105
37
|
}
|
|
@@ -120,220 +52,11 @@ export class AreaFocuser {
|
|
|
120
52
|
return null
|
|
121
53
|
}
|
|
122
54
|
|
|
123
|
-
|
|
55
|
+
_shouldHighlight(options) {
|
|
124
56
|
if (options == null || typeof options !== 'object') {
|
|
125
57
|
return false
|
|
126
58
|
}
|
|
127
59
|
|
|
128
60
|
return options.highlight === true
|
|
129
61
|
}
|
|
130
|
-
|
|
131
|
-
parseViewbox(viewbox) {
|
|
132
|
-
const bounds = viewbox.split(',').map(Number)
|
|
133
|
-
|
|
134
|
-
if (bounds.length != 4) {
|
|
135
|
-
return null
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const [minLat, minLng, maxLat, maxLng] = bounds
|
|
139
|
-
|
|
140
|
-
if (
|
|
141
|
-
Number.isNaN(minLat) ||
|
|
142
|
-
Number.isNaN(minLng) ||
|
|
143
|
-
Number.isNaN(maxLat) ||
|
|
144
|
-
Number.isNaN(maxLng)
|
|
145
|
-
) {
|
|
146
|
-
return null
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return [
|
|
150
|
-
minLat,
|
|
151
|
-
minLng,
|
|
152
|
-
maxLat,
|
|
153
|
-
maxLng,
|
|
154
|
-
]
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
getViewboxFromGeometry(geometry) {
|
|
158
|
-
const bounds = {
|
|
159
|
-
minLat: Infinity,
|
|
160
|
-
minLng: Infinity,
|
|
161
|
-
maxLat: -Infinity,
|
|
162
|
-
maxLng: -Infinity,
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const updateBounds = function (coordinate) {
|
|
166
|
-
if (coordinate.length < 2) {
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const lng = coordinate[0]
|
|
171
|
-
const lat = coordinate[1]
|
|
172
|
-
|
|
173
|
-
if (Number.isNaN(lat) || Number.isNaN(lng)) {
|
|
174
|
-
return
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
bounds.minLat = Math.min(bounds.minLat, lat)
|
|
178
|
-
bounds.minLng = Math.min(bounds.minLng, lng)
|
|
179
|
-
bounds.maxLat = Math.max(bounds.maxLat, lat)
|
|
180
|
-
bounds.maxLng = Math.max(bounds.maxLng, lng)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (geometry.type === 'Polygon') {
|
|
184
|
-
const polygons = geometry.coordinates
|
|
185
|
-
|
|
186
|
-
polygons.forEach(function (ring) {
|
|
187
|
-
ring.forEach(function (coordinate) {
|
|
188
|
-
updateBounds(coordinate)
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (geometry.type === 'MultiPolygon') {
|
|
194
|
-
const multiPolygons = geometry.coordinates
|
|
195
|
-
|
|
196
|
-
multiPolygons.forEach(function (polygon) {
|
|
197
|
-
polygon.forEach(function (ring) {
|
|
198
|
-
ring.forEach(function (coordinate) {
|
|
199
|
-
updateBounds(coordinate)
|
|
200
|
-
})
|
|
201
|
-
})
|
|
202
|
-
})
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (
|
|
206
|
-
bounds.minLat === Infinity ||
|
|
207
|
-
bounds.minLng === Infinity ||
|
|
208
|
-
bounds.maxLat === -Infinity ||
|
|
209
|
-
bounds.maxLng === -Infinity
|
|
210
|
-
) {
|
|
211
|
-
return null
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return [
|
|
215
|
-
bounds.minLat,
|
|
216
|
-
bounds.minLng,
|
|
217
|
-
bounds.maxLat,
|
|
218
|
-
bounds.maxLng,
|
|
219
|
-
]
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
createHighlightPaths(geometry) {
|
|
223
|
-
this.clearHighlightPaths()
|
|
224
|
-
|
|
225
|
-
const paths = this.createWorldMaskPaths(geometry)
|
|
226
|
-
|
|
227
|
-
if (paths.length <= 1) {
|
|
228
|
-
return
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
this.highlightPaths = paths
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
clearHighlightPaths() {
|
|
235
|
-
this.highlightPaths = []
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
clearHighlightPolygon() {
|
|
239
|
-
if (!this.mapView) {
|
|
240
|
-
return
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
this.mapView._removePolygon(this.highlightPolygonId)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
getHighlightPolygonProps() {
|
|
247
|
-
if (!this.highlightPaths || this.highlightPaths.length <= 1) {
|
|
248
|
-
return null
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const [coordinates, ...holes] = this.highlightPaths
|
|
252
|
-
|
|
253
|
-
return {
|
|
254
|
-
coordinates,
|
|
255
|
-
holes,
|
|
256
|
-
fillColor: "#0000001E",
|
|
257
|
-
strokeColor: "#FF0000FF",
|
|
258
|
-
strokeWidth: 2.0,
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
createWorldMaskPaths(geometry) {
|
|
263
|
-
const worldPath = [
|
|
264
|
-
{ longitude: -180, latitude: -90 },
|
|
265
|
-
{ longitude: 180, latitude: -90 },
|
|
266
|
-
{ longitude: 180, latitude: 90 },
|
|
267
|
-
{ longitude: -180, latitude: 90 },
|
|
268
|
-
{ longitude: -180, latitude: -90 },
|
|
269
|
-
]
|
|
270
|
-
|
|
271
|
-
const paths = [
|
|
272
|
-
worldPath,
|
|
273
|
-
]
|
|
274
|
-
|
|
275
|
-
const holes = this.getHolePathsFromGeometry(geometry)
|
|
276
|
-
|
|
277
|
-
holes.forEach((hole) => {
|
|
278
|
-
paths.push(hole)
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
return paths
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
getHolePathsFromGeometry(geometry) {
|
|
285
|
-
const paths = []
|
|
286
|
-
|
|
287
|
-
if (geometry.type == 'Polygon') {
|
|
288
|
-
const polygon = geometry.coordinates
|
|
289
|
-
|
|
290
|
-
if (polygon.length > 0) {
|
|
291
|
-
paths.push(this.convertAndClosePath(polygon[0]))
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (geometry.type == 'MultiPolygon') {
|
|
296
|
-
const multiPolygon = geometry.coordinates
|
|
297
|
-
|
|
298
|
-
multiPolygon.forEach((polygon) => {
|
|
299
|
-
if (polygon.length > 0) {
|
|
300
|
-
paths.push(this.convertAndClosePath(polygon[0]))
|
|
301
|
-
}
|
|
302
|
-
})
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return paths
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
convertAndClosePath(path) {
|
|
309
|
-
if (path.length == 0) {
|
|
310
|
-
return []
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const coordinatePath = path
|
|
314
|
-
.filter((point) => point.length >= 2)
|
|
315
|
-
.map((point) => ({
|
|
316
|
-
latitude: point[1],
|
|
317
|
-
longitude: point[0],
|
|
318
|
-
}))
|
|
319
|
-
|
|
320
|
-
if (coordinatePath.length == 0) {
|
|
321
|
-
return []
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const firstPoint = coordinatePath[0]
|
|
325
|
-
const lastPoint = coordinatePath[coordinatePath.length - 1]
|
|
326
|
-
|
|
327
|
-
if (
|
|
328
|
-
firstPoint.latitude == lastPoint.latitude &&
|
|
329
|
-
firstPoint.longitude == lastPoint.longitude
|
|
330
|
-
) {
|
|
331
|
-
return coordinatePath
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
return [
|
|
335
|
-
...coordinatePath,
|
|
336
|
-
firstPoint,
|
|
337
|
-
]
|
|
338
|
-
}
|
|
339
62
|
}
|