Browser-friendly way of drawing rectangles on top of image R Shiny

后端 未结 1 1503
[愿得一人]
[愿得一人] 2021-01-20 20:48

I have written a shiny app that allows the user to draw rectangles on top of an image (minimal reproducible example below).

The problem with my current approach is t

相关标签:
1条回答
  • 2021-01-20 20:58

    Here's a JS option based entirely on this answer.

    # JS and CSS modified from: https://stackoverflow.com/a/17409472/8099834
    css <- "
        #canvas {
            width:2000px;
            height:2000px;
            border: 10px solid transparent;
        }
        .rectangle {
            border: 5px solid #FFFF00;
            position: absolute;
        }
    "
    
    js <- 
    "function initDraw(canvas) {
        var mouse = {
            x: 0,
            y: 0,
            startX: 0,
            startY: 0
        };
        function setMousePosition(e) {
            var ev = e || window.event; //Moz || IE
            if (ev.pageX) { //Moz
                mouse.x = ev.pageX + window.pageXOffset;
                mouse.y = ev.pageY + window.pageYOffset;
            } else if (ev.clientX) { //IE
                mouse.x = ev.clientX + document.body.scrollLeft;
                mouse.y = ev.clientY + document.body.scrollTop;
            }
        };
    
        var element = null;    
        canvas.onmousemove = function (e) {
            setMousePosition(e);
            if (element !== null) {
                element.style.width = Math.abs(mouse.x - mouse.startX) + 'px';
                element.style.height = Math.abs(mouse.y - mouse.startY) + 'px';
                element.style.left = (mouse.x - mouse.startX < 0) ? mouse.x + 'px' : mouse.startX + 'px';
                element.style.top = (mouse.y - mouse.startY < 0) ? mouse.y + 'px' : mouse.startY + 'px';
            }
        }
    
        canvas.onclick = function (e) {
            if (element !== null) {
               var coord = {
                   left: element.style.left,
                   top: element.style.top,
                   width: element.style.width,
                   height: element.style.height
                };
                Shiny.onInputChange('rectCoord', coord);
                element = null;
                canvas.style.cursor = \"default\";
            } else {
                mouse.startX = mouse.x;
                mouse.startY = mouse.y;
                element = document.createElement('div');
                element.className = 'rectangle'
                element.style.left = mouse.x + 'px';
                element.style.top = mouse.y + 'px';
                canvas.appendChild(element);
                canvas.style.cursor = \"crosshair\";
            }
        }
    };
    $(document).on('shiny:sessioninitialized', function(event) {
        initDraw(document.getElementById('canvas'));
    });
    "
    
    library(shiny)
    
    ui <- fluidPage(
      tags$head(
          tags$style(css),
          tags$script(HTML(js))
      ),
      fluidRow(
          column(width = 6, 
                 # inline is necessary
                 # ...otherwise we can draw rectangles over entire fluidRow
                 uiOutput("canvas", inline = TRUE)),
          column(
              width = 6,
              verbatimTextOutput("rectCoordOutput")
              )
      )
    )
    
    server <- function(input, output, session) {
        output$canvas <- renderUI({
            tags$img(src = "https://www.r-project.org/logo/Rlogo.png")
        })
        output$rectCoordOutput <- renderPrint({
            input$rectCoord
        })
    
    }
    
    shinyApp(ui, server)
    
    0 讨论(0)
提交回复
热议问题