diff --git a/NAMESPACE b/NAMESPACE index e25acbd..86db466 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -60,6 +60,7 @@ export(run_demo_input) export(run_demo_sparkbox) export(run_demo_sync) export(set_input_click) +export(set_input_export) export(set_input_selection) export(set_input_zoom) export(set_tooltip_fixed) diff --git a/R/shiny-input.R b/R/shiny-input.R index ff4f1c5..d5b25f3 100644 --- a/R/shiny-input.R +++ b/R/shiny-input.R @@ -169,6 +169,35 @@ set_input_selection <- function(ax, inputId, type = c("x", "xy", "y"), +#' Retrieve chart's base64 dataURI. +#' +#' @param ax An \code{apexcharts} \code{htmlwidget} object. +#' @param inputId The id that will be used server-side for retrieving data. +#' @param session The Shiny session. +#' +#' @return An \code{apexcharts} \code{htmlwidget} object. +#' @export +#' +#' @example examples/export-2.R +set_input_export <- function(ax, inputId, + session = shiny::getDefaultReactiveDomain()) { + if (is.null(session)) + session <- list(ns = identity) + ax$x$shinyEvents$export <- list( + inputId = session$ns(inputId) + ) + ax +} + + + + + + +# Demo -------------------------------------------------------------------- + + + #' Run Shiny input events examples #' #' @param example Name of the example. diff --git a/examples/export-2.R b/examples/export-2.R new file mode 100644 index 0000000..7433d87 --- /dev/null +++ b/examples/export-2.R @@ -0,0 +1,47 @@ +library(shiny) +library(apexcharter) + +ui <- fluidPage( + fluidRow( + column( + width = 8, offset = 2, + tags$h2("Export PNG"), + actionButton("redraw", "Redraw chart"), + apexchartOutput("chart"), + verbatimTextOutput("result"), + uiOutput(outputId = "image") + ) + ) +) + +server <- function(input, output, session) { + + output$chart <- renderApexchart({ + input$redraw + apexchart() %>% + ax_chart(type = "bar") %>% + ax_series( + list( + name = "Example", + data = sample(1:100, 5) + ) + ) %>% + ax_xaxis( + categories = LETTERS[1:5] + ) %>% + set_input_export("export") + }) + + output$result <- renderPrint({ + input$export + }) + + output$image <- renderUI({ + tags$img(src = input$export) + }) + +} + +if (interactive()) + shinyApp(ui, server) + diff --git a/examples/export.R b/examples/export.R new file mode 100644 index 0000000..dc4c7b4 --- /dev/null +++ b/examples/export.R @@ -0,0 +1,59 @@ +library(shiny) +library(apexcharter) + +ui <- fluidPage( + fluidRow( + column( + width = 8, offset = 2, + tags$h2("Export PNG"), + actionButton("redraw", "Redraw chart"), + apexchartOutput("chart"), + downloadButton("download", "Download PNG"), + verbatimTextOutput("result"), + uiOutput(outputId = "image") + ) + ) +) + +server <- function(input, output, session) { + + output$chart <- renderApexchart({ + input$redraw + apexchart() %>% + ax_chart(type = "bar") %>% + ax_series( + list( + name = "Example", + data = sample(1:100, 5) + ) + ) %>% + ax_xaxis( + categories = LETTERS[1:5] + ) %>% + set_input_export("export") + }) + + output$result <- renderPrint({ + input$export + }) + + output$download <- downloadHandler( + filename = function() { + "apexcharts.png" + }, + content = function(file) { + img <- input$export$imgURI + raw <- base64enc::base64decode(what = gsub("data:image/png;base64,", "", img, fixed = TRUE)) + png::writePNG(png::readPNG(raw), file) + } + ) + + output$image <- renderUI({ + tags$img(src = input$export) + }) + +} + +if (interactive()) + shinyApp(ui, server) + diff --git a/inst/htmlwidgets/apexcharter.js b/inst/htmlwidgets/apexcharter.js index c4faf25..32ed06d 100644 --- a/inst/htmlwidgets/apexcharter.js +++ b/inst/htmlwidgets/apexcharter.js @@ -110,6 +110,18 @@ function getXaxis(axis) { return xzoom; } +function exportChart(x, chart) { + if (x.hasOwnProperty("shinyEvents") & HTMLWidgets.shinyMode) { + if (x.shinyEvents.hasOwnProperty("export")) { + setTimeout(function() { + chart.dataURI().then(function(imgURI) { + Shiny.setInputValue(x.shinyEvents.export.inputId, imgURI); + }); + }, 1000); + } + } +} + /// Widget HTMLWidgets.widget({ @@ -125,7 +137,7 @@ HTMLWidgets.widget({ renderValue: function(x) { // Global options axOpts = x.ax_opts; - + if (x.sparkbox) { el.style.background = x.sparkbox.background; el.classList.add("apexcharter-spark-box"); @@ -143,7 +155,7 @@ HTMLWidgets.widget({ if (!axOpts.chart.hasOwnProperty("parentHeightOffset")) { axOpts.chart.parentHeightOffset = 0; } - + // added events to remove minheight container if (!axOpts.chart.hasOwnProperty("events")) { axOpts.chart.events = {}; @@ -246,26 +258,38 @@ HTMLWidgets.widget({ // Generate or update chart if (apexchart === null) { apexchart = new ApexCharts(el, axOpts); - apexchart.render(); + apexchart.render().then(function() { + exportChart(x, apexchart); + }); } else { if (x.auto_update) { //console.log(x.auto_update); - apexchart.updateSeries(axOpts.series, x.auto_update.series_animate); + apexchart + .updateSeries(axOpts.series, x.auto_update.series_animate) + .then(function(chart) { + exportChart(x, chart); + }); if (x.auto_update.update_options) { delete axOpts.series; delete axOpts.chart.width; delete axOpts.chart.height; - apexchart.updateOptions( - axOpts, - x.auto_update.options_redrawPaths, - x.auto_update.options_animate, - x.auto_update.update_synced_charts - ); + apexchart + .updateOptions( + axOpts, + x.auto_update.options_redrawPaths, + x.auto_update.options_animate, + x.auto_update.update_synced_charts + ) + .then(function(a, b) { + exportChart(x, chart); + }); } } else { apexchart.destroy(); apexchart = new ApexCharts(el, axOpts); - apexchart.render(); + apexchart.render().then(function() { + exportChart(x, apexchart); + }); } } }, diff --git a/man/set_input_export.Rd b/man/set_input_export.Rd new file mode 100644 index 0000000..ade04b3 --- /dev/null +++ b/man/set_input_export.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/shiny-input.R +\name{set_input_export} +\alias{set_input_export} +\title{Retrieve chart's base64 dataURI.} +\usage{ +set_input_export(ax, inputId, session = shiny::getDefaultReactiveDomain()) +} +\arguments{ +\item{ax}{An \code{apexcharts} \code{htmlwidget} object.} + +\item{inputId}{The id that will be used server-side for retrieving data.} + +\item{session}{The Shiny session.} +} +\value{ +An \code{apexcharts} \code{htmlwidget} object. +} +\description{ +Retrieve chart's base64 dataURI. +} +\examples{ +library(shiny) +library(apexcharter) + +ui <- fluidPage( + fluidRow( + column( + width = 8, offset = 2, + tags$h2("Export PNG"), + actionButton("redraw", "Redraw chart"), + apexchartOutput("chart"), + verbatimTextOutput("result"), + uiOutput(outputId = "image") + ) + ) +) + +server <- function(input, output, session) { + + output$chart <- renderApexchart({ + input$redraw + apexchart() \%>\% + ax_chart(type = "bar") \%>\% + ax_series( + list( + name = "Example", + data = sample(1:100, 5) + ) + ) \%>\% + ax_xaxis( + categories = LETTERS[1:5] + ) \%>\% + set_input_export("export") + }) + + output$result <- renderPrint({ + input$export + }) + + output$image <- renderUI({ + tags$img(src = input$export) + }) + +} + +if (interactive()) + shinyApp(ui, server) + +}