mirror of
https://github.com/rstudio/shiny.git
synced 2026-04-07 03:00:20 -04:00
Work in progress
This commit is contained in:
@@ -37,6 +37,7 @@ Collate:
|
||||
'timer.R'
|
||||
'tags.R'
|
||||
'cache.R'
|
||||
'graph.R'
|
||||
'react.R'
|
||||
'reactives.R'
|
||||
'fileupload.R'
|
||||
|
||||
@@ -126,6 +126,7 @@ export(validateCssUnit)
|
||||
export(verbatimTextOutput)
|
||||
export(wellPanel)
|
||||
export(withTags)
|
||||
export(writeReactLog)
|
||||
import(RJSONIO)
|
||||
import(caTools)
|
||||
import(digest)
|
||||
|
||||
41
R/graph.R
Normal file
41
R/graph.R
Normal file
@@ -0,0 +1,41 @@
|
||||
#' @export
|
||||
writeReactLog <- function(file=stdout()) {
|
||||
cat(RJSONIO::toJSON(.graphEnv$log, pretty=TRUE), file=file)
|
||||
}
|
||||
|
||||
.graphAppend <- function(logEntry) {
|
||||
.graphEnv$log <- c(.graphEnv$log, list(logEntry))
|
||||
}
|
||||
|
||||
.graphDependsOn <- function(id, label) {
|
||||
.graphAppend(list(action='dep', id=id, dependsOn=label))
|
||||
}
|
||||
|
||||
.graphDependsOnId <- function(id, dependee) {
|
||||
.graphAppend(list(action='depId', id=id, dependsOn=dependee))
|
||||
}
|
||||
|
||||
.graphCreateContext <- function(id, label, type, prevId) {
|
||||
.graphAppend(list(
|
||||
action='ctx', id=id, label=paste(label, collapse='\n'), type=type, prevId=prevId
|
||||
))
|
||||
}
|
||||
|
||||
.graphEnterContext <- function(id) {
|
||||
.graphAppend(list(action='enter', id=id))
|
||||
}
|
||||
|
||||
.graphExitContext <- function(id) {
|
||||
.graphAppend(list(action='exit', id=id))
|
||||
}
|
||||
|
||||
.graphValueChange <- function(label) {
|
||||
.graphAppend(list(action='valueChange', id=label))
|
||||
}
|
||||
|
||||
.graphInvalidate <- function(id) {
|
||||
.graphAppend(list(action='invalidate', id=id))
|
||||
}
|
||||
|
||||
.graphEnv <- new.env()
|
||||
.graphEnv$log <- list()
|
||||
@@ -8,16 +8,19 @@ Context <- setRefClass(
|
||||
.flushCallbacks = 'list'
|
||||
),
|
||||
methods = list(
|
||||
initialize = function(label='') {
|
||||
initialize = function(label='', type='other', prevId='') {
|
||||
id <<- .getReactiveEnvironment()$nextId()
|
||||
.invalidated <<- FALSE
|
||||
.invalidateCallbacks <<- list()
|
||||
.flushCallbacks <<- list()
|
||||
.label <<- label
|
||||
.graphCreateContext(id, label, type, prevId)
|
||||
},
|
||||
run = function(func) {
|
||||
"Run the provided function under this context."
|
||||
env <- .getReactiveEnvironment()
|
||||
.graphEnterContext(id)
|
||||
on.exit(.graphExitContext(id))
|
||||
env$runWith(.self, func)
|
||||
},
|
||||
invalidate = function() {
|
||||
@@ -30,6 +33,7 @@ Context <- setRefClass(
|
||||
lapply(.invalidateCallbacks, function(func) {
|
||||
func()
|
||||
})
|
||||
.graphInvalidate(id)
|
||||
NULL
|
||||
},
|
||||
onInvalidate = function(func) {
|
||||
@@ -86,10 +90,11 @@ ReactiveEnvironment <- setRefClass(
|
||||
return(as.character(.nextId))
|
||||
},
|
||||
currentContext = function() {
|
||||
if (is.null(.currentContext))
|
||||
if (is.null(.currentContext)) {
|
||||
stop('Operation not allowed without an active reactive context. ',
|
||||
'(You tried to do something that can only be done from inside a ',
|
||||
'reactive function.)')
|
||||
}
|
||||
return(.currentContext)
|
||||
},
|
||||
runWith = function(ctx, func) {
|
||||
|
||||
@@ -4,13 +4,18 @@ Dependents <- setRefClass(
|
||||
.dependents = 'Map'
|
||||
),
|
||||
methods = list(
|
||||
register = function() {
|
||||
register = function(depId=NULL, depLabel=NULL) {
|
||||
ctx <- .getReactiveEnvironment()$currentContext()
|
||||
if (!.dependents$containsKey(ctx$id)) {
|
||||
.dependents$set(ctx$id, ctx)
|
||||
ctx$onInvalidate(function() {
|
||||
.dependents$remove(ctx$id)
|
||||
})
|
||||
|
||||
if (!is.null(depId) && nchar(depId) > 0)
|
||||
.graphDependsOnId(ctx$id, depId)
|
||||
if (!is.null(depLabel))
|
||||
.graphDependsOn(ctx$id, depLabel)
|
||||
}
|
||||
},
|
||||
invalidate = function() {
|
||||
@@ -31,6 +36,8 @@ Dependents <- setRefClass(
|
||||
ReactiveValues <- setRefClass(
|
||||
'ReactiveValues',
|
||||
fields = list(
|
||||
# For debug purposes
|
||||
.label = 'character',
|
||||
.values = 'environment',
|
||||
.dependents = 'environment',
|
||||
# Dependents for the list of all names, including hidden
|
||||
@@ -42,6 +49,8 @@ ReactiveValues <- setRefClass(
|
||||
),
|
||||
methods = list(
|
||||
initialize = function() {
|
||||
.label <<- paste('reactiveValues', runif(1, min=1000, max=9999),
|
||||
sep="")
|
||||
.values <<- new.env(parent=emptyenv())
|
||||
.dependents <<- new.env(parent=emptyenv())
|
||||
},
|
||||
@@ -49,6 +58,7 @@ ReactiveValues <- setRefClass(
|
||||
ctx <- .getReactiveEnvironment()$currentContext()
|
||||
dep.key <- paste(key, ':', ctx$id, sep='')
|
||||
if (!exists(dep.key, where=.dependents, inherits=FALSE)) {
|
||||
.graphDependsOn(ctx$id, sprintf('%s$%s', .label, key))
|
||||
assign(dep.key, ctx, pos=.dependents, inherits=FALSE)
|
||||
ctx$onInvalidate(function() {
|
||||
rm(list=dep.key, pos=.dependents, inherits=FALSE)
|
||||
@@ -76,7 +86,11 @@ ReactiveValues <- setRefClass(
|
||||
.allValuesDeps$invalidate()
|
||||
else
|
||||
.valuesDeps$invalidate()
|
||||
|
||||
|
||||
.graphValueChange(sprintf('names(%s)', .label))
|
||||
.graphValueChange(sprintf('%s (all)', .label))
|
||||
.graphValueChange(sprintf('%s$%s', .label, key))
|
||||
|
||||
assign(key, value, pos=.values, inherits=FALSE)
|
||||
dep.keys <- objects(
|
||||
pos=.dependents,
|
||||
@@ -99,16 +113,23 @@ ReactiveValues <- setRefClass(
|
||||
})
|
||||
},
|
||||
names = function() {
|
||||
.graphDependsOn(.getReactiveEnvironment()$currentContext()$id,
|
||||
sprintf('names(%s)', .label))
|
||||
.namesDeps$register()
|
||||
return(ls(.values, all.names=TRUE))
|
||||
},
|
||||
toList = function(all.names=FALSE) {
|
||||
.graphDependsOn(.getReactiveEnvironment()$currentContext()$id,
|
||||
sprintf('%s (all)', .label))
|
||||
if (all.names)
|
||||
.allValuesDeps$register()
|
||||
|
||||
.valuesDeps$register()
|
||||
|
||||
return(as.list(.values, all.names=all.names))
|
||||
},
|
||||
.setLabel = function(label) {
|
||||
.label <<- label
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -231,6 +252,11 @@ as.list.reactivevalues <- function(x, all.names=FALSE, ...) {
|
||||
reactiveValuesToList(x, all.names)
|
||||
}
|
||||
|
||||
# For debug purposes
|
||||
.setLabel <- function(x, label) {
|
||||
.subset2(x, 'impl')$.setLabel(label)
|
||||
}
|
||||
|
||||
#' Convert a reactivevalues object to a list
|
||||
#'
|
||||
#' This function does something similar to what you might \code{\link{as.list}}
|
||||
@@ -269,7 +295,8 @@ Observable <- setRefClass(
|
||||
.running = 'logical',
|
||||
.value = 'ANY',
|
||||
.visible = 'logical',
|
||||
.execCount = 'integer'
|
||||
.execCount = 'integer',
|
||||
.mostRecentCtxId = 'character'
|
||||
),
|
||||
methods = list(
|
||||
initialize = function(func, label=deparse(substitute(func))) {
|
||||
@@ -282,9 +309,10 @@ Observable <- setRefClass(
|
||||
.running <<- FALSE
|
||||
.label <<- label
|
||||
.execCount <<- 0L
|
||||
.mostRecentCtxId <<- ""
|
||||
},
|
||||
getValue = function() {
|
||||
.dependents$register()
|
||||
.dependents$register(.mostRecentCtxId)
|
||||
|
||||
if (.invalidated || .running) {
|
||||
.self$.updateValue()
|
||||
@@ -299,7 +327,8 @@ Observable <- setRefClass(
|
||||
invisible(.value)
|
||||
},
|
||||
.updateValue = function() {
|
||||
ctx <- Context$new(.label)
|
||||
ctx <- Context$new(.label, type='observable', prevId=.mostRecentCtxId)
|
||||
.mostRecentCtxId <<- ctx$id
|
||||
ctx$onInvalidate(function() {
|
||||
.invalidated <<- TRUE
|
||||
.dependents$invalidate()
|
||||
@@ -395,7 +424,8 @@ Observer <- setRefClass(
|
||||
.invalidateCallbacks = 'list',
|
||||
.execCount = 'integer',
|
||||
.onResume = 'function',
|
||||
.suspended = 'logical'
|
||||
.suspended = 'logical',
|
||||
.prevId = 'character'
|
||||
),
|
||||
methods = list(
|
||||
initialize = function(func, label, suspended = FALSE, priority = 0) {
|
||||
@@ -409,12 +439,14 @@ Observer <- setRefClass(
|
||||
.execCount <<- 0L
|
||||
.suspended <<- suspended
|
||||
.onResume <<- function() NULL
|
||||
.prevId <<- ''
|
||||
|
||||
# Defer the first running of this until flushReact is called
|
||||
.createContext()$invalidate()
|
||||
},
|
||||
.createContext = function() {
|
||||
ctx <- Context$new(.label)
|
||||
ctx <- Context$new(.label, type='observer', prevId=.prevId)
|
||||
.prevId <<- ctx$id
|
||||
|
||||
ctx$onInvalidate(function() {
|
||||
lapply(.invalidateCallbacks, function(func) {
|
||||
@@ -780,7 +812,7 @@ invalidateLater <- function(millis, session) {
|
||||
#'
|
||||
#' @export
|
||||
isolate <- function(expr) {
|
||||
ctx <- Context$new('[isolate]')
|
||||
ctx <- Context$new('[isolate]', type='isolate')
|
||||
ctx$run(function() {
|
||||
expr
|
||||
})
|
||||
|
||||
@@ -64,7 +64,9 @@ ShinySession <- setRefClass(
|
||||
.clientData <<- ReactiveValues$new()
|
||||
|
||||
input <<- .createReactiveValues(.input, readonly=TRUE)
|
||||
.setLabel(input, 'input')
|
||||
clientData <<- .createReactiveValues(.clientData, readonly=TRUE)
|
||||
.setLabel(clientData, 'clientData')
|
||||
|
||||
output <<- .createOutputWriter(.self)
|
||||
|
||||
@@ -142,7 +144,7 @@ ShinySession <- setRefClass(
|
||||
}
|
||||
else
|
||||
.invalidatedOutputValues$set(name, value)
|
||||
}, label=label, suspended=.shouldSuspend(name))
|
||||
}, label=sprintf('output$%s', name), suspended=.shouldSuspend(name))
|
||||
|
||||
obs$onInvalidate(function() {
|
||||
showProgress(name)
|
||||
|
||||
605
inst/www/reactive-graph.html
Normal file
605
inst/www/reactive-graph.html
Normal file
@@ -0,0 +1,605 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
|
||||
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
||||
<style type="text/css">
|
||||
#viz {
|
||||
width: 600px;
|
||||
height: 300px;
|
||||
}
|
||||
.node {
|
||||
z-index: 1;
|
||||
}
|
||||
.node.invalidated {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: #CCC;
|
||||
stroke-width: 0.5px;
|
||||
z-index: 0;
|
||||
}
|
||||
#description {
|
||||
position: fixed;
|
||||
width: 300px;
|
||||
left: 12px;
|
||||
top: 36px;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var log = [
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(input)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input$dataset"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(input)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input$caption"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(input)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input$obs"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$output_caption_hidden"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$output_summary_hidden"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$output_view_hidden"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$pixelratio"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$url_protocol"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$url_hostname"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$url_port"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$url_pathname"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$url_search"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$url_hash_initial"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(clientData)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "clientData$allowDataUriScheme"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "1",
|
||||
"label" : "output$caption",
|
||||
"type" : "observer",
|
||||
"prevId" : ""
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "1"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "2",
|
||||
"label" : "output$summary",
|
||||
"type" : "observer",
|
||||
"prevId" : ""
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "2"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "3",
|
||||
"label" : "output$view",
|
||||
"type" : "observer",
|
||||
"prevId" : ""
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "3"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "4",
|
||||
"label" : "output$caption",
|
||||
"type" : "observer",
|
||||
"prevId" : "1"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "4"
|
||||
},
|
||||
{
|
||||
"action" : "dep",
|
||||
"id" : "4",
|
||||
"dependsOn" : "input$caption"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "4"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "5",
|
||||
"label" : "output$summary",
|
||||
"type" : "observer",
|
||||
"prevId" : "2"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "5"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "6",
|
||||
"label" : "{\n switch(input$dataset, rock = rock, pressure = pressure, cars = cars)\n}",
|
||||
"type" : "observable",
|
||||
"prevId" : ""
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "6"
|
||||
},
|
||||
{
|
||||
"action" : "dep",
|
||||
"id" : "6",
|
||||
"dependsOn" : "input$dataset"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "6"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "5"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "7",
|
||||
"label" : "output$view",
|
||||
"type" : "observer",
|
||||
"prevId" : "3"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "7"
|
||||
},
|
||||
{
|
||||
"action" : "depId",
|
||||
"id" : "7",
|
||||
"dependsOn" : "6"
|
||||
},
|
||||
{
|
||||
"action" : "dep",
|
||||
"id" : "7",
|
||||
"dependsOn" : "input$obs"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "7"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(input)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input$caption"
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "4"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "8",
|
||||
"label" : "output$caption",
|
||||
"type" : "observer",
|
||||
"prevId" : "4"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "8"
|
||||
},
|
||||
{
|
||||
"action" : "dep",
|
||||
"id" : "8",
|
||||
"dependsOn" : "input$caption"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "8"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "names(input)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input (all)"
|
||||
},
|
||||
{
|
||||
"action" : "valueChange",
|
||||
"id" : "input$dataset"
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "5"
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "7"
|
||||
},
|
||||
{
|
||||
"action" : "invalidate",
|
||||
"id" : "6"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "9",
|
||||
"label" : "output$summary",
|
||||
"type" : "observer",
|
||||
"prevId" : "5"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "9"
|
||||
},
|
||||
{
|
||||
"action" : "depId",
|
||||
"id" : "9",
|
||||
"dependsOn" : "6"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "10",
|
||||
"label" : "{\n switch(input$dataset, rock = rock, pressure = pressure, cars = cars)\n}",
|
||||
"type" : "observable",
|
||||
"prevId" : "6"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "10"
|
||||
},
|
||||
{
|
||||
"action" : "dep",
|
||||
"id" : "10",
|
||||
"dependsOn" : "input$dataset"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "10"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "9"
|
||||
},
|
||||
{
|
||||
"action" : "ctx",
|
||||
"id" : "11",
|
||||
"label" : "output$view",
|
||||
"type" : "observer",
|
||||
"prevId" : "7"
|
||||
},
|
||||
{
|
||||
"action" : "enter",
|
||||
"id" : "11"
|
||||
},
|
||||
{
|
||||
"action" : "depId",
|
||||
"id" : "11",
|
||||
"dependsOn" : "10"
|
||||
},
|
||||
{
|
||||
"action" : "dep",
|
||||
"id" : "11",
|
||||
"dependsOn" : "input$obs"
|
||||
},
|
||||
{
|
||||
"action" : "exit",
|
||||
"id" : "11"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
];
|
||||
|
||||
var nodes = {};
|
||||
var nodeList = [];
|
||||
var nodeSelection = null;
|
||||
var links = [];
|
||||
var linkSelection = null;
|
||||
|
||||
var colors = {
|
||||
observer: '#009',
|
||||
observable: '#900',
|
||||
value: '#999'
|
||||
};
|
||||
|
||||
var force = d3.layout.force()
|
||||
.nodes(nodeList)
|
||||
.links(links)
|
||||
.size([150, 75]);
|
||||
force.on('tick', onTick);
|
||||
|
||||
function update() {
|
||||
var viz = d3.select('#viz');
|
||||
viz.select('#nodes').selectAll('.node').data(nodeList)
|
||||
.enter().append('circle')
|
||||
.attr('class', 'node')
|
||||
.attr('title', function(n) {return n.label;})
|
||||
.attr('fill', function(n) {return colors[n.type];})
|
||||
.attr('r', 5)
|
||||
.attr('onmouseover', '$("#description").text(this.getAttribute("title"));')
|
||||
.attr('onmouseout', '$("#description").html("<br/>");');
|
||||
viz.selectAll('.node').data(nodeList)
|
||||
.exit().remove();
|
||||
nodeSelection = viz.selectAll('.node');
|
||||
nodeSelection.classed('invalidated', function(n) { return n.invalidated; })
|
||||
|
||||
viz.select('#links').selectAll('.link').data(links)
|
||||
.enter().append('path')
|
||||
.attr('class', 'link');
|
||||
viz.selectAll('.link').data(links)
|
||||
.exit().remove();
|
||||
linkSelection = viz.selectAll('.link');
|
||||
|
||||
force.start();
|
||||
}
|
||||
|
||||
function onTick() {
|
||||
nodeSelection
|
||||
.attr('cx', function(n) { return n.x; })
|
||||
.attr('cy', function(n) { return n.y; })
|
||||
;
|
||||
linkSelection
|
||||
.attr('d', function(link) {
|
||||
return 'M' + link.source.x + ',' + link.source.y +
|
||||
' L' + link.target.x + ',' + link.target.y;
|
||||
});
|
||||
}
|
||||
|
||||
function createNode(data, type) {
|
||||
var node;
|
||||
if (!data.prevId) {
|
||||
node = {
|
||||
label: data.label,
|
||||
type: data.type,
|
||||
index: nodeList.length
|
||||
};
|
||||
nodes[data.id] = node;
|
||||
nodeList.push(node);
|
||||
} else {
|
||||
node = nodes[data.prevId];
|
||||
delete nodes[data.prevId];
|
||||
nodes[data.id] = node;
|
||||
node.invalidated = false;
|
||||
}
|
||||
}
|
||||
|
||||
var callbacks = {
|
||||
ctx: function(data) {
|
||||
createNode(data);
|
||||
},
|
||||
dep: function(data) {
|
||||
if (!nodes[data.dependsOn])
|
||||
createNode({id: data.dependsOn, label: data.dependsOn, type: 'value'});
|
||||
links.push({
|
||||
source: nodes[data.id],
|
||||
target: nodes[data.dependsOn]
|
||||
});
|
||||
},
|
||||
depId: function(data) {
|
||||
links.push({
|
||||
source: nodes[data.id],
|
||||
target: nodes[data.dependsOn]
|
||||
});
|
||||
},
|
||||
invalidate: function(data) {
|
||||
var node = nodes[data.id];
|
||||
node.invalidated = true;
|
||||
links = links.filter(function(link) {
|
||||
return link.source !== node;
|
||||
});
|
||||
},
|
||||
valueChange: function(data) {
|
||||
return true;
|
||||
},
|
||||
enter: function(data) {
|
||||
return true;
|
||||
},
|
||||
exit: function(data) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
function processMessage(data) {
|
||||
console.log(JSON.stringify(data));
|
||||
if (!callbacks.hasOwnProperty(data.action))
|
||||
throw new Error('Unknown action ' + data.action);
|
||||
var result = callbacks[data.action].call(callbacks, data);
|
||||
update();
|
||||
return result;
|
||||
}
|
||||
|
||||
function doNext() {
|
||||
while (log.length)
|
||||
if (!processMessage(log.shift()))
|
||||
break;
|
||||
if (log.length === 0)
|
||||
document.getElementById('processNext').setAttribute('disabled', 'disabled');
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<button id="processNext" onclick="doNext();">Next</button>
|
||||
<br/>
|
||||
<svg>
|
||||
<g id="viz" transform="scale(4)">
|
||||
<g id="links"></g>
|
||||
<g id="nodes"></g>
|
||||
</g>
|
||||
</svg>
|
||||
<pre id="description"><br/></pre>
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
<svg style="border: 1px solid silver; width: 400px; height: 400px">
|
||||
<g>
|
||||
<path stroke="black" stroke-width="4" fill="white" d="m 58,2 c -75,0 -75,100 0,100 l 60,0 l 50,-50 l -50,-50 Z"/>
|
||||
</g>
|
||||
<g transform="translate(0 110)">
|
||||
<path stroke="black" stroke-width="4" fill="white" d="m 58,2 c -75,0 -75,100 0,100 l 100,0 l 0,-100 Z"/>
|
||||
</g>
|
||||
<g transform="translate(0 220)">
|
||||
<path stroke="black" stroke-width="4" fill="white" d="m 2,0 l 0,100 l 100,0 l 50,-50 l -50,-50 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
-->
|
||||
Reference in New Issue
Block a user