R 在智能手机上使用,闪亮的互动绘图不会';我不懂手指的动作

R 在智能手机上使用,闪亮的互动绘图不会';我不懂手指的动作,r,shiny,hover,click,smartphone,R,Shiny,Hover,Click,Smartphone,我有一个R-shinny应用程序,它有一个实现交互操作的绘图:单击,悬停(悬停是将鼠标放在绘图上,这可以被shinny检测到)。为了给大家一个想法,我在下面发布了一个简化的闪亮应用程序,其功能对我来说是有问题的,即交互式绘图绘图。(摘自我的一个老答案) 它实际上工作正常,但是我需要人们从他们的智能手机上使用它。问题是:我们在智能手机中的手指移动被手机理解为在页面上缩放或滚动,而不是鼠标选择或鼠标在绘图上移动(悬停) 我是否可以在应用程序上实现对代码(java?CSS?)的修改,将触摸事件转换为鼠

我有一个R-shinny应用程序,它有一个实现交互操作的绘图:单击,悬停(悬停是将鼠标放在绘图上,这可以被shinny检测到)。为了给大家一个想法,我在下面发布了一个简化的闪亮应用程序,其功能对我来说是有问题的,即交互式绘图绘图。(摘自我的一个老答案)

它实际上工作正常,但是我需要人们从他们的智能手机上使用它。问题是:我们在智能手机中的手指移动被手机理解为在页面上缩放或滚动,而不是鼠标选择或鼠标在绘图上移动(悬停)

我是否可以在应用程序上实现对代码(java?CSS?)的修改,将触摸事件转换为鼠标事件,或者在智能手机上使用选项/手势来实现类似鼠标的移动

非常感谢;守则:

library(shiny)
ui <- fluidPage(
  h4("Click on plot to start drawing, click again to pause"),
  sliderInput("mywidth", "width of the pencil", min=1, max=30, step=1, value=10),
  actionButton("reset", "reset"),
  plotOutput("plot", width = "500px", height = "500px",
             hover=hoverOpts(id = "hover", delay = 100, delayType = "throttle", clip = TRUE, nullOutside = TRUE),
             click="click"))
server <- function(input, output, session) {
  vals = reactiveValues(x=NULL, y=NULL)
  draw = reactiveVal(FALSE)
  observeEvent(input$click, handlerExpr = {
    temp <- draw(); draw(!temp)
    if(!draw()) {
      vals$x <- c(vals$x, NA)
      vals$y <- c(vals$y, NA)
    }})
  observeEvent(input$reset, handlerExpr = {
    vals$x <- NULL; vals$y <- NULL
  })
  observeEvent(input$hover, {
    if (draw()) {
      vals$x <- c(vals$x, input$hover$x)
      vals$y <- c(vals$y, input$hover$y)
    }})
  output$plot= renderPlot({
    plot(x=vals$x, y=vals$y, xlim=c(0, 28), ylim=c(0, 28), ylab="y", xlab="x", type="l", lwd=input$mywidth)
  })}
shinyApp(ui, server)
库(闪亮)

ui虽然我不能完全解决这个问题,但也许一个肮脏的变通方法对你也有一些价值。或者其他人可以基于这个答案

我可以重现这样一个错误:在手机上没有捕捉到对绘图的点击。但是我注意到我可以用javascript/shinyjs添加额外的clickevents

一种方法是:

  onevent(event = "click", id = "plot", function(e){
    global$clickx = c(global$clickx, e$pageX - 88)
    global$clicky = c(global$clicky, 540 - e$pageY)
  })
它有几个缺点:

  • 图形仅用线绘制,它不会捕获在绘图上悬停的所有图形
  • 这个位置很不精确,因为你必须考虑边界和边距(非常脏,但这里有潜力)
几个小时后,我的时间有点用完了,可以肯定的是,我可以改进它,但不管怎样,它可能会让你感兴趣

此处测试:(链接可能在未来几周内更改)

可复制代码:(在智能手机上测试:Mi A2)

库(闪亮)
图书馆(shinyjs)

ui您可以使用CSS属性禁用绘图上的平移/缩放手势:

#plot {
  touch-action: none;
}
将触摸事件转换为鼠标事件有点棘手,但您可以收听触摸事件,如
touchstart
touchmove
touchend
,并在JavaScript中模拟等效的鼠标事件。有关更多信息,请参阅和

