---
title: Web Map Application
source: https://vjmap.com/en/guide/webmapapp.html
---

# Web Map Application

As a map engine, `VJMap` `vjmap` can not only load CAD map tiles, but also directly load web map tiles, and supports overlay display of CAD maps and web maps.

## Load Web Map Directly

Load web maps by providing `WMTS` tile URLs.

<mapFrameEx>
<pre>
// --Tianditu map--
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// Create lnglat projection coordinate system based on map bounds
let prj = new vjmap.LnglatProjection();
// Map object
let map = new vjmap.Map({
    container: 'map', // DIV container ID
    style: {
        version: svc.styleVersion(),
        glyphs: svc.glyphsUrl(),
        sources: {
            tdt1: {
                type: 'raster',
                // Imagery
                // tiles: ["https://t3.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk=7baeffb96bf61861b302d0f963cfda66"],
                // Road
                tiles: ["https://t3.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk=7baeffb96bf61861b302d0f963cfda66"]
            },
            tdt2: {
                type: 'raster',
                tiles: ["https://t3.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk=7baeffb96bf61861b302d0f963cfda66"],
            }
        },
        layers: [{
            id: 'tdt1',
            type: 'raster',
            source: 'tdt1',
        },{
            id: 'tdt2',
            type: 'raster',
            source: 'tdt2',
        }]
    },
    center: prj.toLngLat([116.3912, 39.9073]),
    zoom: 8,
    pitch: 0,
    renderWorldCopies: false // Do not display multi-screen map
});
// Associate service object and projection object
map.attach(svc, prj);
// Fit map to full extent based on map bounds
//map.fitMapBounds();
await map.onLoad();
const co = prj.toLngLat([116.3912, 39.9073])
const marker = new vjmap.Marker({color: "red"})
marker.setLngLat(co).addTo(map)
// Terrain
// map.addSource('dem', {
//     type: 'raster-dem',
//     tiles: ["https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=pk.eyJ1IjoiZnJhemllcm1hcmsiLCJhIjoiY2wzOTBhZzJiMDFwejNqbzJyMGs0YmZ5NCJ9.2VB9C63HoxzjCpCmbhga9A"],
// })
// map.setTerrain({ source: 'dem', exaggeration: 1})
</pre>
</mapFrameEx>



::: warning Note
VJMap does not provide web map tile data. For offline deployment of web map services, please download web map offline tile data yourself or use third-party tools.
:::


## Web Map and CAD Map Overlay (Web Map as Base)

This scenario uses the web map as the base (web map as coordinate system), calling VJMap CAD map's `WMS` service to adapt to the web map for overlay display.

If the CAD map has a geographic coordinate system (e.g. CGCS2000), it can be overlaid automatically.

If the CAD map has no coordinate system, you must specify three or more common points for calibration to compute the four parameters (xy translation, rotation, scale) for overlay.

See the [Coordinate Transformation](/en/guide/coordtransform.html) document for details.


This scenario suits cases where most business data is web map data and the CAD map is only overlaid for reference.

<mapFrameEx>
<pre>
// --Tianditu and CAD overlay [Tianditu as base]--Tianditu and CAD overlay, Tianditu as coordinate system
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// Create lnglat projection coordinate system based on map bounds
let prj = new vjmap.LnglatProjection();
// Map object
let map = new vjmap.Map({
    container: 'map', // DIV container ID
    style: {
        version: svc.styleVersion(),
        sources: {
            tdt1: {
                type: 'raster',
                tiles: ["https://t3.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk=7baeffb96bf61861b302d0f963cfda66"],
                // Use imagery with this URL
                // tiles: ["https://t3.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk=7baeffb96bf61861b302d0f963cfda66"]
            },
            tdt2: {
                type: 'raster',
                tiles: ["https://t3.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk=7baeffb96bf61861b302d0f963cfda66"],
            }
        },
        layers: [{
            id: 'tdt1',
            type: 'raster',
            source: 'tdt1',
        },{
            id: 'tdt2',
            type: 'raster',
            source: 'tdt2',
        }]
    },
    center: prj.toLngLat([117.21242940465396, 39.196783504641644]),
    zoom: 15,
    pitch: 0,
    renderWorldCopies: false // Do not display multi-screen map
});
// Associate service object and projection object
map.attach(svc, prj);
// Fit map to full extent based on map bounds
//map.fitMapBounds();
await map.onLoad();
// Get map metadata first to get layer style
let cadMapId = "sys_cad2000"
let style = await svc.createStyle({
    backcolor: 0xFFFFFF // Light theme
}, cadMapId)
let wmsurl = svc.wmsTileUrl({
    mapid: cadMapId,
    version:"v1",
    layers: style.stylename,
    srs: "EPSG:3857", // Base is Tianditu coordinate system
    crs: "EPSG:4548", // CAD map is CGCS2000, get via first two digits vjmap.transform.getEpsgParam(vjmap.transform.EpsgCrsTypes.CGCS2000, 39).epsg
    // fourParameter: "-39000000,0,1,0"// This map has no zone prefix, need zone offset, use four parameters to adjust position
})
map.addSource('wms-test-source', {
    'type': 'raster',
    'tiles': [
        wmsurl
    ],
    'tileSize': 256
});
map.addLayer({
        'id': 'wms-test-layer',
        'type': 'raster',
        'source': 'wms-test-source',
        'paint': { "raster-opacity": 1 }
    }
);
map.addControl(new vjmap.MousePositionControl({showZoom: true}));
</pre>
</mapFrameEx>


