export { PlotlyCustomModeBar }
/**
* Class extending plotly's mode bar functionality.
*/
class PlotlyCustomModeBar {
/**
* Create a custom plotly mode bar.
* @param {HTMLElement} graphDiv - Plotly graphDiv configuration.
* @param {Array} [data=[]] - Plotly data configuration.
* @param {Object} [layout={}] - Plotly layout configuration.
* @param {Object} [config={}] - Plotly config configuration.
*/
constructor(graphDiv, data = [], layout = {}, config = {}) {
this.graphDiv = graphDiv;
this.data = data;
this.layout = layout;
this.config = config;
this.customButtons = [];
}
/**
* Register custom buttons by providing their plotly button configuration.
* @param {Array} buttonList - Containing plotly's button objects.
*/
registerCustomButtons(buttonList = []) {
this.customButtons = this.customButtons.concat(buttonList);
this.insertCustomButton();
}
_getActiveButtons() {
const buttonsToRemove = [].concat(this.layout?.modebar?.remove, this.config?.modeBarButtonsToRemove);
const buttonsToAdd = [].concat(this.layout?.modebar?.add, this.config?.modeBarButtonsToAdd);
const buttonsToRemoveFlat = buttonsToRemove.flat();
const buttonsToAddFlat = buttonsToAdd.flat();
return [buttonsToAddFlat, buttonsToRemoveFlat];
}
/**
* Check if a button is configured to be visible in plotly's mode bar.
* @param {String} buttonName - Name of the button.
* @returns {Boolean} Status.
*/
isButtonRequested(buttonName) {
const [buttonsToAddFlat, buttonsToRemoveFlat] = this._getActiveButtons();
if (buttonsToAddFlat.includes(buttonName) && !buttonsToRemoveFlat.includes(buttonName))
return true;
return false;
}
/**
* Set the order in which the buttons appear in Plotly's mode bar.
*
* @implNote: This method applies the predefined button order with respect to plotly's add (A) and remove button variables (B).
* It uses plotly's "modeBarButton" configuration, that in contrast to this method, does not take A and B into account.
* Consequently, when buttons should be ordered, the current plotly version is not sufficient enough for vef's plotly inheritance.
* @param {Array} defaultButtonOrder - List containing the sorted button names.
*/
applyButtonOrder(defaultButtonOrder) {
const modeBarButtons = this.config?.modeBarButtons;
if (modeBarButtons?.length > 1) {
console.warn('Plotly variable "modeBarButton" is already defined, no ordering of buttons based on preset');
return;
}
const [buttonsToAddFlat, buttonsToRemoveFlat] = this._getActiveButtons();
buttonsToAddFlat.sort((a, b) => {
return defaultButtonOrder.indexOf(a.name || a) - defaultButtonOrder.indexOf(b.name || b);
});
const setModeBarButtons = buttonsToAddFlat.reduce((acc, curr, idx) => {
if (!buttonsToRemoveFlat.includes(curr))
acc.push([curr]);
return acc;
}, []);
this.config.modeBarButtons = setModeBarButtons;
}
/**
* 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.
*/
insertCustomButton() {
if (this.layout?.modebar?.add)
this.layout.modebar.add = this._insertCustomButton(this.layout?.modebar?.add);
if (this.config?.modeBarButtonsToAdd)
this.config.modeBarButtonsToAdd = this._insertCustomButton(this.config?.modeBarButtonsToAdd);
if (this.config?.modeBarButtons)
this.config.modeBarButtons = this._insertCustomButton(this.config?.modeBarButtons);
}
_insertCustomButton(buttonList) {
if (buttonList && buttonList.length > 0) {
const buttonListCollect = [];
buttonList.forEach((buttonGroup) => {
if (!Array.isArray(buttonGroup)) buttonGroup = [buttonGroup];
const buttonGroupCollect = [];
buttonGroup.forEach((button) => {
const matchedCustomButton = this.customButtons.find(item => item.name == button);
if (matchedCustomButton) button = matchedCustomButton;
buttonGroupCollect.push(button);
});
if (buttonGroupCollect.length > 0)
buttonListCollect.push(buttonGroupCollect);
});
buttonList = buttonListCollect;
}
return buttonList;
}
}