timelyportfolio/svgPanZoom

Pan sensitivity varies depending on SVG size

ajholguin opened this issue · 6 comments

When panning, the plot lags behind for large SVGs and is overly sensitive for small SVGs. Is there a way to handle this automatically, or do I just need to size my SVG graphic ahead of time?

Example of Shiny app with large SVG:

library(shiny)
library(svgPanZoom)
library(SVGAnnotation)

ui <- shinyUI(bootstrapPage(
  svgPanZoomOutput(outputId = "main_plot", width = "100%", height = "5in")
))

server = shinyServer(function(input, output) {
  output$main_plot <- renderSvgPanZoom({
    svgPanZoom(svgPlot(plot(1:10), width=20, height=20), controlIconsEnabled = T)
  })
})

runApp(list(ui=ui,server=server))

Example of Shiny app with small SVG:

ui <- shinyUI(bootstrapPage(
  svgPanZoomOutput(outputId = "main_plot", width = "100%", height = "5in")
))

server = shinyServer(function(input, output) {
  output$main_plot <- renderSvgPanZoom({
    svgPanZoom(svgPlot(plot(1:10), width=2.5, height=2.5), controlIconsEnabled = T)
  })
})

runApp(list(ui=ui,server=server))

My use case is that I am trying to export a large network from the DiagrammeR package as an SVG, but I can't get it to be a specific size:

library(DiagrammeR)

svg1 <- exportSVG(grViz("digraph {A;}"))
svg2 <- exportSVG(grViz("digraph {A;}", width = 100, height = 100))
svg3 <- exportSVG(grViz("digraph {A;}", options=list(width = 100, height = 100)))

identical(svg1, svg2)
identical(svg1, svg3)   # the size of the SVG doesn't change

If this issue can't be addressed here I'll consider filing an issue there. Thanks.

To set size on DiagrammeR see if this rich-iannone/DiagrammeR#126 helps.

Also, are you on the most recent version of svgPanZoom?

There is a parameter zoomScaleSensitivity (default 0.2) that you can > 0.2 (try 1 with your large graph) for quicker zoom response, but it seems to have no effect on the pan.

library(shiny)
library(svgPanZoom)
library(SVGAnnotation)

ui <- shinyUI(bootstrapPage(
  svgPanZoomOutput(outputId = "main_plot", width = "100%", height = "5in")
))

server = shinyServer(function(input, output) {
  output$main_plot <- renderSvgPanZoom({
    svgPanZoom(svgPlot(plot(1:10), width=20, height=20), controlIconsEnabled = T,zoomScaleSensitivity = 1)
  })
})

runApp(list(ui=ui,server=server))

I am using the latest version of svgPanZoom, installed from GitHub.

Here is a more complete example, using a large graph diagram. I tried resizing the SVG, but it does not fill the parent container correctly and still lags behind the cursor when panning (it is particularly problematic with tall, thin graphs).

library(igraph)
library(svgPanZoom)
library(DiagrammeR)
library(pipeR)
library(XML)
library(htmltools)
library(shiny)

ui <- shinyUI(bootstrapPage(
  # output should be 650px high
  div(style = "border: 1px solid black;",
      svgPanZoomOutput(outputId = "main_plot", width = "100%", height = "650px")
  )
))

server = shinyServer(function(input, output) {

  largeDiagram <- make_tree(100, 2) %>>%
    get.data.frame( what = "both" ) %>>%
    (
      create_graph(
        data.frame(
          nodes = rownames(.$vertices)
          ,.$vertices
        )
        ,.$edges,
        graph_attrs = "rankdir = LR" # use TB to get a short-wide graph --> this works better unless the window is narrow
      )
    )

  svg <- render_graph(largeDiagram, output = "SVG")

  svg_xml <- xmlParse(svg)
  root <- xmlRoot(svg_xml)
  svg_attrs <- xmlAttrs(root)

  # output should be 650px high
  asp_ratio <- as.numeric(sub('pt','',svg_attrs['width'])) / as.numeric(sub('pt','',svg_attrs['height']))
  svg_attrs[["height"]] <- "650"
  svg_attrs[["width"]] <- 650 * asp_ratio

  xmlAttrs(root) <- svg_attrs

  output$main_plot <- renderSvgPanZoom({
    svgPanZoom(svg_xml, controlIconsEnabled = T)
  })
})

runApp(list(ui=ui,server=server))

In the last release, I added some behavior to fit and make responsive the svgPanZoom htmlwidget. I think this is causing the problem you are demonstrating, but I need to do some testing. Thinking now that I will most likely add arguments to disable these behaviors.

@ajholguin, could you install the latest from Github and try with the argument viewBox = FALSE?

devtools::install_github("timelyportfolio/svgPanZoom")

library(svgPanZoom)
library(SVGAnnotation)

svgPanZoom(
  svgPlot(plot(1:10), width=20, height=20),
  controlIconsEnabled = T,
  minZoom = 0.1,
  viewBox = FALSE
)

It is working correctly with viewBox = FALSE. Thanks for addressing this issue so quickly. As far as I am concerned this issue can be closed.

Great to hear. This was definitely a case of fix one thing, break another. Thanks for the report. Let me know if you have any more feedback, use cases, ideas, anything.