Switch Map
Switch Layers (Raster Tiles)
Raster tile layer switching achieves the switch effect by modifying layer styles on the backend
// 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 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. 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>;
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// Open map
let res = await svc.openMap({
mapid: "sys_hello", // Map ID
mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry rendering
style: vjmap.openMapLightStyle() // Use dark background style when div has dark background
})
if (res.error) {
// If open fails
showError(res.error)
return;
}
// Get map extent
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// Create geometric projection coordinate system from map extent
let prj = new vjmap.GeoProjection(mapBounds);
//
// Map object
let map = new vjmap.Map({
container: 'map', // DIV container ID
style: svc.rasterStyle(), // Style, raster style here
center: prj.toLngLat(mapBounds.center()), // Set map center
zoom: 1, // Set map zoom level
pitch: 0,
renderWorldCopies: false // Don't show multi-screen map
});
// Associate service object and projection object
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)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