这个问题是我previous question个问题得到回答的后续问题.

目标

在使用嵌套模块的同时,在shiny 的应用程序中实现手写到文本的转换.

这很管用

有三个相关文件:

  • 手写_for_shiny2.js(放在www文件夹中)
  • Mod_handWriting.R(放在R文件夹中;这是一个利用js函数的模块)
  • App.R(放置在应用程序主文件夹中)

Run app.R显示了一个画布,您可以在其中用手写笔书写,当单击"Send"按钮时,它会转换为文本.还有undo撤消、重做和清除画布按钮.

这不管用

然后,我引入了另一个利用模块mod_handwriting.R的模块(mod_simple.R).然后我创建了另一个名为app2.R的应用程序文件,在其中我使用了mod_simple.R.但这一次,按钮不起作用.不过,我还是可以在画布上写字.

代码

Here is all the code:
handwriting_for_shiny2.js

$(document).ready(function() {
   var handwritingCanvas = {};

  Shiny.addCustomMessageHandler("initialize", function(id) {
    var canvas = document.getElementById(id + '-handwritingCanvas');
    handwritingCanvas[id] = new handwriting.Canvas(canvas, 3);

     // Enable undo and redo
     handwritingCanvas[id].set_Undo_Redo(true, true);
     console.log("This is initialize function");
  });

  Shiny.addCustomMessageHandler("clearCanvas", function(id) {
    handwritingCanvas[id].erase();
    console.log("This is clearCanvas function");
  });

   Shiny.addCustomMessageHandler("undoCanvas", function(id) {
    handwritingCanvas[id].undo();
  });

   Shiny.addCustomMessageHandler("redoCanvas", function(id) {
    handwritingCanvas[id].redo();
  });


  Shiny.addCustomMessageHandler("sendCanvas", function(id) {
    var trace = handwritingCanvas[id].trace;
    var options = {
      language: 'en',
      numOfReturn: 1
    };
    var callback = function(result, err) {
      if (err) {
        console.error(err);
      } else {
        Shiny.setInputValue(id + '-recognized_text', result[0]);
      }
    };
    handwriting.recognize(trace, options, callback);
  });





});

mod_handwriting.R

handwritingUI <- function(id) {
  ns <- NS(id)
  fluidRow(
    column(
      width = 4,
      actionButton(ns("clear_canvas"), "Clear Canvas"),
      actionButton(ns("undo"), "Undo"),
      actionButton(ns("redo"), "Redo"),
      actionButton(ns("send"), "Send"),
      textAreaInput(ns("manual_text"), "Enter Text", value = ""),
      tags$canvas(id = ns("handwritingCanvas"), width = "400px", height = "200px")
    )
  )
}


handwritingServer <- function(id) {
  moduleServer(
    id,
    function(input, output, session) {
      
      observe({
        session$sendCustomMessage("initialize", message = id)
      })
    
  observeEvent(input$clear_canvas, {
    session$sendCustomMessage("clearCanvas", message = id)
  })
  
  observeEvent(input$send, {
    session$sendCustomMessage("sendCanvas", message = id)
  })
  
  observeEvent(input$undo, {
    print("Undo button clicked")  # Diagnostic output
    session$sendCustomMessage("undoCanvas", message = id)
  })
  
  observeEvent(input$redo, {
    session$sendCustomMessage("redoCanvas", message = id)
  })
  
  observeEvent(input$recognized_text, {
    if (!is.null(input$recognized_text)) {
      updateTextAreaInput(session, "manual_text", value = input$recognized_text)
    }
  })
  
  
  observe({
    session$sendCustomMessage("initCanvas", message = NULL)
  })
  
    }
  )
}

app.R

library(shiny)

