Web端的地图打印功能,最简单的就是输出当前视窗范围内的地图,即将当前地图导出为一张图片并存储到客户端。不同的浏览器提供了各自的截屏功能,也可以基于浏览器的截屏功能或插件脚本实现导出地图的功能。
OpenLayers5渲染地图有两种渲染模式,即Canvas和WebGL方式可以基于地图渲染容器对象来实现导出图片功能。本示例采用默认的Canvas渲染方式加载地图,因此使用了Canvas方式的toDataURL方法导出地图,其页面功能项通过a标签的download设置导出地图的下载链接,仅支持非IE内核的浏览器。
主要实现步骤如下:
1. 引用开发库: 本示例通过本地离线 【include-openlayers-local.js】 脚本引入开发库;
2. 引用第三方库: 引入第三方库,本示例通过本地离线 FileSaver.min.js 和 jspdf.min.js 脚本引入;
3. 创建地图容器: 创建id="mapCon"的 div 作为地图容器,并设置其样式;
4. 创建地图对象: 创建地图对象,设置地图的必要参数,将 layers 属性设置为天地图地图图层;
5. 导出图片: 通过监听 map 的 postcompose 事件,获取图形绘制的 canvas 对象,从而实现导出图片的功能;
map.once('postcompose', function(event) {
var canvas = event.context.canvas
canvas.toBlob(function(blob) {
saveAs(blob, 'map.png')
})
})
map.renderSync()
6.导出 PDF:
通过监听 map 的 postcompose 事件,获取图形绘制的 canvas 对象,利用第三方库提供的导出 PDF 功能,从而实现导出 PDF 的功能。
var dims = {
a0: [1189, 841],
a1: [841, 594],
a2: [594, 420],
a3: [420, 297],
a4: [297, 210],
a5: [210, 148],
}
var format = document.getElementById('format').value
var resolution = document.getElementById('resolution').value
var dim = dims[format]
var width = Math.round((dim[0] * resolution) / 25.4)
var height = Math.round((dim[1] * resolution) / 25.4)
var size = /** @type {ol.Size} */ (map.getSize())
var extent = map.getView().calculateExtent(size)
map.once('postcompose', function(event) {
var canvas = event.context.canvas
var data = canvas.toDataURL('image/jpeg')
var pdf = new jsPDF('landscape', undefined, format)
pdf.addImage(data, 'JPEG', 0, 0, dim[0], dim[1])
pdf.save('map.pdf')
})
map.setSize([width, height])
map.getView().fit(extent, map.getSize())
map.renderSync()
关键接口
1.【地图类】ol.map
【method】once(type,listener):监听一次某类型的地图事件
参数名 | 类型 | 说明 |
type | String | Array{String} |
listener | function | 监听事件发生时触发的函数 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<!--当前示例页面样式表引用-->
<link rel="stylesheet" href="./static/demo/openlayers/example/style.css" />
<script include="jquery" src="./static/libs/include-lib-local.js"></script>
<script src="./static/libs/include-openlayers-local.js"></script>
<script src="./static/libs/cdn/filesaver/dist/FileSaver.min.js"></script>
<script src="./static/libs/cdn/filesaver/dist/jspdf.min.js"></script>
<style type="text/css">
#mapCon {
width: 100%;
height: 95%;
position: absolute;
}
.ol-mouse-position {
top: 95%;
right: 8px;
position: absolute;
}
label {
color: white;
font-size: 6px;
font-weight: 500;
font-family: cursive;
line-height: 10px;
margin: 5px 5px;
}
select {
height: 16px;
font-size: 8px;
width: 60px;
}
</style>
<script type="text/javascript">
var tdk = '4c27d6e0e8a90715b23a989d42272fd8' //天地图密钥
var mousePositionControl = null
var map = null
function init() {
//加载天地图瓦片图层数据
var TiandiMap_vect = new ol.layer.Tile({
title: '天地图矢量图层',
source: new ol.source.XYZ({
url: 'http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=' + tdk,
wrapX: false,
crossOrigin: 'Anonymous',
}),
})
var TiandiMap_vectcia = new ol.layer.Tile({
title: '天地图矢量注记图层',
source: new ol.source.XYZ({
url: 'http://t0.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=' + tdk,
crossOrigin: 'Anonymous',
}),
})
//初始化地图容器
map = new ol.Map({
target: 'mapCon', //地图容器div的ID
controls: ol.control.defaults({
attributionOptions: {
collapsible: true,
},
}),
view: new ol.View({
center: [12000000, 4000000], //地图初始中心点
maxZoom: 28, //最大瓦片显示级数
minZoom: 1, //最小瓦片显示级数
zoom: 6, //地图初始显示级数
}),
layers: [TiandiMap_vect, TiandiMap_vectcia],
})
mousePositionControl = new ol.control.MousePosition({
coordinateFormat: ol.coordinate.createStringXY(4),
// projection: 'EPSG:3857'
})
map.addControl(mousePositionControl)
}
function MapExportPng() {
map.once('postcompose', function(event) {
var canvas = event.context.canvas
canvas.toBlob(function(blob) {
saveAs(blob, 'map.png')
})
})
map.renderSync()
}
function MapExportPdf() {
var dims = {
a0: [1189, 841],
a1: [841, 594],
a2: [594, 420],
a3: [420, 297],
a4: [297, 210],
a5: [210, 148],
}
var format = document.getElementById('format').value
var resolution = document.getElementById('resolution').value
var dim = dims[format]
var width = Math.round((dim[0] * resolution) / 25.4)
var height = Math.round((dim[1] * resolution) / 25.4)
var size = /** @type {ol.Size} */ (map.getSize())
var extent = map.getView().calculateExtent(size)
map.once('postcompose', function(event) {
var canvas = event.context.canvas
var data = canvas.toDataURL('image/jpeg')
var pdf = new jsPDF('landscape', undefined, format)
pdf.addImage(data, 'JPEG', 0, 0, dim[0], dim[1])
pdf.save('map.pdf')
})
map.setSize([width, height])
map.getView().fit(extent, map.getSize())
map.renderSync()
}
</script>
</head>
<body onload="init()">
<div id="mapCon"></div>
<fieldset style="position: absolute;width: 140px;height: 45px;top: 18px;left: 50px;background-color: black;opacity: 0.5;border-radius: 10px;padding: 10px 6px;">
<label>图片大小:</label>
<select id="format">
<option value="a0">A0</option>
<option value="a1">A1</option>
<option value="a2">A2</option>
<option value="a3">A3</option>
<option value="a4" selected>A4</option>
<option value="a5">A5</option>
</select>
<br />
<label style="letter-spacing: 4px;margin-right: 0px;">分辨率:</label>
<select id="resolution">
<option value="72">72 dpi</option>
<option value="150">150 dpi</option>
<option value="300">300 dpi</option>
</select>
</fieldset>
<div id="menuContain" class="menuContain">
<div id="tool-container">
<div id="dataSourceMenuID" class="optmain" status="unactive" onclick="switchMenuStatus(this,'menu1')"><span></span><i class="menuGroup">地图输出</i><em></em></div>
</div>
</div>
<div id="menu1" class="menuStrip" style="display:none">
<ul class="menuItems">
<li onclick="MapExportPng()"><span class="item1"></span><i>图片</i></li>
<li onclick="MapExportPdf()"><span class="item1"></span><i>PDF</i></li>
</ul>
</div>
<script>
function switchMenuStatus(div, menuitemFrameID) {
var temDivs = document.getElementsByClassName('optmain')
if (temDivs.length > 0) {
for (var i = 0; i < temDivs.length; i++) {
if (temDivs[i] === div) {
var status = div.getAttribute('status')
if (status == 'unactive') {
div.setAttribute('status', 'active')
var tem_spans = div.getElementsByTagName('span')
var tem_ems = div.getElementsByTagName('em')
tem_spans[0].className = 'active'
tem_ems[0].className = 'active'
//显示菜单项
DisplayMenuItem(true, menuitemFrameID)
} else {
div.setAttribute('status', 'unactive')
var tem_spans = div.getElementsByTagName('span')
var tem_ems = div.getElementsByTagName('em')
tem_spans[0].className = ''
tem_ems[0].className = ''
//隐藏菜单项
DisplayMenuItem(false, menuitemFrameID)
}
} else {
var status = temDivs[i].getAttribute('status')
if (status == 'active') {
temDivs[i].setAttribute('status', 'unactive')
var tem_spans = temDivs[i].getElementsByTagName('span')
var tem_ems = temDivs[i].getElementsByTagName('em')
tem_spans[0].className = ''
tem_ems[0].className = ''
}
}
}
}
}
function DisplayMenuItem(isDisplay, iframeID) {
var menuItemFrame = document.getElementById(iframeID)
if (menuItemFrame != null) {
if (isDisplay) {
var temDivs = document.getElementsByClassName('menuStrip')
if (temDivs.length > 0) {
for (var i = 0; i < temDivs.length; i++) {
if (temDivs[i] != menuItemFrame) {
temDivs[i].style.display = 'none'
}
}
}
menuItemFrame.style.display = ''
} else {
menuItemFrame.style.display = 'none'
}
}
}
</script>
</body>
</html>