Using HTML5/Canvas/JavaScript to take in-browser screenshots

后端 未结 5 2446
遇见更好的自我
遇见更好的自我 2020-11-21 04:23

Google\'s "Report a Bug" or "Feedback Tool" lets you select an area of your browser window to create a screenshot that is submitted with your feedback ab

5条回答
  •  南旧
    南旧 (楼主)
    2020-11-21 05:21

    PoC

    As Niklas mentioned you can use the html2canvas library to take a screenshot using JS in the browser. I will extend his answer in this point by providing an example of taking a screenshot using this library ("Proof of Concept"):

    function report() {
      let region = document.querySelector("body"); // whole screen
      html2canvas(region, {
        onrendered: function(canvas) {
          let pngUrl = canvas.toDataURL(); // png in dataURL format
          let img = document.querySelector(".screen");
          img.src = pngUrl; 
    
          // here you can allow user to set bug-region
          // and send it with 'pngUrl' to server
        },
      });
    }
    .container {
      margin-top: 10px;
      border: solid 1px black;
    }
    
    
    Screenshot tester

    In report() function in onrendered after getting image as data URI you can show it to the user and allow him to draw "bug region" by mouse and then send a screenshot and region coordinates to the server.

    In this example async/await version was made: with nice makeScreenshot() function.

    UPDATE

    Simple example which allows you to take screenshot, select region, describe bug and send POST request (here jsfiddle) (the main function is report()).

    async function report() {
        let screenshot = await makeScreenshot(); // png dataUrl
        let img = q(".screen");
        img.src = screenshot; 
        
        let c = q(".bug-container");
        c.classList.remove('hide')
            
        let box = await getBox();    
        c.classList.add('hide');
    
        send(screenshot,box); // sed post request  with bug image, region and description
        alert('To see POST requset with image go to: chrome console > network tab');
    }
    
    // ----- Helper functions
    
    let q = s => document.querySelector(s); // query selector helper
    window.report = report; // bind report be visible in fiddle html
    
    async function  makeScreenshot(selector="body") 
    {
      return new Promise((resolve, reject) => {  
        let node = document.querySelector(selector);
        
        html2canvas(node, { onrendered: (canvas) => {
            let pngUrl = canvas.toDataURL();      
            resolve(pngUrl);
        }});  
      });
    }
    
    async function getBox(box) {
      return new Promise((resolve, reject) => {
         let b = q(".bug");
         let r = q(".region");
         let scr = q(".screen");
         let send = q(".send");
         let start=0;
         let sx,sy,ex,ey=-1;
         r.style.width=0;
         r.style.height=0;
         
         let drawBox= () => {
             r.style.left   = (ex > 0 ? sx : sx+ex ) +'px'; 
             r.style.top    = (ey > 0 ? sy : sy+ey) +'px';
             r.style.width  = Math.abs(ex) +'px';
             r.style.height = Math.abs(ey) +'px'; 
         }
         
         
         
         //console.log({b,r, scr});
         b.addEventListener("click", e=>{
           if(start==0) {
             sx=e.pageX;
             sy=e.pageY;
             ex=0;
             ey=0;
             drawBox();
           }
           start=(start+1)%3;       
         });
         
         b.addEventListener("mousemove", e=>{
           //console.log(e)
           if(start==1) {
               ex=e.pageX-sx;
               ey=e.pageY-sy
               drawBox(); 
           }
         });
         
         send.addEventListener("click", e=>{
           start=0;
           let a=100/75 //zoom out img 75%       
           resolve({
              x:Math.floor(((ex > 0 ? sx : sx+ex )-scr.offsetLeft)*a),
              y:Math.floor(((ey > 0 ? sy : sy+ey )-b.offsetTop)*a),
              width:Math.floor(Math.abs(ex)*a),
              height:Math.floor(Math.abs(ex)*a),
              desc: q('.bug-desc').value
              });
              
         });
      });
    }
    
    function send(image,box) {
    
        let formData = new FormData();
        let req = new XMLHttpRequest();
        
        formData.append("box", JSON.stringify(box)); 
        formData.append("screenshot", image);     
        
        req.open("POST", '/upload/screenshot');
        req.send(formData);
    }
    .bug-container { background: rgb(255,0,0,0.1); margin-top:20px; text-align: center; }
    .send { border-radius:5px; padding:10px; background: green; cursor: pointer; }
    .region { position: absolute; background: rgba(255,0,0,0.4); }
    .example { height: 100px; background: yellow; }
    .bug { margin-top: 10px; cursor: crosshair; }
    .hide { display: none; }
    .screen { pointer-events: none }
    
    
    
    Screenshot tester
    Lorem ipsum
    Select bug region: click once - move mouse - click again
    SEND BUG

提交回复
热议问题