文章目录
前言
三维场景开发过程中,时常会出现需要保存当前场景的内容,去做一些分析或者场景展示。如果使用计算机自带的截图功能,只能将当前的页面截取到计算机本地,不能直接提供给程序去使用。
ArcGIS For JavaScript 的SceneView对象中提供了一个takeScreenshot函数,它可以创建当前视图的屏幕截图。屏幕截图仅包括在画布上渲染的元素 (所有地理元素),但不包括覆盖的 DOM 元素 (UI、弹出窗口等)。默认情况下,会创建整个视图的屏幕截图。不同的选项允许创建不同类型的屏幕截图,包括以不同的纵横比、不同的分辨率进行屏幕截图和创建缩略图。相关参数可以参考官网。
一、takeScreenshot参数
- format:默认值为png,生成的编码数据 url 的格式。可能值:“jpg”|“png”。
- quality:默认值为98,格式为 jpg 时编码图像的质量 (0 - 100)。
- width:屏幕截图的宽度 (默认为区域宽度)。如果未指定,高度将根据屏幕截图区域的纵横比自动得出。
- height:屏幕截图的高度 (默认为区域高度)。如果未指定,宽度将根据屏幕截图区域的纵横比自动得出。
- area:指定是否截取视图特定区域的屏幕截图。区域坐标相对于内边距视图的原点 (请参阅 padding),并将裁剪为视图大小。默认为整个视图 (不包括内边距)。
- ignorePadding:指示是否应忽略视图内边距。将此属性设置为 true 以允许在屏幕截图中包含内边距区域。
二、示例
1、以当前视图相同的分辨率进行截图
view.takeScreenshot().then(function(screenshot) {
let imageElement = document.getElementById("screenshotImage");
imageElement.src = screenshot.dataUrl;
});
2、从当前视图创建一个方形缩略图
let options = {
width: 200,
height: 200
};
view.takeScreenshot(options).then(function(screenshot) {
let imageElement = document.getElementById("screenshotImage");
imageElement.src = screenshot.dataUrl;
});
3、取一个高分辨率的方形截图
let options = {
width: 2048,
height: 2048
};
view.takeScreenshot(options).then(function(screenshot) {
let imageElement = document.getElementById("screenshotImage");
imageElement.src = screenshot.dataUrl;
});
3、在视图中心截取一个小区域的屏幕截图
// 计算视图的大小,不包括padding的部分
let padding = view.padding;
let innerWidth = view.width - padding.left - padding.right;
let innerHeight = view.height - padding.top - padding.bottom;
// 期望的区域大小
let width = 200;
let height = 200;
let options = {
area: {
x: (innerWidth - width) / 2,
y: (innerHeight - height) / 2,
width: width,
height: height
}
};
view.takeScreenshot(options).then(function(screenshot) {
let imageElement = document.getElementById("screenshotImage");
imageElement.src = screenshot.dataUrl;
});
三、完成代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.30/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.30/"></script>
<style>
html,
body,
#viewDiv {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.screenshotDiv {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
text-align: center;
background-color: rgba(255, 255, 255, 0.8);
}
.screenshotDiv img {
border: 10px solid white;
box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.5);
}
.screenshotDiv>* {
margin: 0.5em;
}
.actionButton {
padding: 0.4em;
color: black;
border: 1px solid #5c5e5e;
text-align: center;
background-color: #f1efef;
cursor: pointer;
width: 100px;
border-radius: 3px;
font-size: 16px;
}
.actionButton:hover,
.actionButton:focus {
background: #0079c1;
color: white;
}
.closeBtn {
display: inherit;
margin: auto;
}
.title {
position: absolute;
top: 20px;
width: 600px;
left: calc(50% - 300px);
background: #ffffff99;
padding: 5px;
border-radius: 3px;
}
.hide{
display: none;
}
</style>
<script>
require([
'esri/geometry/Point',
"esri/geometry/SpatialReference",
"esri/geometry/Mesh",
"esri/views/SceneView",
"esri/Map",
"esri/Graphic",
"esri/symbols/FillSymbol3DLayer",
"esri/symbols/MeshSymbol3D",
"esri/geometry/support/MeshMaterial",
"esri/geometry/support/MeshLocalVertexSpace",
"esri/layers/IntegratedMeshLayer"
], (Point, SpatialReference, Mesh, SceneView, Map,
Graphic, FillSymbol3DLayer, MeshSymbol3D, MeshMaterial, MeshLocalVertexSpace, IntegratedMeshLayer) => {
let layer = new IntegratedMeshLayer({
url: "https://tiles.arcgis.com/tiles/cFEFS0EWrhfDeVw9/arcgis/rest/services/Utrecht_Buildings_2021/SceneServer"
})
let map = new Map({
layers: [layer],
basemap: 'satellite'
})
let center = [116.4074, 39.9042, 300];
let view = new SceneView({
container: 'viewDiv',
map,
})
view.when(function () {
view.extent = layer.fullExtent;
})
const screenshotBtn = document.getElementById("screenshotBtn");
// const maskDiv = document.getElementById("maskDiv");
let screenshotDiv = document.getElementById("screenshotDiv");
const closeBtn = document.getElementById("closeBtn");
screenshotDiv.classList.add("hide");
view.ui.empty("top-right");
view.ui.add(screenshotBtn, "top-right");
let that = this;
screenshotBtn.addEventListener("click", () => {
let self = that;
let area = null;
area = {
x: view.canvas.clientLeft,
y: view.canvas.clientTop,
height: view.height,
width: view.width
}
//"jpg"|"png"
view.takeScreenshot({ area: area, format: "png" })
.then((screenshot) => {
console.log(screenshot);//screenshot.dataUrl为base64信息
// let blob = self.base64ToBlob(screenshot.dataUrl, 'png')
// self.download("test.png", blob);
downloadFile(screenshot.dataUrl, 'download', '.png');
showPreview(screenshot);//可以删除,只是为了展示截图信息
})
});
/**
* desc: base64对象转blob文件对象
* @param urlData :数据的base64对象
* @param type :类型 png,pdf,doc,mp3等;
* @returns {Blob}:Blob文件对象
*/
function base64ToBlob(urlData, type) {
let arr = urlData.split(',');
let array = arr[0].match(/:(.*?);/);
let mime = (array && array.length > 1 ? array[1] : type) || type;
// 去掉url的头,并转化为byte
let bytes = window.atob(arr[2]);
// 处理异常,将ascii码小于0的转换为大于0
let ab = new ArrayBuffer(bytes.length);
// 生成视图(直接针对内存):8位无符号整数,长度1个字节
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {
type: mime
});
}
/**
* desc: 下载导出文件
* @param blob :返回数据的blob对象或链接
* @param fileName :下载后文件名标记
* @param fileType :文件类 word(docx) excel(xlsx) ppt等
*/
function downloadExportFile(blob, fileName, fileType) {
let downloadElement = document.createElement('a');
let href = blob;
if (typeof blob == 'string') {
downloadElement.target = '_blank';
} else {
href = window.URL.createObjectURL(blob); //创建下载的链接
}
downloadElement.href = href;
downloadElement.download = fileName + '.' + fileType; //下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); //触发点击下载
document.body.removeChild(downloadElement); //下载完成移除元素
if (typeof blob != 'string') {
window.URL.revokeObjectURL(href); //释放掉blob对象
}
}
/**
* desc: base64转文件并下载
* @param base64 {String} : base64数据
* @param fileType {String} : 要导出的文件类型png,pdf,doc,mp3等
* @param fileName {String} : 文件名
*/
function downloadFile(base64, fileName, fileType) {
let typeHeader = 'data:application/' + fileType + ';base64,' // 定义base64 头部文件类型
let converedBase64 = typeHeader + base64; // 拼接最终的base64
let blob = base64ToBlob(converedBase64, fileType) // 转成blob对象
downloadExportFile(blob, fileName, fileType) // 下载文件
}
function showPreview(screenshot) {
screenshotDiv.classList.remove("hide");
// add the screenshot dataUrl as the src of an image element
const screenshotImage = document.getElementsByClassName(
"js-screenshot-image"
)[0];
screenshotImage.width = screenshot.data.width * 0.3;
screenshotImage.height = screenshot.data.height * 0.3;
screenshotImage.src = screenshot.dataUrl;
}
document.getElementById('closeBtn').addEventListener('click', function () {
screenshotDiv.classList.add("hide");
})
})
</script>
</head>
<body>
<div id="viewDiv">
<button id="screenshotBtn" class="esri-widget actionButton" aria-label="Select screenshot area"
title="Select screenshot area">
截图
</button>
<div id="screenshotDiv" class="screenshotDiv">
<img class="js-screenshot-image" />
<button id="closeBtn" class="closeBtn action-button" aria-label="Back to webscene" title="Back to webscene">
返回到web场景
</button>
</div>
</div>
</body>
</html>