当前位置:网站首页>openlayer中实现截图框截图的功能

openlayer中实现截图框截图的功能

2022-08-11 05:25:00 Mino.66

实现

接着上篇文章写(https://blog.csdn.net/luoluoyang23/article/details/122653363),这次会完整的实现截图的功能
首先要放个地图,直接参照https://openlayers.org/en/latest/doc/quickstart.html写就行了

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/[email protected]/en/v6.12.0/css/ol.css" type="text/css">
  <title>Document</title>
  <style type="text/css"> html, body {
       margin: 0; padding: 0; } #screenshot {
       border: 2px solid black; } .map {
       width: 100%; height: 600px; } </style>
  <script src="https://cdn.jsdelivr.net/gh/openlayers/[email protected]/en/v6.12.0/build/ol.js"></script>
</head>
<body>
  <div id="map" class="map"></div>
</body>
<script> const map = new ol.Map({
       target: 'map', layers: [ new ol.layer.Tile({
       source: new ol.source.OSM() }) ], view: new ol.View({
       center: ol.proj.fromLonLat([37.41, 8.82]), zoom: 4 }) }) window.addEventListener("mousedown", (e) => {
       const [startX, startY] = [e.clientX, e.clientY] const divDom = document.createElement("div") divDom.id = 'screenshot' divDom.width = '1px' divDom.height = '1px' divDom.style.position = "absolute" divDom.style.top = startY + "px" divDom.style.left = startX + "px" document.body.appendChild(divDom) const moveEvent = (e) => {
       const moveX = e.clientX - startX const moveY = e.clientY - startY if (moveX > 0) {
       divDom.style.width = moveX + 'px' } else {
       divDom.style.width = -moveX + 'px' divDom.style.left = e.clientX + 'px' } if (moveY > 0) {
       divDom.style.height = moveY + 'px' } else {
       divDom.style.height = -moveY + 'px' divDom.style.top = e.clientY + 'px' } } window.addEventListener("mousemove", moveEvent) window.addEventListener("mouseup", () => {
       window.removeEventListener("mousemove", moveEvent) }) }) </script>
</html>

我这里代码是直接在上次的代码基础上写的,看看效果
在这里插入图片描述
改点东西,因为我们截图事件是直接写在windows上面的,这样点地图也会触发,随便加个按钮,把事件挪过去

<button id="screen-button">截图</button>
...
document.getElementById('screen-button').addEventListener('click', (e) => {
    
    const mousedownEvent = (e) => {
    
      const [startX, startY] = [e.clientX, e.clientY]
      const divDom = document.createElement("div")
      divDom.id = 'screenshot'
      divDom.width = '1px'
      divDom.height = '1px'
      divDom.style.position = "absolute"
      divDom.style.top = startY + "px"
      divDom.style.left = startX + "px"
      document.body.appendChild(divDom)
      const moveEvent = (e) => {
    
        const moveX = e.clientX - startX
        const moveY = e.clientY - startY
        if (moveX > 0) {
    
          divDom.style.width = moveX + 'px'
        } else {
    
          divDom.style.width = -moveX + 'px'
          divDom.style.left = e.clientX + 'px'
        }
        if (moveY > 0) {
    
          divDom.style.height = moveY + 'px'
        } else {
    
          divDom.style.height = -moveY + 'px'
          divDom.style.top = e.clientY + 'px'
        }
      }
      window.addEventListener("mousemove", moveEvent)
      window.addEventListener("mouseup", () => {
    
        window.removeEventListener("mousemove", moveEvent)
        window.removeEventListener("mousedown", mousedownEvent)
      })
    }
    window.addEventListener("mousedown", mousedownEvent)
  })

这里直接移进去了,这样点击按钮后才会把截图事件绑定到window上,在鼠标松开时移除这些事件
现在我们在网页中测试能够发现,当我们截图时鼠标移动也会拖动地图移动,这样没办法很好的截图,解决这个问题有很多思路,可以在初始化地图的时候拿到拖动地图的事件进行控制,我之前在写地图色块提取的时候有用过透明遮罩的办法,自己权衡。这里采用前一种,参考:

