Javascript 在图像上绘制矩形的浏览器友好方式

Javascript 在图像上绘制矩形的浏览器友好方式,javascript,image,browser,shiny,draw,Javascript,Image,Browser,Shiny,Draw,我已经编写了一个闪亮的应用程序,允许用户在图像顶部绘制矩形(下面是一个最小的可复制示例) 我目前的方法的问题是,每次添加一个矩形时,都会创建一个新的图像,并将其写入磁盘,然后进行渲染(发送到用户的浏览器)。这需要相当长的时间,并且在Internet连接缓慢时会变得非常烦人 是否有任何方法可以直接在浏览器中显示图像顶部的矩形,而无需修改服务器端的图像?我唯一需要确保的是浏览器将绘图上的矩形坐标发送回服务器 我正在寻找的一个很好的例子(JavaScript): 我知道JavaScript可以通过小部

我已经编写了一个闪亮的应用程序,允许用户在图像顶部绘制矩形(下面是一个最小的可复制示例)

我目前的方法的问题是,每次添加一个矩形时,都会创建一个新的图像,并将其写入磁盘,然后进行渲染(发送到用户的浏览器)。这需要相当长的时间,并且在Internet连接缓慢时会变得非常烦人

是否有任何方法可以直接在浏览器中显示图像顶部的矩形,而无需修改服务器端的图像?我唯一需要确保的是浏览器将绘图上的矩形坐标发送回服务器

我正在寻找的一个很好的例子(JavaScript): 我知道JavaScript可以通过小部件嵌入到闪亮的应用程序中,如果没有人提出更简单的解决方案,我会这么做

库(闪亮)
图书馆(png)
图书馆(RCurl)
我的URL=https://raw.githubusercontent.com/Tixierae/deep_learning_NLP/master/CNN_IMDB/cnn_illustration.png'
my_img=readPNG(getURLContent(myurl))
img_height=dim(my_img)[1]
img_width=dim(my_img)[2]
服务器=功能(输入、输出){
观察({
outfile=tempfile(tmpdir='./',fileext='.png')
png(文件名=输出文件,宽度=图像宽度,高度=图像高度)
par(mar=c(0,0,0,0),xaxs='i',yaxs='i')
绘图(NA,xlim=c(0,img_宽度),ylim=c(0,img_高度))
光栅图像(我的图像,0,0,图像宽度,图像高度)
如果(!为.null(输入$image\u笔刷)){
b_in=lappy(输入$image_brush,如.numeric)
如果(!为.null(b_单位为$xmin)){
rect(b_单位为$xmin,img_高度-b_单位为$ymax,b_单位为$xmax,img_高度-b_单位为$ymin,border='green',lwd=5)
}
}
发展主任()
输出$my_image=renderImage({
名单(
src=输出文件,
contentType='image/png',
宽度=img_宽度,
高度=img_高度,
alt=“”
)
},deleteFile=TRUE)
输出$image=renderUI({
imageOutput('my_image',
高度=img_高度,
宽度=img_宽度,
单击='image\u click',
dblclick=dblclickOpts(
id='image_dblclick'
),
hover=hoverOpts(
id='image\u hover'
),
画笔=画笔选项(
id='image\u brush',resetOnNew=TRUE,delayType='debounce',delay=100000
)
)
})
})
}
ui=引导(
uiOutput('图像')
)
shinyApp(用户界面=用户界面,服务器=服务器)

这里有一个完全基于JS的JS选项

#JS和CSS修改自:https://stackoverflow.com/a/17409472/8099834

css太棒了,非常感谢!我很可能会接受你的回答,并将你的赏金奖励给你,我只是再等几个小时,以防万一其他人想要贡献。您是否知道如何通过双击矩形内部来删除矩形?(如果存在多个匹配项,则为最内侧的矩形)。这不是原始问题的一部分,所以如果你不想回答这个问题,我会理解的。事实上,我问了这个后续问题作为一个新的线索:如果你想详细说明你的答案,你可以得到奖励,很高兴这很有帮助:)我不知道如何删除矩形,但我会研究它!谢谢,我希望你能有所贡献!只是想让你知道我已经开始悬赏这个新问题,以防你想插手
# 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)