ui <- fluidPage(
  tags$head(
    tags$script(src = "handwriting.js"),
    tags$script(src = "handwriting.canvas.js"),
    tags$script(src = "handwriting_for_shiny2.js"),
    tags$style(HTML("
       #handwritingCanvas {
         border: 1px solid #000;
         margin-top: 10px;
         margin-bottom: 10px;
       }
     "))
  ),
  titlePanel("Handwriting Recognition"),
  handwritingUI("module1")
)

server <- function(input, output, session) {
  handwritingServer("module1")
}

shinyApp(ui, server)

mod_simple.R

mod_simple_ui <- function(id) {
  ns <- NS(id)
  tagList(
    handwritingUI(ns("foo"))
  )
}

mod_simple_server <- function(id) {
  moduleServer(
    id,
    function(input, output, session) {
      ns <- session$ns
      handwritingServer(ns("foo"))
    }
  )
}

app2.R

library(shiny)

ui <- fluidPage(
  tags$head(
    tags$script(src = "handwriting.js"),
    tags$script(src = "handwriting.canvas.js"),
    tags$script(src = "handwriting_for_shiny2.js"),
    tags$style(HTML("
       #handwritingCanvas {
         border: 1px solid #000;
         margin-top: 10px;
         margin-bottom: 10px;
       }
     "))
  ),
  titlePanel("Handwriting Recognition"),
  mod_simple_ui("module1")
)

server <- function(input, output, session) {

  mod_simple_server("module1")
}

shinyApp(ui, server)

调试JS代码:

我已经在JS代码中放置了console.log条语句.我看到两个 fingerprint 都是app.R,但只有This is initialize functionapp2.R.不知何故,clearCanvas功能没有被触发(其他按钮功能也是如此).这似乎是一个名称空间问题.如果有任何帮助,我将不胜感激.

编辑

通过删除服务器部件中的ns更改了mod_simple.R:

mod_simple_ui <- function(id) {
  ns <- NS(id)
  tagList(
    handwritingUI(ns("foo"))
  )
}

mod_simple_server <- function(id) {
  moduleServer(
    id,
    function(input, output, session) {
      ns <- session$ns
      handwritingServer("foo")
    }
  )
}

但随着这一变化,我失go 了在画布内写作的能力.此外,控制台显示以下错误:

shinyapp.ts:442  TypeError: Cannot read properties of null (reading 'getContext')
    at new handwriting.Canvas (handwriting.canvas.js:19:24)
    at e.<anonymous> (handwriting_for_shiny2.js:6:29)
    at e.<anonymous> (shinyapp.ts:866:40)
    at m (shinyapp.ts:5:1357)
    at Generator.<anonymous> (shinyapp.ts:5:4174)
    at Generator.next (shinyapp.ts:5:2208)
    at f0 (shinyapp.ts:6:99)
    at s (shinyapp.ts:7:194)
    at shinyapp.ts:7:364
    at new Promise (<anonymous>)
(anonymous) @ shinyapp.ts:442
shinyapp.ts:442  TypeError: Cannot read properties of undefined (reading 'erase')
    at e.<anonymous> (handwriting_for_shiny2.js:14:27)
    at e.<anonymous> (shinyapp.ts:866:40)
    at m (shinyapp.ts:5:1357)
    at Generator.<anonymous> (shinyapp.ts:5:4174)
    at Generator.next (shinyapp.ts:5:2208)
    at f0 (shinyapp.ts:6:99)
    at s (shinyapp.ts:7:194)
    at shinyapp.ts:7:364
    at new Promise (<anonymous>)
    at e.<anonymous> (shinyapp.ts:7:97)
(anonymous) @ shinyapp.ts:442
m @ shinyapp.ts:5
(anonymous) @ shinyapp.ts:5
(anonymous) @ shinyapp.ts:5
f0 @ shinyapp.ts:6
c @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7
Promise.then (async)
f0 @ shinyapp.ts:6
s @ shinyapp.ts:7

推荐答案

当您使用嵌套模块时,您不必命名模块服务器中的id:必须将handwritingServer(ns("foo"))替换为handwritingServer("foo").

然后一个新的问题出现了.由于您在内部模块中设置为 tags$canvas(id = ns("handwritingCanvas"), ......),因此画布的id将为module1-foo-handwritingCanvas.因此,您必须将ID module1-foo发送给shiny 的消息处理程序.

处理这个问题的一个方便的方法是在模块服务器中使用ns <- session$ns,然后取ns("").这将是module1-foo-.注意结尾的连字符;你必须删除它.也就是说,你必须做:

handwritingServer <- function(id) {
  moduleServer(
    id,
    function(input, output, session) {
      
      ns <- session$ns
      prefix <- ns("") # = "module1-foo-"
      nested_id <- sub("-$", "", prefix) # remove the trailing hyphen
      
      observe({
        session$sendCustomMessage("initialize", message = nested_id)
      })

Javascript相关问答推荐

调用removeEvents不起作用

Plotly热图:在矩形上zoom 后将zoom 区域居中

如何在Obsidian dataview中创建进度条

当作为表达式调用时,如何解析方法decorator 的签名?

分层树视图

Chart.js 4.4.2,当悬停在一个数据点上时,如何在工具提示中拥有多个数据点/标签?

不能将空字符串传递给cy.containes()

try 使用javascript隐藏下拉 Select

元素字符串长度html

try 使用PM2在AWS ubuntu服务器上运行 node 进程时出错

如何在Press上重新启动EXPO-AV视频?

在Java脚本中录制视频后看不到曲目

P5.js中矩形内的圆弧

将Singleton实例设置为未定义后的Angular 变量引用持久性行为

如何将字符串拆分成单词并跟踪每个单词的索引(在原始字符串中)?

Chrome上的印度时区名S有问题吗?

在范围数组中查找公共(包含)范围

验证Java脚本函数中的两个变量

如何从嵌套的json中获取最大值

如何使用Angular JS双击按钮