https://blog.csdn.net/u013323965/article/details/53183532

let pan
map.getInteractions().forEach(function(element,index,array){
    
	if(element instanceof ol.interaction.DragPan) pan = element; 
})

在事件开始和结尾处加上相应的代码即可
在这里插入图片描述
在这里插入图片描述
然后就是获取图片了,在上一篇文章我已经给过相关API的链接地址,可以自己去研究,这里直接贴代码了

function getMapImg(startX, startY, mWidth, mHeight) {
    
    map.once('rendercomplete', () => {
    
      const mapCanvas = document.createElement('canvas')
      mapCanvas.width = mWidth
      mapCanvas.height = mHeight
      const mapContext = mapCanvas.getContext('2d')
      Array.prototype.forEach.call(
        document.querySelectorAll('.ol-layer canvas'),
        function (canvas) {
    
          if (canvas.width > 0) {
    
            const opacity = canvas.parentNode.style.opacity
            mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity)
            const transform = canvas.style.transform
            // Get the transform parameters from the style's transform matrix
            const matrix = transform
              .match(/^matrix\(([^(]*)\)$/)[1]
              .split(',')
              .map(Number)
            // Apply the transform to the export map context
            CanvasRenderingContext2D.prototype.setTransform.apply(
              mapContext,
              matrix
            )
            mapContext.drawImage(canvas, -startX, -startY)
          }
        }
      )
      if (navigator.msSaveBlob) {
    
        // link download attribute does not work on MS browsers
        navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png')
      } else {
    
        dataUrl = mapCanvas.toDataURL()
        console.log(dataUrl)
      }
    })
    map.renderSync()
  }

四个参数,分别是截图范围的起点xy坐标,截图框的宽高。这就是我们写截图框代码的目的。这四个参数就从上面拿就行了,这里也直接写在之前的代码中获取,为了大家方便查看,这里直接贴出整体的代码

let [canvasX, canvasY] = [startX, startY]
let canvasWidth, canvasHeight
divDom.style.top = startY + "px"
divDom.style.left = startX + "px"
document.body.appendChild(divDom)
const moveEvent = (e) => {
    
  const moveX = e.clientX - startX
  const moveY = e.clientY - startY
  if (moveX > 0) {
    
    divDom.style.width = moveX + 'px'
    canvasWidth = moveX
  } else {
    
    divDom.style.width = -moveX + 'px'
    divDom.style.left = e.clientX + 'px'
    canvasWidth = -moveX
    canvasX = e.clientX
  }
  if (moveY > 0) {
    
    divDom.style.height = moveY + 'px'
    canvasHeight = moveY
  } else {
    
    divDom.style.height = -moveY + 'px'
    divDom.style.top = e.clientY + 'px'
    canvasHeight = -moveY
    canvasY = e.clientY
  }
}

在截图结束的地方调用getMapImg()

window.addEventListener("mouseup", () => {
    
  window.removeEventListener("mousemove", moveEvent)
  window.removeEventListener("mousedown", mousedownEvent)
  pan.setActive(true)
  getMapImg(canvasX, canvasY, canvasWidth, canvasHeight)
})

在getMapImg中最后几行的dataUrl就是图片地址,可以直接在浏览器中打开,现在我们测试效果
在这里插入图片描述
在这里插入图片描述
可以看到我们成功实现了效果,接下来就是一些优化截图表现效果的代码了。具体效果可以按照自己喜欢的来,我这里走比较常规的套路,在截图结束时清除截图框,在窗口中间增加一个预览截图的效果
在这里插入图片描述
这部分写得比较随意,下面时完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/[email protected]/en/v6.12.0/css/ol.css" type="text/css">
  <title>Document</title>
  <style type="text/css"> html, body {
       margin: 0; padding: 0; } #screenshot {
       border: 3px solid black; } .map {
       width: 100%; height: 600px; } #photo-window {
       position: absolute; border: 25px solid rgba(0, 0, 0, 0.5); overflow: hidden; } .hide {
       display: none; } </style>
  <script src="https://cdn.jsdelivr.net/gh/openlayers/[email protected]/en/v6.12.0/build/ol.js"></script>
