VJMAP logoVJMAP
CAD · WebGIS
中

Switch Map

Updated 2026-03-07~ 28 min read
.md

Switch Layers (Raster Tiles)

Raster tile layer switching achieves the switch effect by modifying layer styles on the backend

Switch Layers (Raster)

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

Switch Layers (Vector Tiles)

Vector tile layer switching achieves the switch effect by modifying styles on the frontend

Switch Layers (Vector)

// 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);
}

Switch Map (Same Map Object)

Switch maps by calling switchMap.

Switch Map (Same Map Object)

/**
 * 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>;
Runs in a sandbox against the VJMAP public demo service


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)

// 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)

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)

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

Tip

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

Was this page helpful?