Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom feature save with watermark #450

Open
yogat3ch opened this issue Aug 5, 2022 · 0 comments
Open

Custom feature save with watermark #450

yogat3ch opened this issue Aug 5, 2022 · 0 comments

Comments

@yogat3ch
Copy link
Contributor

yogat3ch commented Aug 5, 2022

Hi @JohnCoene ,
How are you doing?
We've been getting more into the inner workings of echarts4r and are attempting to make a custom toolbox feature that saves the image with a watermark.
I feel like we're getting close but not quite there.
Do you have any tips for how to move forward from here?

Using an old example from my maximize question from a while back:

library(shiny)

e_saveAsImage_filename = function(e, name = "chart_download.png", watermark = TRUE) {
  out <- echarts4r::e_toolbox_feature(e, feature = "saveAsImage", name = name)
  if (watermark) {
    onclick <- "function () {
          var ecModel = this.ecModel;
          ecModel.setOption({
            graphic : [
              {
                  type: 'group',
                  rotation: Math.PI / 4,
                  bounding: 'raw',
                  right: '10%',
                  bottom: '10%',
                  z: 100,
                  children: [
                      {
                          type: 'rect',
                          left: 'center',
                          top: 'center',
                          z: 100,
                          shape: {
                              width: 400,
                              height: 50
                          },
                          style: {
                              fill: 'rgba(0,0,0,0.3)'
                          }
                      },
                      {
                          type: 'text',
                          left: 'center',
                          top: 'center',
                          z: 100,
                          style: {
                              fill: '#fff',
                              text: 'ECHARTS LINE CHART',
                              font: 'bold 26px sans-serif'
                          }
                      }
                  ]
              }
          ]
      });
    debugger;
        const model = this.model;
        const api = this.api;
        const title = model.get('name') || ecModel.get('title.0.text') || 'echarts';
        const isSvg = api.getZr().painter.getType() === 'svg';
        const type = isSvg ? 'svg' : model.get('type', true) || 'png';
        const url = api.getDataURL({
            type: type,
            backgroundColor: model.get('backgroundColor', true)
                || ecModel.get('backgroundColor') || '#fff',
            connectedBackgroundColor: model.get('connectedBackgroundColor'),
            excludeComponents: model.get('excludeComponents'),
            pixelRatio: model.get('pixelRatio')
        });
        const browser = env.browser;
        // Chrome, Firefox, New Edge
        if (isFunction(MouseEvent) && (browser.newEdge || (!browser.ie && !browser.edge))) {
            const $a = document.createElement('a');
            $a.download = title + '.' + type;
            $a.target = '_blank';
            $a.href = url;
            const evt = new MouseEvent('click', {
                // some micro front-end framework, window maybe is a Proxy
                view: document.defaultView,
                bubbles: true,
                cancelable: false
            });
            $a.dispatchEvent(evt);
        }
    }"
    out <- echarts4r::e_toolbox_feature(e, feature = "myWatermark", show = TRUE, onclick = htmlwidgets::JS(onclick), title = "Dl with Watermark", icon = 'image://https://echarts.apache.org/en/images/favicon.png')
  }
  return(out)
}


ui <- bs4Dash::dashboardPage(
  header = bs4Dash::dashboardHeader(disable = TRUE),
  body = bs4Dash::dashboardBody(
    tags$script(
      "$(function(){
        $('#card1').find('[data-card-widget=\"maximize\"]').on('click', function() {
           $('#plot').resize();
        });
      });"
    ),
    shiny::fluidRow(
      bs4Dash::bs4Card(id = "card1", plotly::plotlyOutput("plot"), width = 4, maximizable = TRUE),
      bs4Dash::bs4Card(echarts4r::echarts4rOutput("chart"), width = 4, maximizable = TRUE),
      bs4Dash::bs4Card(width = 4)
    )
  ),
  sidebar = bs4Dash::bs4DashSidebar(disable = TRUE)
)

