@@ -47,18 +47,17 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
4747# '
4848# ' **Widget attributes** \cr
4949# ' Optional echarty widget attributes include: \cr
50- # ' * elementId - Id of the widget, default is NULL(auto-generated)
50+ # ' * elementId - Id of the widget, default is NULL(auto-generated, stored as _echwid_ variable for JS )
5151# ' * load - name(s) of plugin(s) to load. A character vector or comma-delimited string. default NULL.
5252# ' * ask - prompt user before downloading plugins when _load_ is present, FALSE by default
5353# ' * js - single string or a vector with JavaScript expressions to evaluate.\cr
5454# ' single: exposed _chart_ object (most common)\cr
5555# ' vector: \verb{ }see code in \href{https://github.com/helgasoft/echarty/blob/main/demo/examples.R}{examples}\cr
56- # ' \verb{ }First expression evaluated before initialization, exposed object _window_ \cr
56+ # ' \verb{ }First expression evaluated with exposed objects _window_ and _echarts_ \cr
5757# ' \verb{ }Second is evaluated with exposed object _opts_. \cr
58- # ' \verb{ }Third is evaluated with exposed _chart_ object after _opts_ set.
59- # ' * renderer - 'canvas'(default) or 'svg'
60- # ' * locale - 'EN'(default) or 'ZH'. Use predefined or custom \href{https://gist.github.com/helgasoft/0618c6537c45bfd9e86d3f9e1da497b8}{like so}.
61- # ' * useDirtyRect - enable dirty rectangle rendering or not, FALSE by default, see \href{https://echarts.apache.org/en/api.html#echarts.init}{here}\cr
58+ # ' \verb{ }Third is evaluated with exposed _chart_ object after initialization with _opts_ already set.
59+ # ' * iniOpts - a list of initialization options, see _opts_ in \href{https://echarts.apache.org/en/api.html#echarts.init}{echarts.init}\cr
60+ # ' \verb{ }Defaults: renderer='canvas', locale='EN', useDirtyRect=FALSE\cr
6261# '
6362# ' **Built-in plugins** \cr
6463# ' * leaflet - Leaflet maps with customizable tiles, see \href{https://github.com/gnijuohz/echarts-leaflet#readme}{source}\cr
@@ -100,8 +99,15 @@ noCoord <- c('polar','radar','singleAxis','parallelAxis','calendar')
10099# ' @return A widget to plot, or to save and expand with more features.
101100# '
102101# ' @examples
103- # ' # basic scatter chart from a data.frame, using presets
102+ # ' # basic scatter chart from a data.frame using presets
104103# ' cars |> ec.init()
104+ # '
105+ # ' # custom inititlization options and theme
106+ # ' cars |> ec.init(
107+ # ' iniOpts= list(renderer= 'svg', width= '222px'),
108+ # ' toolbox= list(feature= list(saveAsImage= list()))
109+ # ' ) |> ec.theme('mine', code= # theme code JSON
110+ # ' '{"color": ["green"], "backgroundColor": "lemonchiffon"}' )
105111# '
106112# ' # grouping, tooltips, formatting
107113# ' iris |> dplyr::group_by(Species) |>
@@ -134,28 +140,27 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
134140 elementId <- if (is.null(opt1 $ elementId )) NULL else opt1 $ elementId
135141 js <- if (is.null(opt1 $ js )) NULL else opt1 $ js
136142 ask <- if (is.null(opt1 $ ask )) FALSE else opt1 $ ask
137- renderer <- if (is.null(opt1 $ renderer )) ' canvas' else tolower(opt1 $ renderer )
138- locale <- if (is.null(opt1 $ locale )) ' EN' else toupper(opt1 $ locale )
139- useDirtyRect <- if (is.null(opt1 $ useDirtyRect )) FALSE else opt1 $ useDirtyRect
143+ iniOpts <- if (! is.null(opt1 $ iniOpts )) opt1 $ iniOpts else list ()
144+ # for backward compatibility:
145+ if (is.null(iniOpts $ renderer )) iniOpts $ renderer <- if (is.null(opt1 $ renderer )) ' canvas' else tolower(opt1 $ renderer )
146+ if (is.null(iniOpts $ locale )) iniOpts $ locale <- if (is.null(opt1 $ locale )) ' EN' else toupper(opt1 $ locale )
147+ if (is.null(iniOpts $ useDirtyRect )) iniOpts $ useDirtyRect <- if (is.null(opt1 $ useDirtyRect )) FALSE else opt1 $ useDirtyRect
148+
140149 xtKey <- if (is.null(opt1 $ xtKey )) ' XkeyX' else opt1 $ xtKey
141150 # allow debug feedback thru cat() in JS and R code:
142151 dbg <- if (is.null(opt1 $ dbg )) FALSE else opt1 $ dbg
143152 # remove the above attributes since they are not valid ECharts options
144- opt1 $ ask <- opt1 $ js <- opt1 $ renderer <- opt1 $ locale <- NULL
145- opt1 $ useDirtyRect <- opt1 $ elementId <- opt1 $ xtKey <- opt1 $ dbg <- NULL
153+ opt1 $ renderer <- opt1 $ locale <- opt1 $ useDirtyRect <- opt1 $ iniOpts <- NULL
154+ opt1 $ ask <- opt1 $ js <- opt1 $ elementId <- opt1 $ xtKey <- opt1 $ dbg <- NULL
146155 axis2d <- c(' pictorialBar' ,' candlestick' ,' boxplot' ,' scatterGL' ) # 'custom',
147156 isCrosstalk <- FALSE ; deps <- NULL
148157
149158 # forward widget options using x
150159 x <- list (
151160 theme = ' ' ,
152- draw = TRUE ,
153- renderer = renderer ,
154- locale = locale ,
155- useDirtyRect = useDirtyRect ,
161+ iniOpts = iniOpts ,
156162 jcode = js , dbg = dbg ,
157163 opts = opt1
158- # settings= list( crosstalk_key= key, crosstalk_group= group )
159164 )
160165
161166 doType <- function (idx , axx ) {
@@ -488,14 +493,39 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
488493 opt1 <- wt $ x $ opts
489494 load <- opt1 $ load ; wt $ x $ opts $ load <- NULL
490495 if (length(load )== 1 && grepl(' ,' , load , fixed = TRUE ))
491- load <- unlist(strsplit(load , ' ,' ))
496+ load <- unlist(strsplit(load , ' ,' )) # make 'load' a vector
497+ # series.param has been merged into series
498+ if (dbg ) cat(' \n series=' ,unlist(opt1 $ series ))
499+
492500 # autoload 3D
493501 cnd1 <- any(c(' xAxis3D' ,' yAxis3D' ,' zAxis3D' ,' grid3D' ,' globe' ,' geo3D' ) %in% names(opt1 ))
494- styp <- ctype
495- if (! is.null( series.param ) && ! is.null( series.param $ type ) )
496- styp <- series.param $ type
497- cnd2 <- any(endsWith(styp , c(' 3D' ,' GL' )))
502+ cnd2 <- ! is.null( opt1 $ series )
503+ if (cnd2 )
504+ cnd2 <- length( opt1 $ series [sapply( opt1 $ series ,
505+ \( x ) any(endsWith(x $ type , c(' 3D' ,' GL' ))) )] ) > 0
498506 if ((cnd1 || cnd2 ) && ! ' 3D' %in% load ) load <- c(load , ' 3D' )
507+
508+ # autoload 'world' - for geo OR series
509+ cnd1 <- ! is.null(opt1 $ geo ); cnd2 <- FALSE
510+ if (cnd1 && ! is.null(opt1 $ geo $ map ))
511+ cnd2 <- opt1 $ geo $ map == ' world'
512+ if (! cnd1 || ! cnd2 ) { # series
513+ cnd1 <- ! is.null(opt1 $ series ); cnd2 <- FALSE
514+ if (cnd1 ) {
515+ # search series for type=='map', map=='world'
516+ tmc <- 0
517+ cnd2 <- opt1 $ series [sapply(opt1 $ series , \(x ) {
518+ if (' map' %in% names(x )) {
519+ if (! is.null(x $ type ) && x $ type == ' map' ) tmc <<- tmc + 1
520+ x $ map == ' world' } else FALSE
521+ })]
522+ cnd2 <- length(cnd2 )== 1
523+ if (cnd2 ) stopifnot(" type=='map' missing in series" = tmc == 1 )
524+ }
525+ }
526+ if (cnd1 && cnd2 ) {
527+ if (! ' world' %in% load ) load <- c(load , ' world' )
528+ }
499529
500530 path <- system.file(' js' , package = ' echarty' )
501531 dep <- NULL
@@ -574,6 +604,18 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
574604 wt $ dependencies <- append(wt $ dependencies , list (dep ))
575605 }
576606 if (' ecStat' %in% load ) {
607+ # add registration if missing in wt$x$jcode
608+ jreg <- paste(lapply(list (' histogram' ,' regression' ,' clustering' ,' statistics' ),
609+ \(x ) { paste0(' echarts.registerTransform(ecStat.transform.' ,x ,' )' ) }), collapse = ' ;' )
610+ if (! is.null(js )) {
611+ if (! grepl(" registerTransform" , js , fixed = TRUE )[[1 ]]) {
612+ if (length(js )== 1 ) js <- c(jreg ,' ' ,js )
613+ else js [[1 ]] <- paste(js [[1 ]], jreg )
614+ wt $ x $ jcode <- js
615+ }
616+ } else
617+ wt $ x $ jcode <- c(jreg ,' ' ,' ' )
618+
577619 dep <- htmltools :: htmlDependency(
578620 name = ' ecStat' , version = ' 1.0.0' ,
579621 src = c(file = path ), script = ' ecStat.min.js' )
@@ -585,14 +627,17 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
585627 plf <- read.csv(system.file(' plugins.csv' , package = ' echarty' ), header = TRUE , stringsAsFactors = FALSE )
586628 if (' 3D' %in% load ) {
587629 if (preset ) { # replace 2D presets with 3D
588- isGL <- any(unlist(lapply(opt1 $ series , \(k ){ endsWith(k $ type , ' GL' ) }))) # all GL are 2D
589- if (! isGL ) isGL <- endsWith(styp , ' GL' )
630+ isGL <- any(unlist(lapply(opt1 $ series , \(k ){ endsWith(k $ type , ' GL' ) }))) # GL is 2D
590631 isMap3d <- ! is.null(opt1 $ globe ) || ! is.null(opt1 $ geo3D )
591632 if (isMap3d ) isGL <- FALSE
592- if (! isGL ) {
633+ if (! isGL ) {
634+ # replace 2D types with 3D if any
635+ wt $ x $ opts $ series <- lapply(opt1 $ series , \(ss ) {
636+ if (ss $ type %in% c(' scatter' ,' bar' ,' line' )) ss $ type <- paste0(ss $ type ,' 3D' )
637+ ss
638+ })
593639 # check for series types ending in 3D or GL
594- stypes <- ifelse(! is.null(series.param ), styp ,
595- unlist(lapply(opt1 $ series , \(k ){k $ type })) )
640+ stypes <- unlist(lapply(wt $ x $ opts $ series , \(k ){k $ type }))
596641 stypes <- stypes [stypes != ' surface' ]
597642 if (! is.null(stypes )) stopifnot(" Non-3D series type detected" = all(endsWith(stypes , ' 3D' )) )
598643 if (! isMap3d ) {
@@ -766,7 +811,7 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
766811 } else
767812 wt $ x $ opts $ timeline <- .merlis(wt $ x $ opts $ timeline , list (data = steps , axisType = ' category' ))
768813
769- return ( wt )
814+ wt
770815}
771816
772817
@@ -783,18 +828,20 @@ ec.init <- function( df= NULL, preset= TRUE, ctype= 'scatter', ...,
783828# ' @examples
784829# ' library(dplyr)
785830# ' df <- data.frame(x= 1:30, y= runif(30, 5, 10), cat= sample(LETTERS[1:3],size=30,replace=TRUE)) |>
786- # ' mutate(lwr= y-runif(30, 1, 3), upr= y+runif(30, 2, 4))
831+ # ' mutate(lwr= y-runif(30, 1, 3), upr= y+runif(30, 2, 4))
787832# ' band.df <- df |> group_by(cat) |> group_split()
833+ # ' sband <- list()
834+ # ' for(ii in 1:length(band.df)) # build all bands
835+ # ' sband <- append(sband,
836+ # ' ecr.band(band.df[[ii]], 'lwr', 'upr', type='stack', smooth=FALSE,
837+ # ' name= unique(band.df[[ii]]$cat), areaStyle= list(color=c('blue','green','yellow')[ii]))
838+ # ' )
788839# '
789840# ' df |> group_by(cat) |>
790841# ' ec.init(load='custom', ctype='line',
791842# ' xAxis=list(data=c(0,unique(df$x)), boundaryGap=FALSE) ) |>
792- # ' ec.upd({
793- # ' for(ii in 1:length(band.df)) # add bands to their respective groups
794- # ' series <- append(series,
795- # ' ecr.band(band.df[[ii]], 'lwr', 'upr', type='stack', smooth=FALSE,
796- # ' name= unique(band.df[[ii]]$cat), areaStyle= list(color=c('blue','green','yellow')[ii])) )
797- # ' })
843+ # ' ec.upd({ series <- append(series, sband) })
844+ # '
798845# ' @export
799846ec.upd <- function (wt , ... ) {
800847 stopifnot(' ec.upd: expecting wt as echarty widget' = inherits(wt , ' echarty' ))
@@ -1211,7 +1258,7 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
12111258 stopifnot(' ec.plugjs: expecting source as URL or file://' =
12121259 startsWith(source , ' http' ) || startsWith(source , ' file://' ))
12131260 if (! .valid.url(source )) { # CRAN does not like stopifnot errors
1214- wt $ x $ opts $ title <- list (text = ' ERROR ec.plugjs: source is invalid!' )
1261+ wt $ x $ opts <- list (title = list ( text = paste0( ' ec.plugjs: source " ' , source , ' " is invalid!' )) )
12151262 return (wt )
12161263 }
12171264 fname <- basename(source )
@@ -1254,19 +1301,21 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
12541301
12551302# convert from R to JS numbering
12561303.renumber <- function (opa ) {
1257-
1304+ doEncode <- function (el ) {
1305+ for (i in 1 : length(el $ encode )) {
1306+ if (! is.numeric(el $ encode [[i ]])) next
1307+ el $ encode [[i ]] <- el $ encode [[i ]] - 1
1308+ }
1309+ el
1310+ }
12581311 r2jsEncode <- function (ss ) {
12591312
1260- if (any(names(ss )== ' encode' )) {
1261- for (i in 1 : length(ss $ encode )) {
1262- if (! is.numeric(ss $ encode [[i ]])) next
1263- ss $ encode [[i ]] <- ss $ encode [[i ]] - 1
1264- }
1265- }
1266- if (! ss $ type %in% noAxis ) {
1313+ if (any(names(ss )== ' encode' )) ss <- doEncode(ss )
1314+
1315+ # if (!is.null(ss$type) && !ss$type %in% noAxis) {
12671316 if (! is.null(ss $ xAxisIndex )) ss $ xAxisIndex <- ss $ xAxisIndex - 1
12681317 if (! is.null(ss $ yAxisIndex )) ss $ yAxisIndex <- ss $ yAxisIndex - 1
1269- }
1318+ # }
12701319 if (! is.null(ss $ datasetIndex )) ss $ datasetIndex <- ss $ datasetIndex - 1
12711320 if (! is.null(ss $ geoIndex )) ss $ geoIndex <- ss $ geoIndex - 1
12721321 if (! is.null(ss $ polarIndex )) ss $ polarIndex <- ss $ polarIndex - 1
@@ -1275,8 +1324,11 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
12751324 ss
12761325 }
12771326
1278- if (! is.null(opa $ series ))
1279- opa $ series <- lapply(opa $ series , r2jsEncode )
1327+ if (! is.null(opa $ series )) opa $ series <- lapply(opa $ series , r2jsEncode )
1328+ if (! is.null(opa $ dataZoom )) {
1329+ if (all(sapply(opa $ dataZoom , is.list ))) opa $ dataZoom <- lapply(opa $ dataZoom , r2jsEncode )
1330+ else opa $ dataZoom <- r2jsEncode(opa $ dataZoom )
1331+ }
12801332
12811333 decro <- function (x ) {
12821334 if (! is.null(x $ dimension ) && is.numeric(x $ dimension )) x $ dimension <- x $ dimension - 1
@@ -1317,7 +1369,7 @@ ec.plugjs <- function(wt=NULL, source=NULL, ask=FALSE) {
13171369# validate URL (https:// or file://)
13181370.valid.url <- function (durl , tsec = 2 ){
13191371 con <- url(durl )
1320- check <- suppressWarnings(try(open.connection(con ,open = " rt" ,timeout = tsec ),silent = TRUE )[1 ])
1372+ check <- suppressWarnings(try(open.connection(con , open = " rt" , timeout = tsec ),silent = TRUE )[1 ])
13211373 suppressWarnings(try(close.connection(con ),silent = TRUE ))
13221374 ifelse(is.null(check ),TRUE ,FALSE )
13231375}
0 commit comments