xy-map 1.0.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.
@@ -0,0 +1,119 @@
1
+ // import mapBoxGl from 'mapbox-gl'
2
+ import mapSdk from '../map'
3
+
4
+ // 更新数据
5
+ export const setSource = (id, data) => {
6
+ let {
7
+ map
8
+ } = mapSdk
9
+ let hasSource = map.getSource(id)
10
+ if (hasSource) {
11
+ map.getSource(id).setData(data)
12
+ }
13
+ }
14
+ // 判断图层是否存在
15
+ export const hasLayer = (id) => {
16
+ let {
17
+ map
18
+ } = mapSdk
19
+
20
+ return map.getLayer(id)
21
+ }
22
+
23
+ // 判断数据是否存在
24
+ export const hasSource = (id) => {
25
+ let {
26
+ map
27
+ } = mapSdk
28
+
29
+ return map.getSource(id)
30
+ }
31
+
32
+ // 删除图层
33
+ export const removeLayer = (id) => {
34
+ let {
35
+ map
36
+ } = mapSdk
37
+
38
+ let arr = getLayerAll()
39
+ let layers = arr.filter(item => item.id.includes(id + '-') || item.id === id)
40
+
41
+ layers.forEach(item => {
42
+ if (hasLayer(item.id)) {
43
+ map.removeLayer(item.id)
44
+ }
45
+ })
46
+ }
47
+
48
+ /**
49
+ * 获取所有图层
50
+ */
51
+ export const getLayerAll = () => {
52
+ let {
53
+ map
54
+ } = mapSdk
55
+ let data = map.getStyle().layers
56
+ return data
57
+ }
58
+
59
+ // 显示隐藏图层
60
+ export const showLayer = (id, show = false) => {
61
+ let {
62
+ map
63
+ } = mapSdk
64
+
65
+ let arr = getLayerAll()
66
+ let layers = arr.filter(item => item.id.includes(id + '-') || item.id === id)
67
+
68
+ show = show ? 'visible' : 'none'
69
+ layers.forEach(item => {
70
+ if (hasLayer(item.id)) {
71
+ map.setLayoutProperty(item.id, 'visibility', show)
72
+ }
73
+ })
74
+ }
75
+
76
+ // 显隐文字
77
+ export const showLayerText = (show, id = '') => {
78
+ let {
79
+ map
80
+ } = mapSdk
81
+
82
+ if (id) {
83
+ setPaint(id, 'text-opacity', show ? 1 : 0)
84
+ } else {
85
+ let textLayer = map.getStyle().layers
86
+ textLayer.forEach(layer => {
87
+ if (layer.type === 'symbol') {
88
+ setPaint(layer.id, 'text-opacity', show ? 1 : 0)
89
+ }
90
+ })
91
+ }
92
+ }
93
+
94
+ // 修改Layout
95
+ export const setLayout = (id, key, value) => {
96
+ let {
97
+ map
98
+ } = mapSdk
99
+
100
+ map.setLayoutProperty(id, key, value)
101
+ }
102
+
103
+ // 修改Paint
104
+ export const setPaint = (id, key, value) => {
105
+ let {
106
+ map
107
+ } = mapSdk
108
+
109
+ map.setPaintProperty(id, key, value)
110
+ }
111
+
112
+ // 修改Filter
113
+ export const setFilter = (key, filter) => {
114
+ let {
115
+ map
116
+ } = mapSdk
117
+
118
+ map.setFilter(key, filter)
119
+ }
package/map.js ADDED
@@ -0,0 +1,400 @@
1
+ var defaultOptions = {
2
+ container: 'map',
3
+ zoom: 12,
4
+ minZoom: 11,
5
+ center: [102.485544, 24.921785],
6
+ pitch: 0, // 3d倾斜视角
7
+ bearing: -50, // 旋转
8
+ terrain: true, // 开启地形
9
+ build: true, // 显示建筑
10
+ pitchWithRotate: true, // 禁止绕x轴旋转 false禁止
11
+ attributionControl: true, // 隐藏地图所属信息
12
+ projection: 'globe',
13
+ style: 'mapbox://styles/mapbox-map-design/ckhqrf2tz0dt119ny6azh975y'
14
+ // style: 'mapbox://styles/mapbox/streets-v9',
15
+ }
16
+
17
+ import mapBoxGl from 'mapbox-gl'
18
+ import 'mapbox-gl/dist/mapbox-gl.css'
19
+ import './style/map.css'
20
+
21
+ var popup = null
22
+
23
+ class mapSdk {
24
+ constructor() {
25
+ this.accessToken = 'pk.eyJ1IjoiaGo0NjI3NzEzOTYiLCJhIjoiY2t4NzAxZzdvMDZ5MTJ2azN0NzBqZGt0bCJ9.cRDXTquac05DVKJ5wc854w'
26
+ this.options = defaultOptions // 初始参数
27
+ this.map = null
28
+ }
29
+
30
+ /**
31
+ * 初始化地图
32
+ * @param {*} options
33
+ */
34
+ initMap = (options) => {
35
+ mapBoxGl.accessToken = options.accessToken || this.accessToken
36
+ this.options = Object.assign(defaultOptions, options)
37
+
38
+ const map = this.map = new mapBoxGl.Map(this.options)
39
+
40
+ return new Promise((resolve, reject) => {
41
+ map.on('load', () => {
42
+ this.addFog()
43
+ if (this.options.terrain) {
44
+ this.setTerrain()
45
+ }
46
+ if (this.options.build) {
47
+ this.addBuildings()
48
+ }
49
+ resolve(map)
50
+ })
51
+ })
52
+ }
53
+
54
+ /**
55
+ * 摄像机视角飞行
56
+ * @param {*}
57
+ */
58
+ flyTo = (config) => {
59
+ return new Promise((resolve) => {
60
+ let map = this.map
61
+ let options = Object.assign({
62
+ duration: 1000, // Animate over 12 seconds
63
+ essential: true,
64
+ speed: 1,
65
+ }, config)
66
+ map.flyTo(options, {
67
+ moveend: 'flyEnd'
68
+ })
69
+
70
+ // 飞行结束
71
+ map.on('moveend', (e) => {
72
+ if (e.moveend && e.moveend === 'flyEnd') {
73
+ resolve(true)
74
+ }
75
+ })
76
+ })
77
+ }
78
+
79
+ /**
80
+ * 地图平移到某个点
81
+ */
82
+ easeTo(position, duration = 1000) {
83
+ this.map.easeTo({
84
+ center: position,
85
+ duration
86
+ })
87
+ }
88
+
89
+ /**
90
+ * 添加地形
91
+ */
92
+ setTerrain() {
93
+ let map = this.map
94
+ map.addSource('mapbox-dem', {
95
+ 'type': 'raster-dem',
96
+ // 'url': 'mapbox://mapbox.mapbox-terrain-dem-v1',
97
+ 'url': 'mapbox://mapbox.terrain-rgb',
98
+ 'tileSize': 512,
99
+ 'maxzoom': 14
100
+ })
101
+ map.setTerrain({
102
+ 'source': 'mapbox-dem',
103
+ 'exaggeration': 1.5
104
+ })
105
+ }
106
+
107
+ /**
108
+ * 添加雾
109
+ */
110
+ addFog() {
111
+ let map = this.map
112
+ if (this.options.night) {
113
+ // 晚上
114
+ map.setFog({
115
+ 'range': [1, 15],
116
+ 'horizon-blend': 0.1,
117
+ 'color': '#242B4B',
118
+ 'high-color': '#161B36',
119
+ 'space-color': '#0B1026',
120
+ 'star-intensity': 0.1
121
+ })
122
+ } else {
123
+ // 天空
124
+ map.addLayer({
125
+ 'id': 'sky',
126
+ 'type': 'sky',
127
+ 'paint': {
128
+ 'sky-type': 'atmosphere',
129
+ 'sky-atmosphere-sun': [0.0, 0.0],
130
+ 'sky-atmosphere-sun-intensity': 15
131
+ }
132
+ })
133
+
134
+ // 白天
135
+ map.setFog({
136
+ 'range': [1, 15],
137
+ 'horizon-blend': 0.1,
138
+ 'color': 'white',
139
+ 'high-color': '#add8e6',
140
+ 'space-color': '#161B36',
141
+ 'star-intensity': 0.1
142
+ })
143
+ }
144
+ }
145
+
146
+ /**
147
+ * 添加建筑
148
+ */
149
+ addBuildings() {
150
+ let map = this.map
151
+ const layers = map.getStyle().layers
152
+ const labelLayerId = layers.find((layer) => layer.type === 'symbol' && layer.layout['text-field']).id
153
+ map.addLayer({
154
+ 'id': 'add-3d-buildings',
155
+ 'source': 'composite',
156
+ 'source-layer': 'building',
157
+ 'filter': ['==', 'extrude', 'true'],
158
+ 'type': 'fill-extrusion',
159
+ 'minzoom': 15,
160
+ 'paint': {
161
+ 'fill-extrusion-color': '#fff',
162
+
163
+ // Use an 'interpolate' expression to
164
+ // add a smooth transition effect to
165
+ // the buildings as the user zooms in.
166
+ 'fill-extrusion-height': [
167
+ 'interpolate',
168
+ ['linear'],
169
+ ['zoom'],
170
+ 15,
171
+ 0,
172
+ 15.05,
173
+ ['get', 'height']
174
+ ],
175
+ 'fill-extrusion-base': [
176
+ 'interpolate',
177
+ ['linear'],
178
+ ['zoom'],
179
+ 15,
180
+ 0,
181
+ 15.05,
182
+ ['get', 'min_height']
183
+ ],
184
+ 'fill-extrusion-opacity': 0.7
185
+ }
186
+ },
187
+ labelLayerId
188
+ )
189
+ }
190
+
191
+ /**
192
+ * 行政区域边界
193
+ * @param {*} geoJson
194
+ * @param {*} config
195
+ */
196
+ drawCityBorder(geoJson, config = {}) {
197
+ const style = Object.assign({
198
+ lineWidth: 4,
199
+ lineColor: 'rgb(100,149,237)',
200
+ lineOpacity: 1,
201
+ fillColor: 'rgb(2,26,79)',
202
+ fillOpacity: 0.2
203
+ }, config)
204
+ let mbData = geoJson.features[0].geometry.coordinates[0].flat(1)
205
+ this.map.addLayer({
206
+ //蒙版边界
207
+ id: 'bj-line',
208
+ type: 'line',
209
+ source: {
210
+ type: 'geojson',
211
+ data: geoJson, //区划的面数据
212
+ },
213
+ paint: {
214
+ 'line-color': style.lineColor || 'rgb(100,149,237)',
215
+ 'line-width': style.lineWidth || 3,
216
+ 'line-opacity': style.lineOpacity || 1
217
+ },
218
+ layout: {
219
+ visibility: 'visible',
220
+ }
221
+ })
222
+
223
+ this.map.addLayer({
224
+ //蒙版图层 //通过边界数据反选 达到挖洞效果
225
+ id: 'bj-model',
226
+ type: 'fill',
227
+ source: {
228
+ type: 'geojson',
229
+ data: {
230
+ type: 'Feature',
231
+ geometry: {
232
+ type: 'Polygon',
233
+ coordinates: [
234
+ [
235
+ [-180, 90],
236
+ [180, 90],
237
+ [180, -90],
238
+ [-180, -90],
239
+ ],
240
+ mbData,
241
+ ],
242
+ },
243
+ },
244
+ },
245
+ paint: {
246
+ 'fill-color': style.fillColor || 'rgba(255,255,255,.2)',
247
+ 'fill-opacity': style.fillOpacity || 1 /* 透明度 */ ,
248
+ },
249
+ layout: {
250
+ visibility: 'visible',
251
+ },
252
+ })
253
+ }
254
+
255
+ /**
256
+ * 获取摄像机位置
257
+ */
258
+ getCamera() {
259
+ let {
260
+ center,
261
+ pitch,
262
+ zoom,
263
+ bearing
264
+ } = this.map.transform
265
+ let data = {
266
+ lat: center.lat,
267
+ lng: center.lng,
268
+ center: [center.lng, center.lat],
269
+ pitch,
270
+ zoom,
271
+ bearing
272
+ }
273
+ console.log(data)
274
+ return data
275
+ }
276
+
277
+ /**
278
+ * 添加气泡弹窗
279
+ * @param {*} coordinates
280
+ * @param {*} html
281
+ */
282
+ addPopup(coordinates, html) {
283
+ this.removePopup()
284
+ popup = new mapBoxGl.Popup()
285
+ .setLngLat(coordinates)
286
+ .setHTML(html)
287
+ .addTo(this.map)
288
+ popup.on('close', (e) => {
289
+ popup = null
290
+ })
291
+ }
292
+
293
+ /**
294
+ * 删除气泡
295
+ */
296
+ removePopup() {
297
+ if (popup) {
298
+ popup.remove()
299
+ popup = null
300
+ }
301
+ }
302
+
303
+ /**
304
+ * 适应线段范围
305
+ * @param {*} coordinates
306
+ * @param {*} options
307
+ */
308
+ fitLineBounds(coordinates, options) {
309
+ let bounds = coordinates.reduce((bounds, coord) => {
310
+ return bounds.extend(coord)
311
+ }, new mapBoxGl.LngLatBounds(coordinates[0], coordinates[0]))
312
+ this.map.fitBounds(bounds, options)
313
+ }
314
+
315
+ /**
316
+ * 放大 / 缩小地图
317
+ * @param {*} type // type = in 放大
318
+ * @param {*} center // center中心点
319
+ */
320
+ zoom(type, center = '') {
321
+ const maxZoom = this.options.maxZoom || 18
322
+ const minZoom = this.options.minZoom || 6
323
+ let zoom = this.map.getZoom()
324
+ if (!center) {
325
+ center = this.map.getCenter()
326
+ }
327
+ if (type === 'in') {
328
+ // 点击+
329
+ if (zoom < maxZoom) {
330
+ zoom += 1
331
+ }
332
+ } else {
333
+ if (zoom > minZoom) {
334
+ zoom -= 1
335
+ }
336
+ }
337
+ this.map.flyTo({
338
+ center,
339
+ zoom
340
+ })
341
+ }
342
+
343
+ /**
344
+ * 禁用旋转视角
345
+ */
346
+ pitchWithRotate(value) {
347
+ if (value) {
348
+ this.map.dragRotate.enable()
349
+ } else {
350
+ this.map.dragRotate.disable()
351
+ }
352
+ }
353
+
354
+ /**
355
+ * 禁用地图缩放
356
+ */
357
+ disableZoom(value) {
358
+ if (value) {
359
+ this.map.scrollZoom.enable()
360
+ } else {
361
+ this.map.scrollZoom.disable()
362
+ }
363
+ }
364
+
365
+ /**
366
+ * 修改地图样式
367
+ * @param {*} style // 地图样式
368
+ * @returns
369
+ */
370
+ checkStyle(style = 'mapbox://styles/mapbox/streets-v11') {
371
+ let map = this.map
372
+ return new Promise((resolve) => {
373
+ map.setStyle(style)
374
+ map.on('style.load', () => {
375
+ this.addFog()
376
+ resolve(true)
377
+ })
378
+ })
379
+ }
380
+
381
+ /**
382
+ * 设置覆盖地图颜色
383
+ * @param {*} color
384
+ */
385
+ setMapColor(color = 'rgba(3, 20, 57, 0.4)') {
386
+ let map = this.map
387
+ map.addLayer({
388
+ 'id': 'mapColor',
389
+ 'type': 'background',
390
+ 'paint': {
391
+ 'background-color': color
392
+ },
393
+ 'metadata': {
394
+ 'mapbox:group': '92ca48f13df25'
395
+ }
396
+ })
397
+ }
398
+ }
399
+
400
+ export default new mapSdk()
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "xy-map",
3
+ "version": "1.0.0",
4
+ "description": "地图组件",
5
+ "main": "map.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "publish": "npm publish"
9
+ },
10
+ "keywords": [],
11
+ "author": "han",
12
+ "license": "ISC"
13
+ }
@@ -0,0 +1,29 @@
1
+ .xy-hover-html {
2
+ }
3
+
4
+ .xy-hover-html .hover-item {
5
+ display: flex;
6
+ }
7
+ .xy-hover-html .hover-item .label {
8
+ width: 80px;
9
+ }
10
+
11
+ .xy-hover-html .hover-item .value {
12
+ flex: 1;
13
+ }
14
+
15
+ .xy-hover-html .waring-color {
16
+ color: #e6a23c;
17
+ }
18
+
19
+ .xy-hover-html .success-color {
20
+ color: #67c23a;
21
+ }
22
+
23
+ .xy-hover-html .error-color {
24
+ color: #f56c6c;
25
+ }
26
+
27
+ .xy-hover-html .info-color {
28
+ color: #909399;
29
+ }
package/style/map.css ADDED
@@ -0,0 +1,7 @@
1
+ .mapboxgl-ctrl-attrib {
2
+ display: none;
3
+ }
4
+
5
+ .mapboxgl-ctrl-logo {
6
+ display: none !important;
7
+ }
@@ -0,0 +1,108 @@
1
+ import mapSdk from '../map'
2
+
3
+ /**
4
+ * 地图点击
5
+ * @param {*} id 图层id
6
+ * @param {*} callback 点击事件回调
7
+ */
8
+ export const mapClick = (id, callback) => {
9
+ let {
10
+ map
11
+ } = mapSdk
12
+ changeMapCursor(id)
13
+
14
+ map.on('click', id, (e) => {
15
+ //阻止点击重合部分触发事件 重叠时点(isPoint = true)图层优先显示
16
+ // if (callback) {
17
+ // e.preventDefault()
18
+ // } else {
19
+ if (e.defaultPrevented) return
20
+ e.preventDefault()
21
+
22
+ // }
23
+ let coordinates
24
+ //点图层返回点要素经纬度,线面返回所点击的点经纬度
25
+ if (callback) {
26
+ coordinates = e.features[0].geometry.coordinates.slice()
27
+ while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
28
+ coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360
29
+ }
30
+ } else {
31
+ coordinates = [e.lngLat.lng, e.lngLat.lat]
32
+ }
33
+ const properties = e.features[0].properties
34
+
35
+ const event = {
36
+ coordinates,
37
+ properties,
38
+ e,
39
+ position: [e.lngLat.lng, e.lngLat.lat]
40
+ }
41
+ callback(event)
42
+ })
43
+ }
44
+
45
+ /**
46
+ * 图表hover事件
47
+ */
48
+ export const mapHover = (id, callback) => {
49
+ let {
50
+ map
51
+ } = mapSdk
52
+ changeMapCursor(id)
53
+ map.on('mousemove', id, (e) => {
54
+ if (callback) {
55
+ e.preventDefault()
56
+ } else {
57
+ if (e.defaultPrevented) return
58
+ }
59
+
60
+ let coordinates
61
+ //点图层返回点要素经纬度,线面返回所点击的点经纬度
62
+ if (callback) {
63
+ coordinates = e.features[0].geometry.coordinates.slice()
64
+ while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
65
+ coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360
66
+ }
67
+ } else {
68
+ coordinates = [e.lngLat.lng, e.lngLat.lat]
69
+ }
70
+ const properties = e.features[0].properties
71
+
72
+ const event = {
73
+ coordinates,
74
+ properties,
75
+ e,
76
+ position: [e.lngLat.lng, e.lngLat.lat]
77
+ }
78
+ callback(event)
79
+ })
80
+
81
+ map.on('mouseleave', id, () => {
82
+ map.getCanvas().style.cursor = ''
83
+ callback(false)
84
+ })
85
+ }
86
+
87
+
88
+ /**
89
+ * 改变图层手势为手型
90
+ * @param {*} id 图层id
91
+ */
92
+ export const changeMapCursor = (id) => {
93
+ let {
94
+ map
95
+ } = mapSdk
96
+ const layers = map.getStyle().layers
97
+ layers.forEach(layer => {
98
+ const layerId = layer.id
99
+ if (layerId.includes(id)) {
100
+ map.on('mousemove', layerId, () => {
101
+ map.getCanvas().style.cursor = 'pointer'
102
+ })
103
+ map.on('mouseleave', layerId, (e) => {
104
+ map.getCanvas().style.cursor = ''
105
+ })
106
+ }
107
+ })
108
+ }