---
title: 切换地图
source: https://vjmap.com/guide/switchmap.html
---

# 切换地图


## 切换图层(栅格瓦片)

`栅格瓦片切换图层`是通过`后台修改图层样式`来达到切换效果

[切换图层(栅格)](https://vjmap.com/demo/#/demo/map/service/14switchLayerRaster)
```ts
// 切换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;
    }, []))
}
```

## 切换图层(矢量瓦片)

`矢量瓦片切换图层`是通过`前端修改样式`来达到切换效果

[切换图层(矢量)](https://vjmap.com/demo/#/demo/map/service/14switchLayerVector)
```js
// 切换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);
}
```


## 切换图形(地图对象不变)

通过调用 `switchMap` 来切换图形。

[切换图形(地图对象不变)](https://vjmap.com/demo/#/demo/map/service/14switchMap)
```ts
/**
 * 切换地图，请确保之前打开过地图,开始前触发`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>;
```


<mapFrameEx>
<pre>
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
    mapid: "sys_hello", // 地图ID
    mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap.openMapLightStyle() // div为深色背景颜色时，这里也传深色背景样式
})
if (res.error) {
    // 如果打开出错
    showError(res.error)
    return;
}
// 获取地图范围
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(mapBounds);
//
// 地图对象
let map = new vjmap.Map({
    container: 'map', // DIV容器ID
    style: svc.rasterStyle(), // 样式，这里是栅格样式
    center: prj.toLngLat(mapBounds.center()), // 设置地图中心点
    zoom: 1, // 设置地图缩放级别
    pitch: 0,
    renderWorldCopies: false // 不显示多屏地图
});
// 关联服务对象和投影对象
map.attach(svc, prj);
await map.onLoad();
const mapids = ["sys_hello", "sys_world", "sys_cad2000", "sys_zp"]
let curIdx = 1;
let curMapId = mapids[0]
const switchMap = async () => {
    curMapId = mapids[curIdx++ % mapids.length]
    await map.switchMap({
        mapid: curMapId,
        style: vjmap.openMapDarkStyle()
    });
}
setInterval(() => switchMap(), 3000)
</pre>
</mapFrameEx>
<br/>
<br/>

## 切换图形(地图对象改变, 同一个div元素)

这个方法是先通过`map.destory()`销毁之前的`map`对象,再创建一个新的`map`对象关联之前的div元素
[切换图形(地图对象改变，同个div)](https://vjmap.com/demo/#/demo/map/service/14switchMapDestory)

```js
// 要切换的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)

```

## 切换图形(地图对象改变, 关联不同div元素)

 这个方法是清空之前地图对象关联的div，再重新创建一个新的div，与创建的新的`map`对象相关联

[切换图形(地图对象改变，不同div)](https://vjmap.com/demo/#/demo/map/service/14switchMapNew)


```js
// 创建一个新的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");
```


::: tip 提示
地图销毁前记得调用 `map.destory()`   [销毁地图对象](https://vjmap.com/demo/#/demo/map/map/closeMap)
:::