# Define server logic required to draw a histogram
server <- function(input, output) {

  # generate bins based on input$bins from ui.R
  p <- iris |>
    dplyr::group_by(Species) |>
    echarts4r::e_charts(x = Petal.Width) |>
    echarts4r::e_line(Petal.Length, symbol = "none") |>
    echarts4r::e_y_axis(scale = TRUE) |>
    #echarts4r::e_band2(lower = Sepal.Length, upper = Sepal.Width, itemStyle = list(opacity = 0.4)) |>
    echarts4r::e_tooltip(trigger = "axis") |>
    echarts4r::e_datazoom() |>
    echarts4r::e_toolbox(orient = "vertical", itemSize = 10) |>
    e_saveAsImage_filename()
  # setting outputs
  output$chart <- echarts4r::renderEcharts4r(p)

  output$plot <- plotly::renderPlotly({
    plotly::plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
  })

}

# Run the application
shinyApp(ui = ui, server = server)

Here's the onclick function with syntax highlighting:

function () {
          var ecModel = this.ecModel;
    // from https://echarts.apache.org/examples/en/editor.html?c=line-graphic&edit=1&reset=1
          ecModel.setOption({
            graphic : [
              {
                  type: 'group',
                  rotation: Math.PI / 4,
                  bounding: 'raw',
                  right: '10%',
                  bottom: '10%',
                  z: 100,
                  children: [
                      {
                          type: 'rect',
                          left: 'center',
                          top: 'center',
                          z: 100,
                          shape: {
                              width: 400,
                              height: 50
                          },
                          style: {
                              fill: 'rgba(0,0,0,0.3)'
                          }
                      },
                      {
                          type: 'text',
                          left: 'center',
                          top: 'center',
                          z: 100,
                          style: {
                              fill: '#fff',
                              text: 'ECHARTS LINE CHART',
                              font: 'bold 26px sans-serif'
                          }
                      }
                  ]
              }
          ]
      });
    debugger;
    // from https://github.com/apache/echarts/blob/dfa1f0732972e358a3711c75b5f41db741e986b6/src/component/toolbox/feature/SaveAsImage.ts#L50
        const model = this.model;
        const api = this.api;
        const title = model.get('name') || ecModel.get('title.0.text') || 'echarts';
        const isSvg = api.getZr().painter.getType() === 'svg';
        const type = isSvg ? 'svg' : model.get('type', true) || 'png';
        const url = api.getDataURL({
            type: type,
            backgroundColor: model.get('backgroundColor', true)
                || ecModel.get('backgroundColor') || '#fff',
            connectedBackgroundColor: model.get('connectedBackgroundColor'),
            excludeComponents: model.get('excludeComponents'),
            pixelRatio: model.get('pixelRatio')
        });
        const browser = env.browser;
        // Chrome, Firefox, New Edge
        if (isFunction(MouseEvent) && (browser.newEdge || (!browser.ie && !browser.edge))) {
            const $a = document.createElement('a');
            $a.download = title + '.' + type;
            $a.target = '_blank';
            $a.href = url;
            const evt = new MouseEvent('click', {
                // some micro front-end framework, window maybe is a Proxy
                view: document.defaultView,
                bubbles: true,
                cancelable: false
            });
            $a.dispatchEvent(evt);
        }
    }

I'm getting the error :
echarts-en.min.js:45 Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
From this bit:

  const url = api.getDataURL({
            type: type,
            backgroundColor: model.get('backgroundColor', true)
                || ecModel.get('backgroundColor') || '#fff',
            connectedBackgroundColor: model.get('connectedBackgroundColor'),
            excludeComponents: model.get('excludeComponents'),
            pixelRatio: model.get('pixelRatio')
        });

An aside, it appears that echarts4r::e_toolbox_feature only allows for overwrite of the entire toolbox option. Maybe a merge argument would be helpful here if folks want to add to rather than replace existing toolbox features?

Any ideas will be appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant