# 切换地图
# 切换图层(栅格瓦片)
栅格瓦片切换图层
是通过后台修改图层样式
来达到切换效果
// 切换cad图层
export const switchCadLayers = async (map: Map, layers: {name: string; isOff: boolean}[]) => {
let svc = map.getService();
// 如果是栅格瓦片
await map.switchLayers(svc, layers.reduce((sum, val) => {
if (!val.isOff) {
// @ts-ignore
sum.push(val.name);
}
return sum;
}, []))
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 切换图层(矢量瓦片)
矢量瓦片切换图层
是通过前端修改样式
来达到切换效果
// 切换cad图层
export const switchCadLayers = async (map: Map, layers: {name: string; isOff: boolean}[]) => {
let svc = map.getService();
// 如果是矢量瓦片
let onLayers = layers.reduce((sum, val) => {
if (!val.isOff) {
// @ts-ignore
sum.push(val.name);
}
return sum;
}, []); // 要开的图层
switchVectorLayers(map, onLayers)
}
// 矢量瓦片切换图层 onLayers 要显示的图层名称数组
export const switchVectorLayers = (map: Map, onLayers: string[]) => {
// 通过图层名称来查找图层id
const getLayerIdByName = (name: string) => {
return svc.getMapLayers().findIndex(layer => layer.name === name)
}
// 增加实体图层判断条件,只要满足任何一种类型即可,如 ['图层一','图层二']
const conditionLayers = (layers: string[], inputIsIndex: boolean) => {
if (!Array.isArray(layers)) layers = [layers];// 先转成数组,再统一用数组去算吧
let layerIndexs: number[] = [];
if (!inputIsIndex) {
// 如果输入的不是图层索引,是图层名称,则需要转成图层索引
layerIndexs = layers.map(layer => getLayerIdByName(layer)); // 把图层名称转为图层索引,在矢量瓦片中图层是用索引来表示的
}
if (layerIndexs.length == 0) {
layerIndexs = [-1]; // 如果全部关闭,防止数组为空,加一个不存在的
}
return [
"match",
['get', 'layer'],
layerIndexs,
true,
false
]
}
// 获取之前的默认的矢量图层样式,然后在当前样式中,对矢量图层的数据进行图层进行过滤
let style = map.getStyle();
let svc = map.getService();
let vectorStyle = svc.vectorStyle();
let vectorLayerIds = vectorStyle.layers.map(layer => layer.id);
let filter = conditionLayers(onLayers, false);
for (let i = 0; i < style.layers.length; i++) {
if (vectorLayerIds.includes(style.layers[i].id)) {
// @ts-ignore
style.layers[i].filter = filter; // 设置过滤条件
}
}
map.setStyle(style);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 切换图形(地图对象不变)
通过调用 switchMap
来切换图形。
切换图形(地图对象不变) (opens new window)
/**
* 切换地图,请确保之前打开过地图,开始前触发`mapopenstart`事件,打开后触发`mapopenfinish`事件
* @param param 打开选项
* @param isKeepOldLayers 是否保留之前的图层数据,默认false
* @param isVectorStyle 是否为矢量样式
* @param isSetCenter 是否默认设置为地图中心点
* @param isFitBounds 默认是否缩放
* @param source 数据源id,如果修改了默认的栅格或瓦片source,需要传此参数
*/
switchMap(param: IOpenMapParam, isKeepOldLayers?:boolean, isVectorStyle?:boolean, isSetCenter?: boolean, isFitBounds?: boolean, source?: string): Promise<any>;
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 切换图形(地图对象改变, 同一个div元素)
这个方法是先通过map.destory()
销毁之前的map
对象,再创建一个新的map
对象关联之前的div元素
切换图形(地图对象改变,同个div) (opens new window)
// 要切换的mapid数组
const mapids = ["sys_zp", "sys_hello", "sys_world", "sys_cad2000"]
let curMapIdIndex = 0;
/**
* 创建地图对象
* @param serviceUrl 服务地址接口
* @param mapId 地图ID
* @param mapOpenWay 打开方式,缺省vjmap.MapOpenWay.GeomRender
* @param isRaster true为栅格,false为矢量
* @return {Promise<Map>}
*/
async function newMap(serviceUrl, mapId, mapOpenWay = vjmap.MapOpenWay.GeomRender, isRaster = true) {
// 地图服务对象
let svc = new vjmap.Service(serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
mapid: mapids[curMapIdIndex], // 地图ID
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
throw Error(res.error)
}
// 获取地图范围
let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(mapExtent);
// 如果为内存方式打开,则只能为栅格方式
if (mapOpenWay === vjmap.MapOpenWay.Memory) {
isRaster = true;
}
// 地图样式
let style = isRaster ? svc.rasterStyle() : svc.vectorStyle();
// 地图对象
let map = new vjmap.Map({
container: 'map', // DIV容器ID
style: style, // 样式,这里是栅格样式
center: prj.toLngLat(mapExtent.center()), // 设置地图中心点
zoom: 2, // 设置地图缩放级别
renderWorldCopies: false // 不显示多屏地图
});
// 关联服务对象和投影对象
map.attach(svc, prj);
// 根据地图本身范围缩放地图至全图显示
map.fitMapBounds();
// 使地图能选择点击拾取高亮
if (isRaster) {
map.enableLayerClickHighlight(svc, e => {
if (!e) return;
let content = `type: ${e.name}, id: ${e.objectid}, layer: ${e.layerindex}`
e && map.logInfo(content);
})
} else {
// 有高亮状态(鼠标在地图元素上时,会高亮)
map.enableVectorLayerHoverHighlight((event, feature, layer) => {
if (!feature) return;
// 点击高亮实体回调事件
let content = `event: ${event}; feature: ${feature.id}; layer: ${layer}`
map.logInfo(content)
})
}
await map.onLoad();
map.logInfo("地图加载完成", "success")
// 给地图增加一些数据图层做为测试
await addDataLayer(map);
return map;
}
// 给地图增加一些数据图层做为测试
const addDataLayer = async (map) => {
// 导航条控件
map.addControl(new vjmap.NavigationControl());
// 鼠标移动显示坐标位置控件
map.addControl(new vjmap.MousePositionControl({showZoom: true}));
let bounds = map.getGeoBounds() ;// 获取地图范围
// 增加marker
for(let n = 0; n < 3; n++) {
let marker = new vjmap.Marker({
color: vjmap.randomColor(),
draggable: true
}).setLngLat(map.toLngLat(bounds.randomPoint()))
marker.addTo(map);
}
// 增加一个随机位置的popup
let popupPoint = bounds.randomPoint();
let popup = new vjmap.Popup({ closeOnClick: false })
.setLngLat(map.toLngLat(popupPoint))
.setHTML(`<h2><p style="color:#f00">我是Popup</p></h2>`)
.addTo(map);
// 创建polyline对象,包含三条随机线
let polylineData = [];
for(let i = 0; i < 3; i++) {
// 每条线有2-4个随机点
const points = bounds.randomPoints(2, 4);
polylineData.push({
points: map.toLngLat(points),
properties: {
name: `线 ${i+1}`,
color: vjmap.randomColor()
}
});
}
// 创建polyline对象
let polylines = new vjmap.Polyline({
data: polylineData,
lineColor: ['get', 'color'],
lineWidth: 3,
lineOpacity: 0.8,
isHoverPointer: true
});
polylines.addTo(map);
// 添加点击事件
polylines.clickLayer(e => {
map.logInfo(`您点击了: ${e.features[0].properties.name}`);
});
for (let i = 0; i < 4; i++) {
// await map.loadImageEx("icon" + i, env.assetsPath + `images/sensor${i + 1}.png`);
await map.loadImageEx("icon" + i, `https://vjmap.com/static/assets/images/sensor${i + 1}.png`);
}
const geoDatas = []
for (let i = 0; i < 10; i++) {
const pt = bounds.randomPoint();
const data = {
point: map.toLngLat(pt),
properties: {
name: `ID:${i + 1}`,
icon: "icon" + vjmap.randInt(0, 3)
}
}
geoDatas.push(data);
}
const symbols = new vjmap.Symbol({
data: geoDatas,
// 图标名来源于geojson属性中的icon字段
iconImage: ['get', 'icon'],
// 二级以下全部用icon1图标,二级以上用自己属性中的图标名
//iconImage: ["step", ["zoom"], "icon1", 2, ['get', 'icon']],
iconOffset: [0, -12],
// 鼠标hover时设置透明度0.8,不悬浮1.0
iconOpacity: ['case', ['to-boolean', ['feature-state', 'hover']], 0.8, 1.0],
textField: ['get', 'name'],
textFont: ['Arial Unicode MS Regular'],
textSize: 14,
textColor: '#FFA0FD',
textOffset: [0, 0.5],
textAnchor: 'top',
iconAllowOverlap: false,
textAllowOverlap: false,
isHoverPointer: true,
isHoverFeatureState: true
});
symbols.addTo(map);
symbols.clickLayer(e => {
if (e.defaultPrevented) return; // 如果事件之前阻止了,则不再执行了
map.logInfo(`您点击了第 ${e.features[0].id} 个,名称为 ${e.features[0].properties.name},的图标`)
e.preventDefault(); // 阻止之后的事件执行
})
let geoDatas2 = [];
for(let i = 1; i <= 2; i++) {
let mapBounds = map.getGeoBounds(i / 10.0);
let points = mapBounds.toPointArray();
points.push(points[0]); // 闭合
geoDatas2.push({
points: map.toLngLat(points),
id: i,
properties: {
lineWidth: 8 + i * 2,
name: `${i}环`
}
});
}
let arrowAnimateLine = vjmap.createArrowAnimateLineLayer(map, geoDatas2, {
arrowFillColor: vjmap.randomColor(),
arrowStrokeColor: "#fff",
arrowStrokeWidth: 6,
canvasWidth: 128,
canvasHeight: 32,
arrowWidth: 16,
frameCount: 4,
lineWidth: ['get', 'lineWidth'],
lineOpacity: ['case', ['to-boolean', ['feature-state', 'hover']], 0.6, 1.0],
isHoverPointer: true,
isHoverFeatureState: true
});
arrowAnimateLine.polyline.clickLayer(e => map.logInfo(`您点击了第 ${e.features[0].id} 个,名称为 ${e.features[0].properties.name}`))
arrowAnimateLine.polyline.hoverPopup(f => `<h3>ID: ${f.properties.name}`, { anchor: 'bottom' });
// 获取绘制图层
const draw = map.getDrawLayer();
// 初始加入一个多边形
draw.set(vjmap.createPolygonGeoJson(map.toLngLat(bounds.randomPoints(3, 3))));
}
// 创建地图
let map = await newMap(env.serviceUrl, env.exampleMapId, vjmap.MapOpenWay.GeomRender, true)
setInterval(async () => {
map.logInfo("销毁地图")
map.destory(); // 销毁地图
curMapIdIndex = (curMapIdIndex + 1) % mapids.length;
// 再创建一个新的map对象
map = await newMap(env.serviceUrl, env.exampleMapId, vjmap.MapOpenWay.GeomRender, true)
}, 10000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# 切换图形(地图对象改变, 关联不同div元素)
这个方法是清空之前地图对象关联的div,再重新创建一个新的div,与创建的新的map
对象相关联
切换图形(地图对象改变,不同div) (opens new window)
// 创建一个新的div对象
const createNewMapDivId = ()=> {
// 先清空之前的
let parentDiv = document.getElementById("map");
parentDiv.innerHTML = "";
let newMapDiv = document.createElement("div");
newMapDiv.id = vjmap.RandomID(6);
newMapDiv.style.position = 'absolute';
newMapDiv.style.width = "100%";
newMapDiv.style.height = "100%";
parentDiv.appendChild(newMapDiv);
return newMapDiv.id;
}
const openNewMap = async (mapid, isVector) => {
// 打开地图
let res = await svc.openMap({
mapid: mapid,
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
message.error(res.error)
return;
}
// 获取地图的范围
let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
// 建立坐标系
let prj = new vjmap.GeoProjection(mapExtent);
// 新建地图对象
let map = new vjmap.Map({
container: createNewMapDivId(), // 这里要创建一个新的div对象,与新的map对象相绑定
style: isVector ? svc.vectorStyle() : svc.rasterStyle(), // 栅格瓦片样式
center: prj.toLngLat(mapExtent.center()), // 中心点
zoom: 2,
renderWorldCopies: false
});
// 地图关联服务对象和坐标系
map.attach(svc, prj);
// 使地图全部可见
map.fitMapBounds();
}
let curMapId;
const switchMap = async mapid => {
if (curMapId == mapid) return; // 如果一样,不用管了
await openNewMap(mapid);
curMapId = mapid;
}
await switchMap("sys_zp");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
提示
地图销毁前记得调用 map.destory()
销毁地图对象 (opens new window)