# Switch Map
# Switch Layers (Raster Tiles)
Raster tile layer switching achieves the switch effect by modifying layer styles on the backend
Switch Layers (Raster) (opens new window)
// Switch CAD layers
export const switchCadLayers = async (map: Map, layers: {name: string; isOff: boolean}[]) => {
let svc = map.getService();
// If using raster tiles
await map.switchLayers(svc, layers.reduce((sum, val) => {
if (!val.isOff) {
// @ts-ignore
sum.push(val.name);
}
return sum;
}, []))
}
2
3
4
5
6
7
8
9
10
11
12
# Switch Layers (Vector Tiles)
Vector tile layer switching achieves the switch effect by modifying styles on the frontend
Switch Layers (Vector) (opens new window)
// Switch CAD layers
export const switchCadLayers = async (map: Map, layers: {name: string; isOff: boolean}[]) => {
let svc = map.getService();
// If using vector tiles
let onLayers = layers.reduce((sum, val) => {
if (!val.isOff) {
// @ts-ignore
sum.push(val.name);
}
return sum;
}, []); // Layers to show
switchVectorLayers(map, onLayers)
}
// Switch vector tile layers - onLayers is array of layer names to display
export const switchVectorLayers = (map: Map, onLayers: string[]) => {
// Find layer id by layer name
const getLayerIdByName = (name: string) => {
return svc.getMapLayers().findIndex(layer => layer.name === name)
}
// Add entity layer filter condition; any type match is sufficient, e.g. ['Layer1','Layer2']
const conditionLayers = (layers: string[], inputIsIndex: boolean) => {
if (!Array.isArray(layers)) layers = [layers];// Convert to array first, then process uniformly
let layerIndexs: number[] = [];
if (!inputIsIndex) {
// If input is not layer index but layer name, convert to layer index
layerIndexs = layers.map(layer => getLayerIdByName(layer)); // Convert layer names to layer indices; vector tiles use indices for layers
}
if (layerIndexs.length == 0) {
layerIndexs = [-1]; // If all closed, add non-existent index to prevent empty array
}
return [
"match",
['get', 'layer'],
layerIndexs,
true,
false
]
}
// Get the default vector layer style, then filter vector layer data in the current style
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; // Set filter condition
}
}
map.setStyle(style);
}
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
# Switch Map (Same Map Object)
Switch maps by calling switchMap.
Switch Map (Same Map Object) (opens new window)
/**
* Switch map. Ensure the map was opened previously. Triggers `mapopenstart` before start and `mapopenfinish` after opening.
* @param param Open options
* @param isKeepOldLayers Whether to keep previous layer data, default false
* @param isVectorStyle Whether to use vector style
* @param isSetCenter Whether to set as map center by default
* @param isFitBounds Whether to fit bounds by default
* @param source Data source id; pass this if the default raster or tile source was modified
*/
switchMap(param: IOpenMapParam, isKeepOldLayers?:boolean, isVectorStyle?:boolean, isSetCenter?: boolean, isFitBounds?: boolean, source?: string): Promise<any>;
2
3
4
5
6
7
8
9
10
# Switch Map (Different Map Object, Same div Element)
This method first destroys the previous map object via map.destory(), then creates a new map object associated with the same div element.
Switch Map (Different Map Object, Same div) (opens new window)
// Array of mapids to switch
const mapids = ["sys_zp", "sys_hello", "sys_world", "sys_cad2000"]
let curMapIdIndex = 0;
/**
* Create map object
* @param serviceUrl Service URL
* @param mapId Map ID
* @param mapOpenWay Open way, default vjmap.MapOpenWay.GeomRender
* @param isRaster true for raster, false for vector
* @return {Promise<Map>}
*/
async function newMap(serviceUrl, mapId, mapOpenWay = vjmap.MapOpenWay.GeomRender, isRaster = true) {
// Map service object
let svc = new vjmap.Service(serviceUrl, env.accessToken)
// Open map
let res = await svc.openMap({
mapid: mapids[curMapIdIndex], // Map ID
mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry rendering
style: vjmap.openMapDarkStyle() // Use dark background style when div has dark background
})
if (res.error) {
// If open fails
throw Error(res.error)
}
// Get map extent
let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
// Create geometric projection coordinate system from map extent
let prj = new vjmap.GeoProjection(mapExtent);
// If opened in memory mode, only raster is supported
if (mapOpenWay === vjmap.MapOpenWay.Memory) {
isRaster = true;
}
// Map style
let style = isRaster ? svc.rasterStyle() : svc.vectorStyle();
// Map object
let map = new vjmap.Map({
container: 'map', // DIV container ID
style: style, // Style, raster style here
center: prj.toLngLat(mapExtent.center()), // Set map center
zoom: 2, // Set map zoom level
renderWorldCopies: false // Don't show multi-screen map
});
// Associate service object and projection object
map.attach(svc, prj);
// Fit map to full extent based on map bounds
map.fitMapBounds();
// Enable select click highlight
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 {
// Hover highlight (highlights when mouse is over map element)
map.enableVectorLayerHoverHighlight((event, feature, layer) => {
if (!feature) return;
// Click highlight entity callback
let content = `event: ${event}; feature: ${feature.id}; layer: ${layer}`
map.logInfo(content)
})
}
await map.onLoad();
map.logInfo("Map loaded", "success")
// Add some data layers for testing
await addDataLayer(map);
return map;
}
// Add some data layers for testing
const addDataLayer = async (map) => {
// Navigation control
map.addControl(new vjmap.NavigationControl());
// Mouse position control showing coordinates
map.addControl(new vjmap.MousePositionControl({showZoom: true}));
let bounds = map.getGeoBounds() ;// Get map extent
// Add markers
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);
}
// Add a popup at random position
let popupPoint = bounds.randomPoint();
let popup = new vjmap.Popup({ closeOnClick: false })
.setLngLat(map.toLngLat(popupPoint))
.setHTML(`<h2><p style="color:#f00">I am Popup</p></h2>`)
.addTo(map);
// Create polyline object with three random lines
let polylineData = [];
for(let i = 0; i < 3; i++) {
// Each line has 2-4 random points
const points = bounds.randomPoints(2, 4);
polylineData.push({
points: map.toLngLat(points),
properties: {
name: `Line ${i+1}`,
color: vjmap.randomColor()
}
});
}
// Create polyline object
let polylines = new vjmap.Polyline({
data: polylineData,
lineColor: ['get', 'color'],
lineWidth: 3,
lineOpacity: 0.8,
isHoverPointer: true
});
polylines.addTo(map);
// Add click event
polylines.clickLayer(e => {
map.logInfo(`You clicked: ${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,
// Icon name from icon field in geojson properties
iconImage: ['get', 'icon'],
// Use icon1 for zoom below 2, use own icon from properties above 2
//iconImage: ["step", ["zoom"], "icon1", 2, ['get', 'icon']],
iconOffset: [0, -12],
// Set opacity 0.8 on hover, 1.0 when not hovering
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; // If event was prevented, don't execute
map.logInfo(`You clicked icon ${e.features[0].id}, name: ${e.features[0].properties.name}`)
e.preventDefault(); // Prevent subsequent event execution
})
let geoDatas2 = [];
for(let i = 1; i <= 2; i++) {
let mapBounds = map.getGeoBounds(i / 10.0);
let points = mapBounds.toPointArray();
points.push(points[0]); // Close
geoDatas2.push({
points: map.toLngLat(points),
id: i,
properties: {
lineWidth: 8 + i * 2,
name: `${i} ring`
}
});
}
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(`You clicked ${e.features[0].id}, name: ${e.features[0].properties.name}`))
arrowAnimateLine.polyline.hoverPopup(f => `<h3>ID: ${f.properties.name}`, { anchor: 'bottom' });
// Get draw layer
const draw = map.getDrawLayer();
// Initially add a polygon
draw.set(vjmap.createPolygonGeoJson(map.toLngLat(bounds.randomPoints(3, 3))));
}
// Create map
let map = await newMap(env.serviceUrl, env.exampleMapId, vjmap.MapOpenWay.GeomRender, true)
setInterval(async () => {
map.logInfo("Destroying map")
map.destory(); // Destroy map
curMapIdIndex = (curMapIdIndex + 1) % mapids.length;
// Create a new map object
map = await newMap(env.serviceUrl, env.exampleMapId, vjmap.MapOpenWay.GeomRender, true)
}, 10000)
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
# Switch Map (Different Map Object, Different div Element)
This method clears the div previously associated with the map object, then creates a new div and associates it with the new map object.
Switch Map (Different Map Object, Different div) (opens new window)
// Create a new div object
const createNewMapDivId = ()=> {
// Clear previous first
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) => {
// Open map
let res = await svc.openMap({
mapid: mapid,
mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry rendering
style: vjmap.openMapDarkStyle() // Use dark background style when div has dark background
})
if (res.error) {
message.error(res.error)
return;
}
// Get map extent
let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
// Create coordinate system
let prj = new vjmap.GeoProjection(mapExtent);
// Create map object
let map = new vjmap.Map({
container: createNewMapDivId(), // Create a new div object to bind to the new map object
style: isVector ? svc.vectorStyle() : svc.rasterStyle(), // Raster tile style
center: prj.toLngLat(mapExtent.center()), // Center point
zoom: 2,
renderWorldCopies: false
});
// Associate map with service object and coordinate system
map.attach(svc, prj);
// Make entire map visible
map.fitMapBounds();
}
let curMapId;
const switchMap = async mapid => {
if (curMapId == mapid) return; // If same, no need to change
await openNewMap(mapid);
curMapId = mapid;
}
await switchMap("sys_zp");
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
Tip
Remember to call map.destory() before destroying the map Destroy Map Object (opens new window)