这并不完美,但我试过了。我禁用了绘图上的触摸手势,并添加了一个脚本,该脚本将
touchmove
转换为
mousemove
,并告诉服务器何时开始绘图(在
touchstart
)和何时停止绘图(在
touchend

库(闪亮)

关于plotly.js(不是R api),GitHub上有一个用于移动交互的ui。您好,非常感谢您的回答;事实上,我真的需要为一个公共演示解决这个问题。如果我理解的很好,你只是用点击代替了悬停?我没有想到这个解决方法,好主意,这是一个简化,因为绘图变得更难,更不平滑。但如果我没有其他解决方案,我会选择这个。我将你的代码改编为我最初的应用程序,用一个按钮“打断”行(举起铅笔),并升级到在第一次点击时在右边显示一个点:嗯,我并没有真正替换它。原来的功能在手机上似乎不起作用,因此我删除了它。如果你让它工作,这将是更好的解决方案,但我不是移动专家。因此,我刚刚添加了另一个点击事件。我不知道如何捕捉移动设备上的悬停,我想应该是鼠标向下,但在鼠标向下时,我得到了一个上下文菜单,但它无法阻止默认行为。我有另一个答案,解决了最初的问题,所以我将赏金授予了他。感谢@BigDataScientist的贡献和宝贵的时间!这是完全应得的。我很有兴趣在下班后探究他的答案。我对手机没有太多的经验,很高兴知道他是如何解决的:)。发布了你的代码链接来测试它:嗨,谢谢,太棒了。我在服务器中添加了一些代码,以便在touchend之后在data.frame中添加NA,以打断行(举起铅笔)。我还减少了一点绘图大小,这样就可以在大多数屏幕上显示,而无需滚动。在iphone/Safari上,阻止情节移动(平移/缩放)并不总是有效的,我发现双击是有效的。是否有一种方法可以阻止整个网页上的所有缩放和滚动(而不阻止按钮…)?喜欢这个答案吗?啊,没错,Safari和iOS当然不支持触摸操作:无(.我不能真正测试这一点,但你可以尝试添加
preventDefault()
添加到每个触摸事件处理程序,以完全禁用滚动/缩放。我编辑了答案。谢谢。现在页面似乎不再移动,但副作用actionbutton在android和ios中都被禁用了…好吧,你在这方面的帮助已经够多了,我现在将尝试改进它,非常感谢!这是最后一个版本的bingo!它工作正常s、 值得所有的尝试!谢谢。
#plot {
  touch-action: none;
}
library(shiny)

ui <- fluidPage(
  h4("Click on plot to start drawing, click again to pause"),
  sliderInput("mywidth", "width of the pencil", min=1, max=30, step=1, value=10),
  actionButton("reset", "reset"),
  plotOutput("plot", width = "400px", height = "400px",
             hover=hoverOpts(id = "hover", delay = 100, delayType = "throttle", clip = TRUE, nullOutside = TRUE),
             click="click"),
  tags$head(
    tags$script("
      $(document).ready(function() {
        var plot = document.getElementById('plot')

        plot.addEventListener('touchmove', function (e) {
          var touch = e.changedTouches[0];
          var mouseEvent = new MouseEvent('mousemove', {
            view: window,
            bubbles: true,
            cancelable: true,
            screenX: touch.screenX,
            screenY: touch.screenY,
            clientX: touch.clientX,
            clientY: touch.clientY
          })
          touch.target.dispatchEvent(mouseEvent);
          e.preventDefault()
        }, { passive: false });

        plot.addEventListener('touchstart', function(e) {
          Shiny.onInputChange('draw', true)
          e.preventDefault()
        }, { passive: false });

        plot.addEventListener('touchend', function(e) {
          Shiny.onInputChange('draw', false)
          e.preventDefault()
        }, { passive: false });
      })
    "),
    tags$style("#plot { touch-action: none; }")
    )
)

server <- function(input, output, session) {
  vals = reactiveValues(x=NULL, y=NULL)
  draw = reactiveVal(FALSE)

  observeEvent(input$click, {
    draw(!draw())
    vals$x <- append(vals$x, NA)
    vals$y <- append(vals$y, NA)
  })

  observeEvent(input$draw, {
    draw(input$draw)
    vals$x <- append(vals$x, NA)
    vals$y <- append(vals$y, NA)
  })

  observeEvent(input$reset, handlerExpr = {
    vals$x <- NULL; vals$y <- NULL
  })

  observeEvent(input$hover, {
    if (draw()) {
      vals$x <- c(vals$x, input$hover$x)
      vals$y <- c(vals$y, input$hover$y)
    }
  })

  output$plot= renderPlot({
    plot(x=vals$x, y=vals$y, xlim=c(0, 28), ylim=c(0, 28), ylab="y", xlab="x", type="l", lwd=input$mywidth)
  })
}

shinyApp(ui, server)