Colors should appear and change when dragging the slider button but nothing happens, there is just a blank canvas in the right hand side of the screen. I changed some things before it was not even a canvas on the right hand side of the screen but now when there is a canvas nothing happens when I use slider option like color should appear. When I select a color from the dropdown and use slider then the color should also change:
# install.packages(c("shiny", "shinyjs"))
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
titlePanel("Drawing App"),
sidebarLayout(
sidebarPanel(
sliderInput("brushSize", "Brush Size", min = 1, max = 20, value = 5),
selectInput("brushColor", "Brush Color",
choices = c("Black", "Red", "Blue", "Green", "Eraser"),
selected = "Black")
),
mainPanel(
div(id = "canvas", style = "border:1px solid #000; height: 400px;"),
tags$script('
var isDrawing = false;
var context;
$(document).ready(function(){
var canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
$("#canvas").mousedown(function(e){
isDrawing = true;
context.beginPath();
context.moveTo(e.pageX - canvas.offsetLeft, e.pageY - canvas.offsetTop);
});
$("#canvas").mousemove(function(e){
if(isDrawing){
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
var color = $("#brushColor").val();
var size = $("#brushSize").val();
context.lineWidth = size;
if(color === "Eraser"){
context.strokeStyle = "#FFF"; // White color for eraser
} else {
context.strokeStyle = color.toLowerCase();
}
context.lineTo(x, y);
context.stroke();
}
});
$("#canvas").mouseup(function(){
isDrawing = false;
});
$("#canvas").mouseleave(function(){
isDrawing = false;
});
Shiny.setInputValue("canvasData", canvas.toDataURL());
});
Shiny.addCustomMessageHandler("clearCanvas", function(message) {
context.clearRect(0, 0, canvas.width, canvas.height);
});
')
)
)
)
server <- function(input, output, session) {
observe({
brush_color <- switch(input$brushColor,
"Black" = "black",
"Red" = "red",
"Blue" = "blue",
"Green" = "green",
"Eraser" = "white")
shinyjs::runjs(paste0('context.strokeStyle = "', brush_color, '";'))
})
observeEvent(input$canvasData, {
session$sendCustomMessage("clearCanvas", NULL)
shinyjs::runjs(paste0('var img = new Image(); img.src = "', input$canvasData, '"; context.drawImage(img, 0, 0);'))
})
}
shinyApp(ui, server)
Note that:
getContext()
on a div
, you have to create your canvas
using tags$canvas(height="400px", id="canvas", style="border: 1px solid #000;")
.$(document).on("shiny:connected"
, otherwise shiny
may not be ready when you try to use setInputValue
.canvas
attributes for width
and height
should be set up correctly: canvas.setAttribute("width", canvas.parentNode.offsetWidth); canvas.setAttribute("height", canvas.parentNode.offsetHeight);
var bounds = canvas.getBoundingClientRect();
and access them (e.g. context.moveTo(e.pageX - bounds.left, e.pageY - bounds.top);
), otherwise the cursor position won't match.Then it will work.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
titlePanel("Drawing App"),
sidebarLayout(
sidebarPanel(
sliderInput("brushSize", "Brush Size", min = 1, max = 20, value = 5),
selectInput("brushColor", "Brush Color",
choices = c("Black", "Red", "Blue", "Green", "Eraser"),
selected = "Black")
),
mainPanel(
tags$canvas(
height="400px", id="canvas", style="border: 1px solid #000;"
),
tags$script(HTML('
var isDrawing = false;
var context;
$(document).on("shiny:connected", function(){
var canvas = document.getElementById("canvas");
canvas.setAttribute("width", canvas.parentNode.offsetWidth);
canvas.setAttribute("height", canvas.parentNode.offsetHeight);
context = canvas.getContext("2d");
var bounds = canvas.getBoundingClientRect();
$("#canvas").mousedown(function(e){
isDrawing = true;
context.beginPath();
context.moveTo(e.pageX - bounds.left, e.pageY - bounds.top);
});
$("#canvas").mousemove(function(e){
if(isDrawing){
var x = e.pageX - bounds.left;
var y = e.pageY - bounds.top;
var color = $("#brushColor").val();
var size = $("#brushSize").val();
context.lineWidth = size;
if(color === "Eraser"){
context.strokeStyle = "#FFF"; // White color for eraser
} else {
context.strokeStyle = color.toLowerCase();
}
context.lineTo(x, y);
context.stroke();
}
});
$("#canvas").mouseup(function(){
isDrawing = false;
});
$("#canvas").mouseleave(function(){
isDrawing = false;
});
Shiny.setInputValue("canvasData", canvas.toDataURL());
});
Shiny.addCustomMessageHandler("clearCanvas", function(message) {
context.clearRect(0, 0, canvas.width, canvas.height);
});
'))
)
)
)
server <- function(input, output, session) {
observe({
brush_color <- switch(input$brushColor,
"Black" = "black",
"Red" = "red",
"Blue" = "blue",
"Green" = "green",
"Eraser" = "white")
shinyjs::runjs(paste0('context.strokeStyle = "', brush_color, '";'))
})
observeEvent(input$canvasData, {
session$sendCustomMessage("clearCanvas", NULL)
shinyjs::runjs(paste0('var img = new Image(); img.src = "', input$canvasData, '"; context.drawImage(img, 0, 0);'))
})
}
shinyApp(ui, server)