</head>
<body>
  <div id="map" class="map"></div>
  <button id="screen-button">截图</button>
  <div id="photo-window" class="hide">
    <img id="photo" src="" alt="#" />
  </div>
</body>
<script> const map = new ol.Map({
       target: 'map', layers: [ new ol.layer.Tile({
       source: new ol.source.OSM() }) ], view: new ol.View({
       center: ol.proj.fromLonLat([37.41, 8.82]), zoom: 4 }) }) let dataUrl let pan map.getInteractions().forEach(function(element,index,array){
       if(element instanceof ol.interaction.DragPan) pan = element; }) document.getElementById('screen-button').addEventListener('click', (e) => {
       const mousedownEvent = (e) => {
       pan.setActive(false) const [startX, startY] = [e.clientX, e.clientY] const divDom = document.createElement("div") divDom.id = 'screenshot' divDom.width = '1px' divDom.height = '1px' divDom.style.position = "absolute" let [canvasX, canvasY] = [startX, startY] let canvasWidth, canvasHeight divDom.style.top = startY + "px" divDom.style.left = startX + "px" document.body.appendChild(divDom) const moveEvent = (e) => {
       const moveX = e.clientX - startX const moveY = e.clientY - startY if (moveX > 0) {
       divDom.style.width = moveX + 'px' canvasWidth = moveX } else {
       divDom.style.width = -moveX + 'px' divDom.style.left = e.clientX + 'px' canvasWidth = -moveX canvasX = e.clientX } if (moveY > 0) {
       divDom.style.height = moveY + 'px' canvasHeight = moveY } else {
       divDom.style.height = -moveY + 'px' divDom.style.top = e.clientY + 'px' canvasHeight = -moveY canvasY = e.clientY } } window.addEventListener("mousemove", moveEvent) window.addEventListener("mouseup", () => {
       window.removeEventListener("mousemove", moveEvent) window.removeEventListener("mousedown", mousedownEvent) pan.setActive(true) getMapImg(canvasX, canvasY, canvasWidth, canvasHeight) document.body.removeChild(divDom) generateWindow() }) } window.addEventListener("mousedown", mousedownEvent) }) function getMapImg(startX, startY, mWidth, mHeight) {
       map.once('rendercomplete', () => {
       const mapCanvas = document.createElement('canvas') mapCanvas.width = mWidth mapCanvas.height = mHeight const mapContext = mapCanvas.getContext('2d') Array.prototype.forEach.call( document.querySelectorAll('.ol-layer canvas'), function (canvas) {
       if (canvas.width > 0) {
       const opacity = canvas.parentNode.style.opacity mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity) const transform = canvas.style.transform // Get the transform parameters from the style's transform matrix const matrix = transform .match(/^matrix\(([^(]*)\)$/)[1] .split(',') .map(Number) // Apply the transform to the export map context CanvasRenderingContext2D.prototype.setTransform.apply( mapContext, matrix ) mapContext.drawImage(canvas, -startX, -startY) } } ) if (navigator.msSaveBlob) {
       // link download attribute does not work on MS browsers navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png') } else {
       dataUrl = mapCanvas.toDataURL() generateWindow(mWidth, mHeight) } }) map.renderSync() } function generateWindow(width, height) {
       document.getElementById('photo').src = dataUrl const boxDom = document.getElementById('photo-window') boxDom.classList.remove('hide') boxDom.style.left = 'calc(50% - ' + (width / 2) + 'px)' boxDom.style.top = 'calc(50% - ' + (height / 2) + 'px)' } </script>
</html>

原网站

版权声明
本文为[Mino.66]所创,转载请带上原文链接,感谢
https://blog.csdn.net/luoluoyang23/article/details/122763696