Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to switch between different modeBarButtons in plotly.js

I've created 2 custom buttons (icons) for my Plotly.js modeBar: play and pause.

I want to switch/toggle between this icons and I'm able to do it, however I'm not happy with the result and would like to know if there is a better way without calling Plotly again.

const paused = false

// Custom icons
const play = {
  name: 'Pause',
  icon: {
    width: 500,
    height: 500,
    path: 'M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z',
  },
  click: () => Plotly.plot(chart, [], {}, { modeBarButtonsToAdd: [pause] })
}

const pause = {
  name: 'Play',
  icon: {
    width: 500,
    height: 500,
    path: 'M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z',
  },
  click: () => Plotly.plot(chart, [], {}, { modeBarButtonsToAdd: [play] })
}

// Chart
const plot = Plotly.plot(chart, [{
  x: [1, 2, 3, 4],
  y: [10, 15, 13, 17],
  type: 'scatter'
}], {}, { 
  displaylogo: false,
  displayModeBar: true,
  modeBarButtonsToAdd: [paused ? pause : play]  
})
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="chart"></div>

Run the above snippet and click on the last icon.

Also, I implemented another version using the .active class and setting the icons with CSS but again would like to figure out how Plotly.js experts solve this.

like image 270
gengns Avatar asked Jan 01 '26 08:01

gengns


1 Answers

Plotly has some features it ought to document, that it uses internally to make modeBarButtons easier to manage from code. You can leverage those features to make this easier. I cover this here as well on the Plotly forum.

There's a secret modeBarButton attr you can use to easily target the generated button from CSS and Javascript. From there you can swap your icon very easily.

https://jsfiddle.net/b9chris/yd5pxb47/

First you'll need a custom button. You can either add the button via modeBarAddButtons, or, manually insert it and take over the ordering of the buttons directly. In this example I'm using the manual method, since it's the only way to control the order of the buttons - which you'll usually want to do:

modeBarButtons: [[
    {
        name: 'download',
        attr: 'download',
        title: 'Download as Image',
        icon: {
            width: 10, height: 10,
            path: 'M5,1 L5,8 L2,5 L5,8 L8,5 M2,9 L8,9'
        },
        click: onClickDownloadImage
    }
    ],['zoom2d', 'pan2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d'
]]

This property is on the plotlyConfig object you'll be passing as the 4th argument to plotly's newPlot() function.

In this case it's a download button but, you can put in your play button or whatever.

Because the attr property has been set, the modebar button is going to render out like:

<a data-attr=download ...><svg class=icon ...><path d="(icon path)"/></svg></a>

Meaning you can target it with CSS and selectors in JS like:

#graph div.modebar a[data-attr=download]

In my silly example, after downloading the icon becomes a checkmark, like so:

function onClickDownloadImage(gd) {
  . . .
  
  var buttonPath = $('#graph div.modebar a[data-attr=download] svg path');
  buttonPath.attr('d', 'M1,5 L5,9 L9,1');
};

So it just grabs the path from the button onclick, and swaps in some new path data. But you could keep path datas in a library and swap them, or however you want to approach it.

like image 100
Chris Moschini Avatar answered Jan 02 '26 20:01

Chris Moschini



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!