# openlayers
# OpenLayers Introduction
OpenLayers is a free, open-source frontend map development library based on JavaScript. With it, you can easily develop WebGIS systems. OpenLayers currently supports map tiles, vector data, and many other map data formats, with comprehensive map interaction support. OpenLayers has become a mature, popular framework with many developers and a helpful community, and is widely used in GIS-related industries both domestically and internationally.
OpenLayers official site: https://openlayers.org/ (opens new window)
OpenLayers source code: https://github.com/openlayers/openlayers (opens new window)
# Loading CAD Raster Tiles in OpenLayers

// Map service object, call Vijmap service to open map and get map metadata
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// Open map
let mapId = "sys_zp";
let res = await svc.openMap({
mapid: mapId, // Map ID
mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry data rendering
style: vjmap.openMapDarkStyle() // Use dark background style when div has dark background
})
if (res.error) {
// If open fails
message.error(res.error)
}
// Get map bounds
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// Custom projection parameters
let cadProjection = new ol.proj.Projection({
// extent used to determine zoom levels
extent: mapBounds.toArray(),
units: 'm'
});
// Set resolution for each level
let resolutions= [];
for(let i = 0; i < 25; i++) {
resolutions.push(mapBounds.width() / (512 * Math.pow(2, i - 1)))
}
// Add custom CAD coordinate system
ol.proj.addProjection(cadProjection);
// Create OpenLayers map object
let map = new ol.Map({
target: 'map', // div id
view: new ol.View({
center: mapBounds.center().toArray(), // Map center
projection: cadProjection, // Custom CAD coordinate system
resolutions:resolutions, // Resolution
zoom: 2// Initial zoom level
})
});
// Add a tile layer
let layer = new ol.layer.Tile({
// Add tile data source
source: new ol.source.TileImage({
url: svc.rasterTileUrl() // Vijmap service CAD raster tile URL
})
});
// Add the tile layer to the map
map.addLayer(layer);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Loading CAD Vector Tiles in OpenLayers
// Add a vector tile layer
let layer = new ol.layer.VectorTile({
// Add tile data source
source: new ol.source.VectorTile({
projection: cadProjection,
format: new ol.format.MVT(),
url: svc.vectorTileUrl() // Vijmap service CAD vector tile URL
}),
style: createVjMapVectorStyle(ol.style.Style, ol.style.Fill, ol.style.Stroke, ol.style.Circle)
});
// Add the tile layer to the map
map.addLayer(layer);
2
3
4
5
6
7
8
9
10
11
12
13
# Selecting and Highlighting CAD Entities in OpenLayers

