在 Cesium 中选择特定区域并渲染保存为图片,可以通过 绘制矩形选区 + 相机视角调整 + 截图保存 实现。以下是完整方案:
步骤 1:添加矩形绘制工具
使用 Cesium.ScreenSpaceEventHandler
监听鼠标事件,绘制选区并获取地理范围。
javascript
Copy Code
let` handler = `new` `Cesium`.`ScreenSpaceEventHandler`(viewer.`scene`.`canvas`);
`let` startPosition = `null`;
`let` rectangle = `null`;
`
// 监听鼠标按下事件
handler.setInputAction((event) => {
startPosition = event.position;
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 监听鼠标移动事件(绘制临时矩形)
handler.setInputAction((event) => {
if (!startPosition) return;
const currentPosition = event.endPosition;
// 清除之前的矩形
if (rectangle) {
viewer.entities.remove(rectangle);
}
// 计算矩形范围(屏幕坐标转地理坐标)
const cartesianStart = viewer.camera.pickEllipsoid(startPosition);
const cartesianEnd = viewer.camera.pickEllipsoid(currentPosition);
const rect = Cesium.Rectangle.fromCartesianArray([cartesianStart, cartesianEnd]);
// 绘制临时矩形
rectangle = viewer.entities.add({
rectangle: {
coordinates: rect,
material: Cesium.Color.RED.withAlpha(0.3),
outline: true,
outlineColor: Cesium.Color.RED
}
});
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 监听鼠标释放事件(确定选区)
handler.setInputAction(async (event) => {
const endPosition = event.position;
const rectCoordinates = rectangle.rectangle.coordinates.getValue();
// 保存选区范围
const selectedRectangle = rectCoordinates;
// 删除临时矩形
viewer.entities.remove(rectangle);
rectangle = null;
// 调整视角并截图(步骤2)
await captureAndSave(selectedRectangle);
}, Cesium.ScreenSpaceEventType.LEFT_UP);
步骤 2:调整相机视角到选区
将相机视角聚焦到选定的矩形区域。
javascript
Copy Code
async` `function` `captureAndSave`(`rectangle`) {
`// 调整相机视角到矩形区域`
viewer.`camera`.`flyTo`({
`destination`: rectangle,
`complete`: `() =>` {
`// 等待渲染完成`
`setTimeout`(`() =>` {
`// 截图保存(步骤3)`
`saveAsImage`();
}, `1000`); `// 延迟确保渲染完成`
}
});
}
`
步骤 3:截图保存为图片
使用 canvas.toDataURL
将当前视图保存为 PNG 图片。
javascript
Copy Code
function` `saveAsImage`(``) {
`// 获取 Canvas 元素`
`const` canvas = viewer.`scene`.`canvas`;
`
// 转换为 Data URL
const image = canvas.toDataURL('image/png');
// 创建下载链接
const link = document.createElement('a');
link.download = 'cesium-screenshot.png';
link.href = image;
link.click();
}
完整代码整合
html
Copy Code
<!DOCTYPE html>`
`<html>`
`<head>`
`<link href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css" rel="stylesheet">`
`<script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script>`
`</head>`
`<body>`
`<div id="cesiumContainer" style="width: 100%; height: 600px;"></div>`
`<script>
const viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain()
});
<span class="hljs-keyword">let</span> handler = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> startPosition = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> rectangle = <span class="hljs-literal">null</span>;
<span class="hljs-comment">// 启动矩形绘制工具</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">enableRectangleSelection</span>(<span class="hljs-params"></span>) {
handler = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Cesium</span>.<span class="hljs-title class_">ScreenSpaceEventHandler</span>(viewer.<span class="hljs-property">scene</span>.<span class="hljs-property">canvas</span>);
handler.<span class="hljs-title function_">setInputAction</span>(<span class="hljs-function">(<span class="hljs-params">event</span>) =></span> {
startPosition = event.<span class="hljs-property">position</span>;
}, <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">ScreenSpaceEventType</span>.<span class="hljs-property">LEFT_DOWN</span>);
handler.<span class="hljs-title function_">setInputAction</span>(<span class="hljs-function">(<span class="hljs-params">event</span>) =></span> {
<span class="hljs-keyword">if</span> (!startPosition) <span class="hljs-keyword">return</span>;
<span class="hljs-keyword">const</span> currentPosition = event.<span class="hljs-property">endPosition</span>;
<span class="hljs-keyword">if</span> (rectangle) viewer.<span class="hljs-property">entities</span>.<span class="hljs-title function_">remove</span>(rectangle);
<span class="hljs-keyword">const</span> cartesianStart = viewer.<span class="hljs-property">camera</span>.<span class="hljs-title function_">pickEllipsoid</span>(startPosition);
<span class="hljs-keyword">const</span> cartesianEnd = viewer.<span class="hljs-property">camera</span>.<span class="hljs-title function_">pickEllipsoid</span>(currentPosition);
<span class="hljs-keyword">const</span> rect = <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">Rectangle</span>.<span class="hljs-title function_">fromCartesianArray</span>([cartesianStart, cartesianEnd]);
rectangle = viewer.<span class="hljs-property">entities</span>.<span class="hljs-title function_">add</span>({
<span class="hljs-attr">rectangle</span>: { <span class="hljs-attr">coordinates</span>: rect, <span class="hljs-attr">material</span>: <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">Color</span>.<span class="hljs-property">RED</span>.<span class="hljs-title function_">withAlpha</span>(<span class="hljs-number">0.3</span>) }
});
}, <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">ScreenSpaceEventType</span>.<span class="hljs-property">MOUSE_MOVE</span>);
handler.<span class="hljs-title function_">setInputAction</span>(<span class="hljs-keyword">async</span> (event) => {
<span class="hljs-keyword">const</span> rectCoordinates = rectangle.<span class="hljs-property">rectangle</span>.<span class="hljs-property">coordinates</span>.<span class="hljs-title function_">getValue</span>();
viewer.<span class="hljs-property">entities</span>.<span class="hljs-title function_">remove</span>(rectangle);
rectangle = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">await</span> <span class="hljs-title function_">captureAndSave</span>(rectCoordinates);
}, <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">ScreenSpaceEventType</span>.<span class="hljs-property">LEFT_UP</span>);
}
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">captureAndSave</span>(<span class="hljs-params">rectangle</span>) {
viewer.<span class="hljs-property">camera</span>.<span class="hljs-title function_">flyTo</span>({
<span class="hljs-attr">destination</span>: rectangle,
<span class="hljs-attr">complete</span>: <span class="hljs-function">() =></span> {
<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {
<span class="hljs-keyword">const</span> canvas = viewer.<span class="hljs-property">scene</span>.<span class="hljs-property">canvas</span>;
<span class="hljs-keyword">const</span> image = canvas.<span class="hljs-title function_">toDataURL</span>(<span class="hljs-string">'image/png'</span>);
<span class="hljs-keyword">const</span> link = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">'a'</span>);
link.<span class="hljs-property">download</span> = <span class="hljs-string">'selected-area.png'</span>;
link.<span class="hljs-property">href</span> = image;
link.<span class="hljs-title function_">click</span>();
}, <span class="hljs-number">1000</span>);
}
});
}
<span class="hljs-comment">// 初始化工具</span>
<span class="hljs-title function_">enableRectangleSelection</span>();
</script>
</body>
</html>
关键优化
-
高清截图:
javascript Copy Code // 提高分辨率(2倍)` viewer.`resolutionScale` = `2`; `
-
去除水印:
javascript Copy Code `viewer.`cesiumWidget`.`creditContainer`.`style`.`display` = `'none'`; `
-
支持文件命名:
javascript Copy Code `link.`download` = ``area-${new Date().toISOString()}.png``; `
注意事项
- 确保
Cesium.Camera.flyTo
的动画完成后截图,避免画面未渲染完成。 - 如果选区跨越大范围,可能需要调整相机的
pitch
和roll
以垂直俯视。 - 跨域图片资源可能导致
toDataURL
失效,需配置服务器 CORS。
通过此方案,您可以在 Cesium 中实现交互式选区并保存为图片。