Source: plot/buttons/PlotlyCustomModeBar.js

  1. export { PlotlyCustomModeBar }
  2. /**
  3. * Class extending plotly's mode bar functionality.
  4. */
  5. class PlotlyCustomModeBar {
  6. /**
  7. * Create a custom plotly mode bar.
  8. * @param {HTMLElement} graphDiv - Plotly graphDiv configuration.
  9. * @param {Array} [data=[]] - Plotly data configuration.
  10. * @param {Object} [layout={}] - Plotly layout configuration.
  11. * @param {Object} [config={}] - Plotly config configuration.
  12. */
  13. constructor(graphDiv, data = [], layout = {}, config = {}) {
  14. this.graphDiv = graphDiv;
  15. this.data = data;
  16. this.layout = layout;
  17. this.config = config;
  18. this.customButtons = [];
  19. }
  20. /**
  21. * Register custom buttons by providing their plotly button configuration.
  22. * @param {Array} buttonList - Containing plotly's button objects.
  23. */
  24. registerCustomButtons(buttonList = []) {
  25. this.customButtons = this.customButtons.concat(buttonList);
  26. this.insertCustomButton();
  27. }
  28. _getActiveButtons() {
  29. const buttonsToRemove = [].concat(this.layout?.modebar?.remove, this.config?.modeBarButtonsToRemove);
  30. const buttonsToAdd = [].concat(this.layout?.modebar?.add, this.config?.modeBarButtonsToAdd);
  31. const buttonsToRemoveFlat = buttonsToRemove.flat();
  32. const buttonsToAddFlat = buttonsToAdd.flat();
  33. return [buttonsToAddFlat, buttonsToRemoveFlat];
  34. }
  35. /**
  36. * Check if a button is configured to be visible in plotly's mode bar.
  37. * @param {String} buttonName - Name of the button.
  38. * @returns {Boolean} Status.
  39. */
  40. isButtonRequested(buttonName) {
  41. const [buttonsToAddFlat, buttonsToRemoveFlat] = this._getActiveButtons();
  42. if (buttonsToAddFlat.includes(buttonName) && !buttonsToRemoveFlat.includes(buttonName))
  43. return true;
  44. return false;
  45. }
  46. /**
  47. * Set the order in which the buttons appear in Plotly's mode bar.
  48. *
  49. * @implNote: This method applies the predefined button order with respect to plotly's add (A) and remove button variables (B).
  50. * It uses plotly's "modeBarButton" configuration, that in contrast to this method, does not take A and B into account.
  51. * Consequently, when buttons should be ordered, the current plotly version is not sufficient enough for vef's plotly inheritance.
  52. * @param {Array} defaultButtonOrder - List containing the sorted button names.
  53. */
  54. applyButtonOrder(defaultButtonOrder) {
  55. const modeBarButtons = this.config?.modeBarButtons;
  56. if (modeBarButtons?.length > 1) {
  57. console.warn('Plotly variable "modeBarButton" is already defined, no ordering of buttons based on preset');
  58. return;
  59. }
  60. const [buttonsToAddFlat, buttonsToRemoveFlat] = this._getActiveButtons();
  61. buttonsToAddFlat.sort((a, b) => {
  62. return defaultButtonOrder.indexOf(a.name || a) - defaultButtonOrder.indexOf(b.name || b);
  63. });
  64. const setModeBarButtons = buttonsToAddFlat.reduce((acc, curr, idx) => {
  65. if (!buttonsToRemoveFlat.includes(curr))
  66. acc.push([curr]);
  67. return acc;
  68. }, []);
  69. this.config.modeBarButtons = setModeBarButtons;
  70. }
  71. /**
  72. * Replace the names of the custom buttons with the button object. Thus, the names of custom button can be used in the plotly configuration instead of the button object.
  73. */
  74. insertCustomButton() {
  75. if (this.layout?.modebar?.add)
  76. this.layout.modebar.add = this._insertCustomButton(this.layout?.modebar?.add);
  77. if (this.config?.modeBarButtonsToAdd)
  78. this.config.modeBarButtonsToAdd = this._insertCustomButton(this.config?.modeBarButtonsToAdd);
  79. if (this.config?.modeBarButtons)
  80. this.config.modeBarButtons = this._insertCustomButton(this.config?.modeBarButtons);
  81. }
  82. _insertCustomButton(buttonList) {
  83. if (buttonList && buttonList.length > 0) {
  84. const buttonListCollect = [];
  85. buttonList.forEach((buttonGroup) => {
  86. if (!Array.isArray(buttonGroup)) buttonGroup = [buttonGroup];
  87. const buttonGroupCollect = [];
  88. buttonGroup.forEach((button) => {
  89. const matchedCustomButton = this.customButtons.find(item => item.name == button);
  90. if (matchedCustomButton) button = matchedCustomButton;
  91. buttonGroupCollect.push(button);
  92. });
  93. if (buttonGroupCollect.length > 0)
  94. buttonListCollect.push(buttonGroupCollect);
  95. });
  96. buttonList = buttonListCollect;
  97. }
  98. return buttonList;
  99. }
  100. }