, , , updateprob. @AEF , . R- Javascript.
, . R-, , :
library(shiny)
digits=3
step <- .1^digits
num.questions <- 6
num.sliders <- sample(2:8, num.questions)
updateprob <- function(oldprobs, new, i) {
oldprobs <- oldprobs + 1e-6
ret <- rep(0,length(oldprobs))
ind.other <- c(1:length(oldprobs))[! 1:length(oldprobs) %in% i]
sum.others <- sum( oldprobs[ind.other] )
range.left <- 1 - new
ret[i] <- new
for( n in ind.other ){
ret[n] <- ( oldprobs[n] * range.left) /sum.others
}
return(ret)
}
probsliderInput <- function(inputId,value,submitted=FALSE) {
if (!submitted)
sliderInput(inputId=inputId,
value=value,
label=NULL,
min=0,
max=1,
step=step,
round=-digits,
ticks=FALSE)
}
generateSliders <- function(id, n){
sliders <- lapply(1:n, function(i){
probsliderInput(sprintf("q%ss%d",id,i),1/n)
})
do.call(fluidRow, sliders)
}
generateObservers <- function(id, n, input, session, callback){
lapply(1:n,function(i){
c.id <- sprintf("q%ss%d",id, i)
print(sprintf("Observer for slider with id %s generated",c.id))
observeEvent(input[[ sprintf("q%ss%d",id, i) ]],{
do.call( callback, list(id, n, i, input, session) )
})
})
}
getSlidersValues <- function(id, n, input){
unlist(lapply(1:n,function(i){
input[[sprintf("q%ss%d",id,i)]]
}))
}
setSliderValues <-function(id, ns, session, new.vals){
suspendMany(observers)
for(i in 1:ns){
local({
il <- i
updateSliderInput( session, sprintf("q%ss%d",id,il),value=new.vals[il])
})
}
resumeMany(observers)
}
normalizeSliders <- function(id, nt, nc, input, session){
print(sprintf("[q%ss%d] Slider %d moved, total: %d, l: %d",id,nc,nc, nt,length(observers)))
vals <- getSlidersValues(id, nt, input)
new.vals <- updateprob(vals, input[[sprintf("q%ss%d",id, nc)]],nc)
suspendMany(observers)
for(i in 1:nt){
updateSliderInput( session, sprintf("q%ss%d",id,i),value=new.vals[i])
}
resumeMany(observers)
}
suspendMany <- function(observers) invisible(lapply(observers, function(o) o$suspend()))
resumeMany <- function(observers) invisible(lapply(observers, function(o) o$resume()))
initiateProbs <- function(ns){
lapply(ns,function(i){
rep( 1/i, i)
})
}
server <- function(input, output, session) {
prob <- reactiveValues( prob= initiateProbs(num.sliders) )
observers <- NULL
observeEvent(input$questionNum, {
q.num <- as.character( input$questionNum )
cns <- num.sliders[[input$questionNum]]
sliders <- generateSliders( q.num, cns )
observers <<- generateObservers( q.num, cns, input, session, normalizeSliders)
output$sliders <- renderUI({ sliders })
})
observeEvent(input$previousquestion,{
cns <- num.sliders[[input$questionNum]]
if (input$questionNum <= 1) return()
prob$prob[[input$questionNum]] <- getSlidersValues( as.character( input$questionNum ), cns ,input)
updateNumericInput(session, "questionNum", value=input$questionNum-1)
})
observeEvent(input$nextquestion,{
cns <- num.sliders[[input$questionNum]]
if (input$questionNum >= num.questions) return()
prob$prob[[input$questionNum]] <- getSlidersValues( as.character( input$questionNum ), cns,input)
updateNumericInput(session, "questionNum", value=input$questionNum+1)
})
observeEvent(input$questionNum,{
suspendMany(observers)
setSliderValues( as.character( input$questionNum ), num.sliders[[input$questionNum]], session, prob$prob[[input$questionNum]])
resumeMany(observers)
})
output$number <- renderText(paste("Question", input$questionNum))
}
ui <- fluidPage(
actionButton("previousquestion",icon=icon("angle-left"),label="Previous",
style="color: #000"),
actionButton("nextquestion",icon=icon("angle-right"),label="Next",
style="#000"),
uiOutput("nextbutton", inline = TRUE),
textOutput("number"),
uiOutput('sliders'),
div(numericInput('questionNum','Hidden',1), style="visibility: hidden;")
)
shinyApp(ui=ui , server=server)
HTML, . , , .