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.
// --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})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 document for details.
This scenario suits cases where most business data is web map data and the CAD map is only overlaid for reference.
// --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}));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 document for details.
This scenario suits cases where most business data is CAD data and the web map is only overlaid for reference.
// --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);Note
For more on web map overlay display, see the Web Map document.