const highlight_ent = async co => {
vectorSource.clear();
let res = await svc.pointQueryFeature({
x: co[0],
y: co[1],
zoom: map.getView().getZoom(),
fields: ""
}, pt => {
// Coordinate conversion callback for each queried point
return mapPrj.fromMercator(pt);// Convert to CAD coordinates
})
if (res && res.result && res.result.length > 0) {
let features = [];
for (let ent of res.result) {
if (ent.geom && ent.geom.geometries) {
let clr = vjmap.entColorToHtmlColor(ent.color);
for (let g = 0; g < ent.geom.geometries.length; g++) {
features.push({
type: "Feature",
properties: {
objectid: ent.objectid + "_" + g,
color: clr,
alpha: ent.alpha / 255,
lineWidth: 1,
name: ent.name,
isline: ent.isline,
layerindex: ent.layerindex
},
geometry: ent.geom.geometries[g]
})
}
// Selection hint
let content = `feature: ${ent.objectid}; layer: ${cadLayers[ent.layerindex].name}; type: ${ent.name}`
message.info({ content, key: "info", duration: 3});
}
}
geojsonObject.features = features;
if (geojsonObject.features.length > 0) {
vectorSource.addFeatures( new ol.format.GeoJSON().readFeatures(geojsonObject, {dataProjection: cadProjection}))
}
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# Uploading and Opening CAD DWG in OpenLayers

// Map service object, call Vijmap service to open map and get map metadata
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// Upload dwg file
const uploadDwgFile = async file => {
message.info("Uploading drawing, please wait", 2);
let res = await svc.uploadMap(file); // Upload map
// Enter map id
let mapid = prompt("Please enter map name ID", res.mapid);
res.mapid = mapid;
res.mapopenway = vjmap.MapOpenWay.GeomRender; // Geometry render, use vjmap.MapOpenWay.Memory for memory render
res.isVector = false; // Use raster tiles
res.style = vjmap.openMapDarkStyle(); // Dark style, use openMapDarkStyle for light
message.info("Opening drawing, please wait. First open may take tens of seconds to several minutes depending on size", 5);
let data = await svc.openMap(res); // Open map
if (data.error) {
message.error(data.error)
return;
}
openMap(data);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Switching CAD Layers in OpenLayers

// Switch layer
const switchLayer = async layers => {
let res = await svc.cmdSwitchLayers(layers); // Call Vijmap service to switch layers, returns layer id {layerid: "xxxx"}
let source = layer.getSource();
// Reset new Vijmap CAD raster tile URL
source.setUrl(svc.rasterTileUrl());
// Refresh
source.refresh();
}
2
3
4
5
6
7
8
9
# Switching CAD Maps in OpenLayers

const switchToMapId = async (mapId)=> {
let res = await svc.openMap({
mapid: mapId, // Map ID
mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry data rendering
style: vjmap.openMapDarkStyle() // Use dark background style when div has dark background
})
if (res.error) {
// If open fails
message.error(res.error)
return;
}
// Get map bounds
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// Custom projection parameters
let cadProjection = new ol.proj.Projection({
// extent used to determine zoom levels
extent: mapBounds.toArray(),
units: 'm'
});
// Set resolution for each level
let resolutions= [];
for(let i = 0; i < 25; i++) {
resolutions.push(mapBounds.width() / (512 * Math.pow(2, i - 1)))
}
// Add custom CAD coordinate system
ol.proj.addProjection(cadProjection);
// Recreate OpenLayers map object
map = new ol.Map({
target: createNewMapDivId(), // div id
view: new ol.View({
center: mapBounds.center().toArray(), // Map center
projection: cadProjection, // Custom CAD coordinate system
resolutions:resolutions, // Resolution
zoom: 2 // Initial zoom level
})
});
// Add a tile layer
let layer = new ol.layer.Tile({
// Add tile data source
source: new ol.source.TileImage({
url: svc.rasterTileUrl() // Vijmap CAD raster tile URL
})
});
// Add the tile layer to the map
map.addLayer(layer);
map.on('click', (e) => message.info({content: `Clicked coordinate: ${JSON.stringify(e.coordinate)}`, key: "info", duration: 3}));
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Dark/Light Theme Switching in OpenLayers

let curIsDarkTheme = true;
const switchToDarkTheme = async () => {
if (curIsDarkTheme) return;
curIsDarkTheme = true;
document.body.style.background = "#022B4F"; // Change background to dark
await updateStyle(curIsDarkTheme)
}
const switchToLightTheme = async () => {
if (!curIsDarkTheme) return;
curIsDarkTheme = false;
document.body.style.backgroundImage = "linear-gradient(rgba(255, 255, 255, 1), rgba(233,255,255, 1), rgba(233,255,255, 1))"
await updateStyle(curIsDarkTheme)
}
const updateStyle = async (isDarkTheme) => {
style.backcolor = isDarkTheme ? 0 : 0xFFFFFF;// Black for dark, white for light
let res = await svc.cmdUpdateStyle(style);
let source = layer.getSource();
// Reset new Vijmap CAD raster tile URL
source.setUrl(svc.rasterTileUrl());
// Refresh
source.refresh();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Custom CAD Map Style in OpenLayers
Customize the map by modifying CAD map backend style data

// Change style
const expressionList = [] ;// Expression array
const updateStyle = async (style) => {
let res = await svc.cmdUpdateStyle({
name: "customStyle2",
backcolor: 0,
expression: expressionList.join("\n"),
...style
});
let source = layer.getSource();
// Reset new Vijmap CAD raster tile URL
source.setUrl(svc.rasterTileUrl());
// Refresh
source.refresh();
}
// For expression syntax and variables, refer to
// Server-side condition query and expression query https://vjmap.com/guide/svrStyleVar.html
// Server-side render expression syntax https://vjmap.com/guide/expr.html
// Modify color: red color.r, green color.g, blue color.b, alpha color.a. If zoom is provided, applies to that level and above
const modifyColor = (color, zoom) => {
let result = "";
let z = Number.isInteger(zoom) ? `[${zoom + 1}]` : '';
if ("r" in color) result += `gOutColorRed${z}:=${color.r};`;
if ("g" in color) result += `gOutColorGreen${z}:=${color.g};`;
if ("b" in color) result += `gOutColorBlue${z}:=${color.b};`;
if ("a" in color) result += `gOutColorAlpha${z}:=${color.a};`;
return result;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# CAD Map Composition in OpenLayers
Combine multiple CAD maps with layer visibility, clipping, rotation, and scaling into a new CAD map

// Compose new map: process sys_world, then combine with sys_hello to generate new map file name
let rsp = await svc.composeNewMap([
{
mapid: "sys_world", // Map id
// Set parameters below as needed for layer, extent, coordinate transform
layers: ["latlon labels","COUNTRY"], // Layer names to display
//clipbounds: [10201.981489534268, 9040.030491346213, 26501.267379, 4445.465999], // Extent to display
//fourParameter: [0,0,1,0] // Four-parameter transform for map
},
{
mapid: "sys_hello"
}
])
if (!rsp.status) {
message.error(rsp.error)
}
// Result:
/*
{
"fileid": "pec9c5f73f1d",
"mapdependencies": "sys_world||sys_hello",
"mapfrom": "sys_world&&v1&&&&0&&&&&&&&&&00A0&&10||sys_hello&&v1&&&&0&&&&&&&&&&&&2",
"status": true
}
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Querying All Text in Map and Drawing Bounds in OpenLayers

// Entity type ID and name mapping
const { entTypeIdMap } = await svc.getConstData();
const getTypeNameById = name => {
for(let id in entTypeIdMap) {
if (entTypeIdMap[id] == name) {
return id
}
}
}
const queryTextAndDrawBounds = async () => {
let queryTextEntTypeId = getTypeNameById("AcDbText"); // Single-line text
let queryMTextEntTypeId = getTypeNameById("AcDbMText"); // Multi-line text
let queryAttDefEntTypeId = getTypeNameById("AcDbAttributeDefinition"); // Attribute definition text
let queryAttEntTypeId = getTypeNameById("AcDbAttribute"); // Attribute text
let query = await svc.conditionQueryFeature({
condition: `name='${queryTextEntTypeId}' or name='${queryMTextEntTypeId}' or name='${queryAttDefEntTypeId}' or name='${queryAttEntTypeId}'`, // Only write SQL WHERE clause, see "Server-side condition query and expression query" for fields
fields: "",
limit: 100000 // Large value to fetch all. Default 100 if not provided
}, pt => {
// Coordinate conversion callback for each queried point
return mapPrj.fromMercator(pt);// Convert to CAD coordinates
})
if (query.error) {
message.error(query.error)
} else {
message.info(`Query matched count: ${query.recordCount}`)
if (query.recordCount > 0) {
let features = [];
for(var i = 0; i < query.recordCount; i++) {
let bounds = vjmap.getEnvelopBounds(query.result[i].envelop, mapPrj);
let clr = vjmap.entColorToHtmlColor(query.result[i].color); // Entity color to HTML color
features.push({
type: "Feature",
properties: {
name: "objectid:" + query.result[i].objectid,
color: clr
},
geometry: {
'type': 'Polygon',
'coordinates': [
bounds.toPointArray(),
],
}
})
}
if (!vectorSource) {
// If no highlight vector layer yet
addHighLightLayer();
}
vectorSource.clear();
let geojsonObject = {
'type': 'FeatureCollection',
'features': features
}
// Update vector source data
vectorSource.addFeatures( new ol.format.GeoJSON().readFeatures(geojsonObject, {dataProjection: cadProjection}))
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# Drawing in OpenLayers

const source = new ol.source.Vector({wrapX: false});
const vector = new ol.layer.Vector({
source: source,
});
map.addLayer(vector);
let draw; // global so we can remove it later
function addInteraction(value) {
map.removeInteraction(draw);
if (value !== 'None') {
draw = new ol.interaction.Draw({
source: source,
type: value,
});
map.addInteraction(draw);
}
}
addInteraction('Point');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# CAD Map Overlaid on Web Map in OpenLayers [CAD as Base]

// Add Amap base
let gdlayer;
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:4527",// Get via vjmap.transform.getEpsgParam(vjmap.transform.EpsgCrsTypes.CGCS2000, 39).epsg
// sys_cad2000 has 6 digits without zone. Need zone offset before transform https://blog.csdn.net/thinkpang/article/details/124172626
fourParameterBefore: "39000000,0,1,0"
})
// Add tile layer
gdlayer = new ol.layer.Tile({
// Add tile data source
source: new ol.source.TileImage({
url: tileUrl
})
});
gdlayer.setZIndex(-1);
// Add tile layer to map
map.addLayer(gdlayer);
// CAD and web coordinate conversion example
let webCo = await cad2webCoordinate(center, false); // CAD to web
let cadCo = await web2cadCoordinate(webCo, false); // Web to CAD
console.log(center, webCo, cadCo)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Auto Overlay CAD on Web Map in OpenLayers [Web Map as Base]

let cadEpsg = "EPSG:4544";// CAD map EPSG code
// Add CAD WMS layer
let wmsUrl = svc.wmsTileUrl({
mapid: mapId, // Map id
layers: layer, // Layer name
bbox: '', // bbox not needed here
srs: "EPSG:3857", //
crs: cadEpsg
})
function getQueryStringArgs(url) {
let theRequest = {};
let idx = url.indexOf("?");
if (idx != -1) {
let str = url.substr(idx + 1);
let strs = str.split("&");
for (let i = 0; i < strs.length; i++) {
let items = strs[i].split("=");
theRequest[items[0]] = items[1];
}
}
return theRequest;
}
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// CAD to web WGS84 coordinate
const cadToWebCoordinate = async point => {
let co = await svc.cmdTransform(cadEpsg, "EPSG:4326", point);
return co[0]
}
// CAD to WGS84 lnglat
let boundsMin = await cadToWebCoordinate(mapBounds.min);
let boundsMax = await cadToWebCoordinate(mapBounds.max);
// WGS84 lnglat to Mercator
boundsMin = vjmap.Projection.lngLat2Mercator(boundsMin);
boundsMax = vjmap.Projection.lngLat2Mercator(boundsMax);
// Add WMS layer in OpenLayers
map.addLayer(new ol.layer.Tile({
// Extent
extent: [boundsMin[0], boundsMin[1], boundsMax[0], boundsMax[1]],
source: new ol.source.TileWMS({
url: wmsUrl.substr(0, wmsUrl.indexOf("?")),
params: {...getQueryStringArgs(wmsUrl),'TILED': true}
}),
}))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Overlaying CAD on Web Map by Common Points in OpenLayers [Web Map as Base]

// Points on CAD
let cadPoints = [
vjmap.geoPoint([587464448.8435847, 3104003685.208651,]),
vjmap.geoPoint([587761927.7224838, 3104005967.655292]),
vjmap.geoPoint([587463688.0280377, 3103796743.3798513]),
vjmap.geoPoint([587760406.0913897, 3103793700.1176634])
];
// Corresponding points picked on web map (WGS84)
let webPoints = [
vjmap.geoPoint([116.48476281710168, 39.96200739703454]),
vjmap.geoPoint([116.48746772021137, 39.96022062215167]),
vjmap.geoPoint([116.48585059441585, 39.9588451134361]),
vjmap.geoPoint([116.48317418949145, 39.960515760972356])
]
// Compute four-parameter from point pairs
let epsg3857Points = webPoints.map(w => vjmap.geoPoint(vjmap.Projection.lngLat2Mercator(w)));
let param = vjmap.coordTransfromGetFourParamter(epsg3857Points, cadPoints , false); // Consider rotation
let fourparam = [param.dx, param.dy, param.scale, param.rotate]
// WMS layer URL
const getCadWmsUrl = (transparent) => {
let wmsUrl = svc.wmsTileUrl({
mapid: mapId, // Map id
layers: layer, // Layer name
bbox: '', // bbox not needed here
fourParameter: fourparam,
transparent: transparent,
backgroundColor: 'rgba(240, 255, 255)' // For non-transparent
})
return wmsUrl
}
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
let cadPrj = new vjmap.GeoProjection(mapBounds);
// CAD to 3857 coordinate
const cadToWebCoordinate = point => {
// Inverse four-parameter to get web coordinate
return vjmap.coordTransfromByInvFourParamter(vjmap.geoPoint(point), param)
}
// 3857 to CAD coordinate
const webToCadCoordinate = point => {
return vjmap.coordTransfromByFourParamter(vjmap.geoPoint(point), param)
}
let wmsLayer;
const addWmsLayer = async (transparent)=> {
removeWmsLayer();
let wmsUrl = getCadWmsUrl(transparent);
wmsLayer = new ol.layer.Tile({
// Extent
extent: bounds.toArray(),
source: new ol.source.TileWMS({
url: wmsUrl.substr(0, wmsUrl.indexOf("?")),
params: {...getQueryStringArgs(wmsUrl),'TILED': true}
}),
});
// Add WMS layer to map
map.addLayer(wmsLayer);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# Finally
Click https://vjmap.com/demo/#/demo/map/openlayers/01olraster (opens new window) to try the above features online
For OpenLayers CAD loading development, see https://vjmap.com/demo/#/demo/map/openlayers/01olraster (opens new window)
For Leaflet CAD loading development, see https://vjmap.com/demo/#/demo/map/leaflet/01leafletraster (opens new window)
For Maptalks CAD loading development, see https://vjmap.com/demo/#/demo/map/maptalks/01maptalksraster (opens new window)
For Vue3 OpenLayers development, see https://github.com/MelihAltintas/vue3-openlayers
For Vue2 OpenLayers development, see https://github.com/ghettovoice/vuelayers
← Deck.GL Layer leaflet →