rshinyecharts4r

How to add an animation using dispatchAction to a chart?


I would like to insert this animation using echarts4r:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Pie Chart Example</title>
      <!-- Include ECharts library -->
      <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.0/echarts.min.js"></script>
    </head>
    <body>
    
    <!-- Container for the chart -->
    <div id="chart-container" style="width: 600px; height: 400px;"></div>
    
    <script>
      // Your JavaScript code goes here
    
      // Define the option object
      var option = {
        tooltip: {
          trigger: 'item',
          formatter: '{a} <br/>{b} : {c} ({d}%)'
        },
        legend: {
          orient: 'vertical',
          left: 'left',
          data: [
            'Direct Access',
            'Email Marketing',
            'Affiliate Ads',
            'Video Ads',
            'Search Engines'
          ]
        },
        series: [
          {
            name: 'Access Source',
            type: 'pie',
            radius: '55%',
            center: ['50%', '60%'],
            data: [
              { value: 335, name: 'Direct Access' },
              { value: 310, name: 'Email Marketing' },
              { value: 234, name: 'Affiliate Ads' },
              { value: 135, name: 'Video Ads' },
              { value: 1548, name: 'Search Engines' }
            ],
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
              }
            }
          }
        ]
      };
    
      // Create a chart using the provided option
      var myChart = echarts.init(document.getElementById('chart-container'));
      myChart.setOption(option);
    
      // Set up the interval function
      let currentIndex = -1;
    
      setInterval(function() {
        var dataLen = option.series[0].data.length;
        myChart.dispatchAction({
          type: 'downplay',
          seriesIndex: 0,
          dataIndex: currentIndex
        });
        currentIndex = (currentIndex + 1) % dataLen;
        myChart.dispatchAction({
          type: 'highlight',
          seriesIndex: 0,
          dataIndex: currentIndex
        });
        myChart.dispatchAction({
          type: 'showTip',
          seriesIndex: 0,
          dataIndex: currentIndex
        });
      }, 1000);
    
    </script>
    
    </body>
    </html> 

See more.

I tried this:

library(shiny)
library(echarts4r)

ui <- fluidPage(
  echarts4rOutput(outputId = "chart1"),
  actionButton(inputId = "btn1", label = "Click")
)

server <- function(input, output, session) {
  output$chart1 <- renderEcharts4r({
    mtcars |>
      head() |>
      tibble::rownames_to_column("model") |> 
      e_charts(model, elementId = "chart-container") |>
      e_pie(carb) |>
      e_tooltip()
  })
  
  observe({
    req(input$btn1)
    
    HTML(
      " // Create a chart using the provided option
      var chart1 = echarts.init(document.getElementById('chart-container'));
      chart1.setOption(option);

      // Set up the interval function
      var currentIndex = -1;

      setInterval(function() {
        var dataLen = option.series[0].data.length;
        chart1.dispatchAction({
          type: 'downplay',
          seriesIndex: 0,
          dataIndex: currentIndex
        });
        currentIndex = (currentIndex + 1) % dataLen;
        chart1.dispatchAction({
          type: 'highlight',
          seriesIndex: 0,
          dataIndex: currentIndex
        });
        chart1.dispatchAction({
          type: 'showTip',
          seriesIndex: 0,
          dataIndex: currentIndex
        });
      }, 1000);"
    )
  }) 
}

shinyApp(ui, server)
 

But it did not work.

How to apply this effect to a chart with the echarts4r package?

I would also like to add a stop button, to stop the animation. But I can't even get it to work by clicking on the created button.


Solution

  • Here is a possibility which uses some minor modifications of your provided JS for the animation and shinyjs in order to handle the click events of the buttons. I also implemented your desired button for stopping the animation.

    enter image description here

    library(shiny)
    library(shinyjs)
    library(echarts4r)
    
    js_init <- "
              var chart1 = echarts.init(document.getElementById('chart1'));
              option = document.getElementById('chart1').htmlwidget_data_init_result.getOpts();
              chart1.setOption(option);
    "
    
    js_run_anim <- "
          var currentIndex = -1;
    
          anim = setInterval(function() {
            var dataLen = option.series[0].data.length;
            chart1.dispatchAction({
              type: 'downplay',
              seriesIndex: 0,
              dataIndex: currentIndex
            });
            currentIndex = (currentIndex + 1) % dataLen;
            chart1.dispatchAction({
              type: 'highlight',
              seriesIndex: 0,
              dataIndex: currentIndex
            });
            chart1.dispatchAction({
              type: 'showTip',
              seriesIndex: 0,
              dataIndex: currentIndex
            });
          }, 1000);
    
          document.getElementById('btn1').setAttribute('disabled', 'disabled');
          document.getElementById('btn2').removeAttribute('disabled');
          document.getElementById('btn2').setAttribute('enabled', 'enabled');
    "
    
    js_stop_anim <- "
              clearInterval(anim);
    
              var dataLen = option.series[0].data.length;
              chart1.dispatchAction({
                type: 'downplay',
                seriesIndex: 0 ,
                dataIndex: [...Array(dataLen).keys()]
              });
              chart1.dispatchAction({
                type: 'hideTip',
                seriesIndex: 0 ,
                dataIndex: [...Array(dataLen).keys()]
              });
    
              document.getElementById('btn1').removeAttribute('disabled');
              document.getElementById('btn1').setAttribute('enabled', 'enabled');
              document.getElementById('btn2').setAttribute('disabled', 'disabled');
    "
    
    ui <- fluidPage(
        useShinyjs(),
        echarts4rOutput(outputId = "chart1"),
        actionButton(inputId = "btn1", label = "Start animation"),
        actionButton(inputId = "btn2", label = "Stop animation")
    )
    
    server <- function(input, output, session) {
        output$chart1 <- renderEcharts4r({
            mtcars |>
                head() |>
                tibble::rownames_to_column("model") |>
                e_charts(model) |>
                e_pie(carb) |>
                e_tooltip()
        })
        
        observeEvent(input$btn1, {
            onclick("btn1", runjs(paste0(js_init, js_run_anim)))
        }, ignoreNULL = FALSE)
        
        observeEvent(input$btn2, {
            onclick("btn2", runjs(paste0(js_init, js_stop_anim)))
        }, ignoreNULL = FALSE)
    }
    
    shinyApp(ui, server)