'R - Plots without Shiny - Create with JavaScript and produce screenshot

I have a Shiny application that generates one image after clicking an action button, and saves the screenshot of that image after pressing on another action button. The code is working, but I now need to do the same in a loop for 500 cases, in R but without Shiny, automatically, without clicking between plots, saving the screenshots in a folder. (I don't need to see the plots being generated but, for debugging purposes, it might help initially to see them.)

Currently the image is generated with a commercial plotting library, called by the nice.js files. The js files and the library are in the ./www folder.

I cannot put a proper reproducible example because of the commercial library.

Based on Stéphane's answer, I modified the question.

The code now reads ...

library(htmltools)

dep <- htmlDependency(
  name      = "html2canvas",
  version   = "1.4.1",
  src       = list(paste0(getwd(),"/www")),
  script    = "html2canvas.js",
  all_files = FALSE
)

myscript <- HTML('
function takeshot(i) {
  var captureElement = document.getElementById("myframe");
  html2canvas(captureElement)
    .then(function (canvas) {
      canvas.style.display = "none";
      document.body.appendChild(canvas);
      return canvas;
    })
    .then(function (canvas) {
      var image = canvas
        .toDataURL("image/png")
        .replace("image/png", "octet-stream");
      var a = document.createElement("a");
      a.setAttribute("download", "./www/my-image-" + i + ".png");
      a.setAttribute("href", image);
      a.click();
      canvas.remove();
    });
}
')

for(i in 1:500){
  print(
      browsable(
      tagList(
        dep,
        tags$div(
          #xxxxx plot goes here xxxxx
            tags$script(src='commercial library goes here.js'),
            id = 'myframe',                                           
            htmltools::includeScript(paste0(getwd(),'/www/nice_',i,'.js')),
        ),
        # tags$button( 'Take screenshot', onclick = 'takeshot();' ),
        # tags$h1('Screenshot:'),
        
        tags$div(id = 'output'),
        tags$script(myscript)  # tags$script('takeshot(i);'), # <======= calling takeshot(i) here?
      ) # closes tagList
     ) # closes browsable
    ) # closes print
  
  Sys.sleep(2)
}

The plotting part of the code works well and, if one has a single plot, will download the image after one clicks the "Take screenshot" button.

However, I have to do this for 500 files. Is there a way of downloading the screenshots automatically, without clicking? (Perhaps there must be some delay between the generation of the image and the screenshot.)

I tried to modify the 'takeshot' function to save the files as my-image-1.png, my-image-2.png, ..., my-image-500.png, but it doesn't download anything.

Thanks



Solution 1:[1]

You can do something like this:

library(htmltools)

# html2canvas: https://html2canvas.hertzen.com/

dep <- htmlDependency(
  name = "html2canvas",
  version = "1.4.1",
  src = "path/to/html2canvas",
  script = "html2canvas.js",
  all_files = FALSE
)

myscript <- HTML('
function takeshot() {
  var div = document.getElementById("myframe");
  html2canvas(div).then(function (canvas) {
    document.getElementById("output").appendChild(canvas);
  });
}
')

app <- tagList(
  dep,
  tags$div(
    id = "myframe",
    #xxxxx plot goes here xxxxx
  ),
  tags$button(
    "Take screenshot",
    onclick = "takeshot();"
  ),
  tags$h1("Screenshot:"),
  tags$div(id = "output"),
  tags$script(myscript)
)

browsable(app)

You'll have to include the JavaScript library you use as dependency as well, and a script which generates your plot.


EDIT

Sorry, rather use this function for the automatic download:

function takeshot() {
  var captureElement = document.getElementById("myframe");
  html2canvas(captureElement)
    .then(function (canvas) {
      canvas.style.display = "none";
      document.body.appendChild(canvas);
      return canvas;
    })
    .then(function (canvas) {
      var image = canvas
        .toDataURL("image/png")
        .replace("image/png", "image/octet-stream");
      var a = document.createElement("a");
      a.setAttribute("download", "my-image.png");
      a.setAttribute("href", image);
      a.click();
      canvas.remove();
    });
}

Solution 2:[2]

Based on my tests this doesn't seem to function without the "click". Any way to automate it, seems this has not be resolved across multiple forums.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Trading ShortAlgo