## CAD Map and Web Map Overlay (CAD Map as Base)

This scenario uses the CAD map as the base (CAD map as coordinate system), calling VJMap's web map `WMS` service to adapt to the CAD map for overlay display.

If the CAD map has a geographic coordinate system (e.g. CGCS2000), it can be overlaid automatically.

If the CAD map has no coordinate system, you must specify three or more common points for calibration to compute the four parameters (xy translation, rotation, scale) for overlay.

See the [Coordinate Transformation](/en/guide/coordtransform.html) document for details.


This scenario suits cases where most business data is CAD data and the web map is only overlaid for reference.


<mapFrameEx>
<pre>
// --CAD map and web map overlay--CAD and web map overlay, CAD as coordinate system
// Assume CAD full extent corresponds to zoom level 8, so web map still shows when zoomed out
let initZoom = 8;
let style = {
    backcolor: 0, // When div has dark background, pass dark background style here
    clipbounds: Math.pow(2, initZoom) // Value only (no bounds) means scale previous bounds by this factor
}
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
let res = await svc.openMap({
    mapid: "sys_cad2000",
    mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry render mode
    style:  style
})
if (res.error) {
    consoloe.error(res.error)
}
let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
let prj = new vjmap.GeoProjection(mapExtent);
let center = mapExtent.center();
let map = new vjmap.Map({
    container: 'map', // container ID
    style: svc.rasterStyle(),
    center: prj.toLngLat(center),
    zoom: 10,
    renderWorldCopies: false
});
map.attach(svc, prj);
await map.onLoad();
map.addControl(new vjmap.NavigationControl());
map.addControl(new vjmap.MousePositionControl({showZoom: true}));
// If x is 8 digits, get via first two digits e.g. vjmap.transform.getEpsgParam(vjmap.transform.EpsgCrsTypes.CGCS2000, 39).epsg
// If x is 6 digits, use this tool https://vjmap.com/demo/#/demo/map/web/03webzgetepsg, move map to province/city of CAD, click to get center lnglat, compute EPSG, find EPSG close to CAD
let epsg = "EPSG:4509" // CAD map epsg
// Add Amap base
const addGaodeMap = async (isRoadway) => {
    const tileUrl = svc.webMapUrl({
        tileCrs: "gcj02",
        tileUrl:  isRoadway ? [
                "https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
            ] :
            /* For imagery */
            [
                "https://webst0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=6&x={x}&y={y}&z={z}",
                "https://webst0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
            ],
        tileSize: 256,
        tileRetina: 1,
        tileMaxZoom: 18,
        tileShards: "1,2,3,4",
        tileToken: "",
        tileFlipY: false,
        mapbounds: res.bounds,
        srs: epsg
    })
    map.addSource('web-gaode-source', {
        'type': 'raster',
        'tiles': [
            tileUrl
        ],
        'tileSize': 256
    });
    map.addLayer({
            'id': 'web-gaode-layer',
            'type': 'raster',
            'source': 'web-gaode-source',
            'paint': { "raster-opacity": 1 }
        }
    );
    let layers = map.getStyle().layers
    // Move this layer to the bottom of all layers
    map.moveLayer('web-gaode-layer', layers[0].id)
    // CAD to web coordinate conversion example
    let webCo = await cad2webCoordinate(center, false); // CAD to Amap
    let cadCo = await web2cadCoordinate(webCo, false); // Amap to CAD
    console.log(center, webCo, cadCo)
}
// Add Tianditu base
const addTiandituMap = async (isRoadway) => {
    const tileUrl = svc.webMapUrl({
        tileCrs: "wgs84",
        tileUrl: [
            isRoadway ? "https://t{s}.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk={t}" :
                /* For imagery */"https://t{s}.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk={t}",
            "https://t{s}.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk={t}"
        ],
        tileSize: 256,
        tileRetina: 1,
        tileMaxZoom: 18,
        tileShards: "1,2,3,4,5,6",
        tileToken: [
            "6d53378dc5f7dbef8d84ffdd2b54139b", // One token may fail due to rate limit, add more, will try next on failure
            "69eb2fa0de3b2a668f1ef603a3f8bc73"
        ],
        tileFlipY: false,
        mapbounds: res.bounds,
        srs: epsg
    })
    map.addSource('web-tdt-source', {
        'type': 'raster',
        'tiles': [
            tileUrl
        ],
        'tileSize': 256
    });
    map.addLayer({
            'id': 'web-tdt-layer',
            'type': 'raster',
            'source': 'web-tdt-source',
            'paint': { "raster-opacity": 1 }
        }
    );
    let layers = map.getStyle().layers
    // Move this layer to the bottom of all layers
    map.moveLayer('web-tdt-layer', layers[0].id)
    // CAD to Tianditu coordinate conversion example
    let webCo = await cad2webCoordinate(center, true); // CAD to Tianditu
    let cadCo = await web2cadCoordinate(webCo, true); // Tianditu to CAD
    console.log(center, webCo, cadCo)
}
const removeMapLayer = ()=> {
    // Remove source and all layers under it
    map.removeSourceEx(['web-gaode-source', 'web-tdt-source'])
}
// CAD to web coordinate, isWgs84: true for WGS84 4326 (e.g. Tianditu); false for GCJ02 Mars (e.g. Amap)
const cad2webCoordinate = async (pt, isWgs84) => {
    // Convert to WGS84 4326 via coordinate transform
    let res = await svc.cmdTransform(epsg,"EPSG:4326",pt); // Or use proj4 on frontend if you don't want to call service
    // If Mars coord, also convert from 4326 to Mars
    let webPt = res[0];// First result
    if (isWgs84 === false) {
        webPt = vjmap.transform.convert(webPt, vjmap.transform.CRSTypes.EPSG4326, vjmap.transform.CRSTypes.AMap)
    }
    return webPt;
}
// Web to CAD coordinate, isWgs84: true for WGS84 4326 (e.g. Tianditu); false for GCJ02 Mars (e.g. Amap)
const web2cadCoordinate = async (pt, isWgs84) => {
    // Inverse of above: if Mars, convert Mars to 4326, then 4326 to CAD via coordinate transform
    if (isWgs84 === false) {
        pt = vjmap.transform.convert(pt, vjmap.transform.CRSTypes.AMap, vjmap.transform.CRSTypes.EPSG4326);
    }
    // Convert CAD EPSG to WGS84 4326 via coordinate transform
    let res = await svc.cmdTransform("EPSG:4326",epsg,vjmap.geoPoint(pt)); // Or use proj4 on frontend
    let cadPt = res[0];// First result
    return cadPt
}
map.on("zoomend", async ()=> {
    let center = map.fromLngLat(map.getCenter());// Get CAD map geographic center
    let gcj02Web = await cad2webCoordinate(center, false);// To Amap
    let wgs84Web = await cad2webCoordinate(center, true);// To Tianditu
    let content = `Current map center: CAD:${center.x.toFixed(4)},${center.y.toFixed(4)}; Amap:${gcj02Web[0].toFixed(4)},${gcj02Web[1].toFixed(4)}; Tianditu:${wgs84Web[0].toFixed(4)},${wgs84Web[1].toFixed(4)}`;
    console.log({ content, key: "info", duration: 3});
})
addGaodeMap(true);
</pre>
</mapFrameEx>


::: tip Note
For more on web map overlay display, see the [Web Map](/en/guide/webmap.html) document.
:::

