@@ -11,8 +11,10 @@ lenv <- new.env(parent = emptyenv())
1111lenv $ coNames <- ' '
1212# assign('aa', 11, envir=.ecv.colnames); get('aa', envir=.ecv.colnames)
1313noAxisXY <- c(' radar' ,' parallel' ,' themeRiver' ,' map' ,' gauge' ,' pie' ,' funnel' ,' polar' ,' chord' ,
14- ' sunburst' ,' tree' ,' treemap' ,' sankey' ,' lines' , ' liquidFill' ,' wordCloud' ) # series
14+ ' sunburst' ,' tree' ,' treemap' ,' sankey' ,' lines' , ' liquidFill' ,' wordCloud' , ' segmentedDoughnut ' ) # series
1515noCoord <- c(' polar' ,' radar' ,' singleAxis' ,' parallelAxis' ,' calendar' )
16+ plf <- read.csv(system.file(' plugins.csv' , package = ' echarty' ), header = TRUE , stringsAsFactors = FALSE )
17+ renderCustom <- setNames(as.list(plf [[2 ]]), plf [[1 ]])
1618# using list(show=TRUE) or list(list()) is to create empty object{} in JS
1719
1820# ' Initialize a chart
@@ -72,15 +74,16 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
7274# ' * world - world map with country boundaries, see \href{https://github.com/apache/echarts/tree/master/test/data/map/js}{source} \cr
7375# ' * lottie - support for \href{https://lottiefiles.com}{lotties} \cr
7476# ' * ecStat - statistical tools, see\href{https://github.com/ecomfe/echarts-stat}{echarts-stat}\cr
75- # ' * custom - renderers for [ecr.band] and [ecr.ebars] \cr
77+ # ' * custom - renderers for echarty plugins like [ecr.band] and [ecr.ebars] \cr
7678# '
7779# ' **Plugins with one-time installation** \cr
7880# ' * 3D - support for 3D charts and WebGL acceleration, see \href{https://github.com/ecomfe/echarts-gl}{source} and \href{https://echarts.apache.org/en/option-gl.html#series}{docs} \cr
7981# ' \verb{ } This plugin is auto-loaded when 3D/GL axes/series are detected.\cr
80- # ' * liquid - liquid fill, see \href{https://github.com/ecomfe/echarts-liquidfill}{source} \cr
8182# ' * gmodular - graph modularity, see \href{https://github.com/ecomfe/echarts-graph-modularity}{source} \cr
83+ # ' * liquid - liquid fill, see \href{https://github.com/ecomfe/echarts-liquidfill}{source} \cr
8284# ' * wordcloud - cloud of words, see \href{https://github.com/ecomfe/echarts-wordcloud}{source} \cr
83- # ' or install your own third-party plugins.\cr
85+ # ' Note: the last three are being moved to the \href{https://github.com/apache/echarts-custom-series}{official custom series}.\cr
86+ # ' OR install your own third-party plugins like _confetti_, see example below.\cr
8487# '
8588# ' **Crosstalk** \cr
8689# ' Parameter _df_ should be of type \link[crosstalk]{SharedData}, see \href{https://helgasoft.github.io/echarty/articles/gallery.html#crosstalk-2d}{more info}.\cr
@@ -116,8 +119,8 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
116119# ' # custom inititlization options and theme
117120# ' myth <- '{"color": ["green"], "backgroundColor": "lemonchiffon"}'
118121# ' ec.init( cars,
119- # ' theme= jsonlite::fromJSON(myth),
120122# ' iniOpts= list(renderer= 'svg', width= '222px'),
123+ # ' theme= jsonlite::fromJSON(myth),
121124# ' toolbox= list(feature= list(saveAsImage= list()))
122125# ' )
123126# '
@@ -140,6 +143,19 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
140143# ' series.param= list(type='gauge', max=5)
141144# ' )
142145# '
146+ # ' ec.init(
147+ # ' series.param= list(
148+ # ' renderItem= 'segmentedDoughnut', # v.6 from https://github.com/apache/echarts-custom-series
149+ # ' itemPayload= list(segmentCount= 8, label= list(show=T, formatter= '{c}/{b}', fontSize=35) ),
150+ # ' data= list(5) )
151+ # ' )
152+ # '
153+ # ' ec.init(cars, js= 'confetti();', # js code executes on init
154+ # ' load= 'https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/dist/confetti.browser.min.js',
155+ # ' ask= 'loadRemote',
156+ # ' on= list(list(event= 'click', handler= ec.clmn('() => confetti()')) )
157+ # ' )
158+ # '
143159# ' @importFrom htmlwidgets createWidget sizingPolicy getDependency JS shinyWidgetOutput shinyRenderWidget
144160# ' @importFrom utils read.csv modifyList
145161# ' @import dplyr
@@ -154,7 +170,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
154170 # treacherous R does "partial matching of argument names" (like a bug):
155171 # if 'series.param' is before '...' and 'series' is added, the latter is ignored!
156172 elementId <- opt1 $ elementId ; js <- opt1 $ js
157- ask <- if ( is.null(opt1 $ ask )) FALSE else opt1 $ ask
173+ ask <- ifelse( ! is.null(opt1 $ ask ), opt1 $ ask , FALSE )
158174 ctype <- if (is.null(opt1 $ ctype )) ' scatter' else opt1 $ ctype
159175 iniOpts <- if (! is.null(opt1 $ iniOpts )) opt1 $ iniOpts else list ()
160176 # set defaults + backward compat:
@@ -165,7 +181,6 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
165181 xtKey <- if (is.null(opt1 $ xtKey )) ' XkeyX' else opt1 $ xtKey
166182 # allow debug feedback thru cat() in R & JS code
167183 dbg <- if (is.null(opt1 $ dbg )) FALSE else opt1 $ dbg
168- if (dbg ) cat(' \n coln=' , lenv $ coNames )
169184 # remove the above attributes since they are not valid ECharts options
170185 for (ii in c(' renderer' ,' locale' ,' useDirtyRect' ,' iniOpts' ,' ask' ,' js' ,
171186 ' elementId' ,' xtKey' ,' dbg' ,' ctype' )) opt1 [ii ] <- NULL
@@ -471,7 +486,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
471486 tl.series $ type <- ctype
472487 }
473488
474- if (' series' %in% names( x $ opts ) ) {
489+ if (' series' %in% namop ) {
475490 if (! is.null(ctype )) # all series, not 1st only
476491 x $ opts $ series <- lapply(x $ opts $ series , function (ss ) {
477492 if (is.null(ss $ type )) ss $ type <- ctype
@@ -492,6 +507,24 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
492507 }
493508 axad <- 1 ; isSname <- FALSE
494509 x $ opts $ series <- lapply(x $ opts $ series , function (ss ) {
510+ # renderItem helper
511+ if (! is.null(ss $ renderItem ) && inherits(ss $ renderItem , " character" )) {
512+ if (startsWith(ss $ renderItem , ' ri' ))
513+ ss $ renderItem <- htmlwidgets :: JS(ss $ renderItem )
514+ else { # new ECharts 6 custom series want a character string
515+ bask <- (ask == FALSE ) | (ask == ' loadRemote' )
516+ if (bask && ! is.null(renderCustom [ss $ renderItem ])) {
517+ ask <<- ' loadRemote'
518+ x $ opts $ load <<- c(x $ opts $ load , renderCustom [[ss $ renderItem ]])
519+ }
520+ if (ss $ renderItem %in% c(' segmentedDoughnut' ,' liquidFill' ,' wordCloud' ))
521+ ss $ coordinateSystem <- ' none'
522+ if (! any(grepl(' d3.min.js' , x $ opts $ load )) && ss $ renderItem == ' contour' )
523+ x $ opts $ load <<- c(' https://cdn.jsdelivr.net/npm/d3@latest/dist/d3.min.js' , x $ opts $ load )
524+ }
525+ if (! is.null(ss $ type )) ss $ type <- ' custom'
526+ }
527+
495528 tmp <- xyNamesCS(ss )
496529 if (! is.null(tmp $ c )) ss $ coordinateSystem <- tmp $ c
497530
@@ -510,10 +543,6 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
510543 }
511544 if (! is.null(ss $ name )) isSname <<- TRUE
512545
513- # renderItem helper only for our custom functions ri*
514- # new ECharts custom series, like segmentedDoughnut, want a character string
515- if (! is.null(ss $ renderItem ) && inherits(ss $ renderItem ," character" ) && startsWith(ss $ renderItem , ' ri' ))
516- ss $ renderItem <- htmlwidgets :: JS(ss $ renderItem )
517546 ss
518547 })
519548 if (any(c(' geo' ,' leaflet' ,' globe' , noCoord ) %in% namop )) axad <- 0 # was axad-1
@@ -542,7 +571,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
542571 # set X,Y axes type & name from df OR from series.data
543572
544573 cnms <- NULL
545- ena <- c(' x' ,' y' ) # for polar > c('radius','angle') #, 'lng','lat')
574+ ena <- c(' x' ,' y' ) # TODO: for polar= c('radius','angle') map= c( 'lng','lat')
546575 coln <- colp <- ctyp <- list () # column names, positions, types
547576 for (xy in ena ) { coln [xy ] <- ctyp [xy ] <- colp [xy ] <- NA }
548577
@@ -556,9 +585,9 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
556585 ! paste0(s1 $ type ,s1 $ layout ) %in% c(' graphforce' ,' graphcircular' ) &&
557586 ! slb && ! paste0(' ' ,s1 $ coordinateSystem ) %in% c(' leaflet' ,' geo' ) &&
558587 ! any(noCoord %in% names(x $ opts ))
559- if (isAxes ) { # can search for XY axes names/ type
588+ if (isAxes ) { # search for single X/Y axis name and type
560589 colp [1 ] <- colX [1 ]; colp [2 ] <- colY [1 ];
561- if (! is.null(s1 $ encode )) { # chk $data then $dset
590+ if (! is.null(s1 $ encode )) {
562591 for (xy in ena ) {
563592 exy <- s1 $ encode [[xy ]]
564593 if (! is.null(exy ) && length(exy ) < 2 ) { # exclude multi-values like candlestick
@@ -567,7 +596,7 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
567596 }
568597 }
569598 }
570-
599+ # check first $data then $dset
571600 if (exists(' sedval' )) { # encode$data$value takes precedence
572601 i <- 1
573602 for (xy in ena ) {
@@ -576,7 +605,8 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
576605 }
577606 else if (' data' %in% names(s1 )) {
578607 # chk s1$data for type (and maybe name) list(value=) or list(c()) or mixed
579- # verify only first row in list-of-lists # non-named but can have names in s1$dimens
608+ # verify only first row in list-of-lists
609+ # TODO: s1$data could be non-named but have names in s1$dimensions
580610 d1 <- if (is.list(s1 $ data ) && is.list(s1 $ data [[1 ]])) s1 $ data [[1 ]] else s1 $ data
581611 if (! is.null(names(d1 ))) {
582612 cnms <- names(d1 )
@@ -589,11 +619,13 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
589619 }
590620 }
591621 else { # like data=c(1,2..)
592- if (! is.na(coln [[xy ]]) && coln [[xy ]] %in% cnms ) ctyp [xy ] <- tail(class(d1 [[coln [[xy ]]]]), 1 )
622+ if (! is.na(coln [[xy ]]) && coln [[xy ]] %in% cnms ) ctyp [xy ] <- tail(class(d1 [[ coln [[xy ]] ]]), 1 )
593623 else if (! is.na(colp [[xy ]])) ctyp [xy ] <- tail(class(d1 [[colp [[xy ]]]]), 1 ) # numeric array
594624 }
595625 }
596- else if (! is.null(x $ opts $ dataset )) { # dataset # TODO ignore if {nam=...} format ?
626+ else if (! is.null(x $ opts $ dataset )) { # dataset
627+ # TODO: ignore when format is [{name=...},..] ?
628+ # TODO: types of multiple xAxis[] (when no series$encode)
597629 dset <- x $ opts $ dataset [[1 ]]
598630 r1 <- dset $ source [[1 ]]
599631 if (! is.null(dset $ dimensions )) cnms <- dset $ dimensions
@@ -602,9 +634,12 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
602634 cnms <- unlist(r1 ) # header
603635 r1 <- dset $ source [[2 ]]
604636 }
637+ # for(xy in ena) {
638+ # if (!is.na(coln[xy]) && coln[xy] %in% cnms) colp[xy] <- which(cnms==coln[[xy]]) # name to pos
639+ # if (!is.na(colp[xy])) ctyp[xy] <- tail(class(r1[[colp[[xy]]]]), 1) # numeric array
640+ # }
605641 for (xy in ena ) {
606- if (! is.na(coln [xy ]) && coln [xy ] %in% cnms ) colp [xy ] <- which(cnms == coln [[xy ]]) # name to pos
607- if (! is.na(colp [xy ])) ctyp [xy ] <- tail(class(r1 [[colp [[xy ]]]]), 1 ) # numeric array
642+ if (! is.na(colp [xy ])) ctyp [xy ] <- tail(class(r1 [[ colp [[xy ]] ]]), 1 )
608643 }
609644 }
610645
@@ -627,7 +662,8 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
627662 } # end isAxes
628663
629664 } # end preset
630-
665+ if (dbg ) cat(' \n cnames=' , lenv $ coNames )
666+
631667 x $ opts <- .renumber(x $ opts )
632668
633669 # ------------- create widget ----------------
@@ -789,8 +825,8 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
789825 }
790826
791827 # Plugins implemented as dynamic load on-demand
792- if (any(load %in% c(' 3D' ,' liquid ' ,' gmodular ' ,' wordcloud' ))) {
793- plf <- read.csv(system.file(' plugins.csv' , package = ' echarty' ), header = TRUE , stringsAsFactors = FALSE )
828+ if (any(load %in% c(' 3D' ,' gmodular ' ,' liquid ' ,' wordcloud' ))) {
829+ # plf <- read.csv(system.file('plugins.csv', package='echarty'), header=TRUE, stringsAsFactors=FALSE)
794830 if (' 3D' %in% load ) {
795831 isGL <- any(unlist(lapply(opt1 $ series , \(k ){ endsWith(k $ type , ' GL' ) }))) # GL is 2D
796832 isMap3d <- ! is.null(opt1 $ globe ) || ! is.null(opt1 $ geo3D )
@@ -828,13 +864,13 @@ ec.init <- function( df= NULL, preset= TRUE, ..., #ctype= 'scatter',
828864 }
829865 wt <- ec.plugjs(wt , plf [plf $ name == ' 3D' ,]$ url , ask )
830866 }
831- if (' liquid' %in% load ) wt <- ec.plugjs(wt , plf [plf $ name == ' liquid' ,]$ url , ask )
832- if (' gmodular' %in% load ) wt <- ec.plugjs(wt , plf [plf $ name == ' gmodular' ,]$ url , ask )
833- if (' wordcloud' %in% load ) wt <- ec.plugjs(wt , plf [plf $ name == ' wordcloud' ,]$ url , ask )
867+ for (nn in c(' gmodular' ,' liquid' ,' wordcloud' )) {
868+ if (nn %in% load ) wt <- ec.plugjs(wt , plf [plf $ name == nn ,]$ url , ask ) }
869+ # if ('liquid' %in% load) wt <- ec.plugjs(wt, plf[plf$name=='liquid',]$url, ask)
870+ # if ('wordcloud' %in% load) wt <- ec.plugjs(wt, plf[plf$name=='wordcloud',]$url, ask)
834871 }
835872 # load unknown plugins
836- unk <- load [! load %in% c(' leaflet' ,' custom' ,' world' ,' lottie' ,' ecStat' ,
837- ' 3D' ,' liquid' ,' gmodular' ,' wordcloud' )]
873+ unk <- load [! load %in% c(' leaflet' ,' custom' ,' world' ,' lottie' ,' ecStat' ,' 3D' ,' gmodular' ,' liquid' ,' wordcloud' )]
838874 if (length(unk )> 0 ) {
839875 for (pg in unk )
840876 wt <- ec.plugjs(wt , pg , ask )
@@ -1450,7 +1486,6 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
14501486 )
14511487 }
14521488 else { # download it
1453- # if (ask=='loadRemote') ask <- FALSE
14541489 path <- system.file(' js' , package = ' echarty' )
14551490
14561491 ffull <- paste0(path ,' /' ,fname )
@@ -1498,6 +1533,7 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
14981533 x
14991534 }
15001535 doEncode <- function (el ) { # for tooltip, seriesName, itemId, itemName, itemGroupId, itemChildGroupId
1536+ # should be defined as vector, not list; ex: tooltip= c(2,3), not tooltip= list(2,3)
15011537 for (i in seq_along(el $ encode )) {
15021538 if (! is.numeric(el $ encode [[i ]])) next
15031539 el $ encode [[i ]] <- el $ encode [[i ]] - 1
0 commit comments