# 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;
    }, []))
}
1
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);
}
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

# 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>;
1
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)

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

# 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");
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

Tip

Remember to call map.destory() before destroying the map Destroy Map Object (opens new window)