实现

接着上篇文章写(,这次会完整的实现截图的功能
首先要放个地图,直接参照

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><linkrel="stylesheet"href=""type="text/css"><title>Document</title><styletype="text/css">html, body{margin: 0;padding: 0;}#screenshot{border: 2px solid black;}.map{width: 100%;height: 600px;}</style><scriptsrc=""></script></head><body><divid="map"class="map"></div></body><script>const map =newol.Map({
    target:'map',
    layers:[newol.layer.Tile({
        source:newol.source.OSM()})],
    view:newol.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)constmoveEvent=(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>

我这里代码是直接在上次的代码基础上写的,看看效果

<button id="screen-button">截图</button>...
document.getElementById('screen-button').addEventListener('click',(e)=>{constmousedownEvent=(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)constmoveEvent=(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上,在鼠标松开时移除这些事件
现在我们在网页中测试能够发现,当我们截图时鼠标移动也会拖动地图移动,这样没办法很好的截图,解决这个问题有很多思路,可以在初始化地图的时候拿到拖动地图的事件进行控制,我之前在写地图色块提取的时候有用过透明遮罩的办法,自己权衡。这里采用前一种,参考:

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

在事件开始和结尾处加上相应的代码即可

functiongetMapImg(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 matrixconst matrix = transform
              .match(/^matrix\(([^(]*)\)$/)[1].split(',').map(Number)// Apply the transform to the export map contextCanvasRenderingContext2D.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)constmoveEvent=(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就是图片地址,可以直接在浏览器中打开,现在我们测试效果

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><linkrel="stylesheet"href=""type="text/css"><title>Document</title><styletype="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><scriptsrc=""></script></head><body><divid="map"class="map"></div><buttonid="screen-button">截图</button><divid="photo-window"class="hide"><imgid="photo"src=""alt="#"/></div></body><script>const map =newol.Map({
    target:'map',
    layers:[newol.layer.Tile({
        source:newol.source.OSM()})],
    view:newol.View({
      center: ol.proj.fromLonLat([37.41,8.82]),
      zoom:4})})let dataUrl
  let pan
  map.getInteractions().forEach(function(element,index,array){if(element instanceofol.interaction.DragPan) pan = element;})
  document.getElementById('screen-button').addEventListener('click',(e)=>{constmousedownEvent=(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)constmoveEvent=(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)})functiongetMapImg(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 matrixconst matrix = transform
              .match(/^matrix\(([^(]*)\)$/)[1].split(',').map(Number)// Apply the transform to the export map contextCanvasRenderingContext2D.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()}functiongenerateWindow(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>