highcharts
Version:
JavaScript charting framework
338 lines (337 loc) • 11.1 kB
JavaScript
/* *
*
* (c) 2010-2024 Mateusz Bernacik
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import Chart from '../../Core/Chart/Chart.js';
import Navigator from './Navigator.js';
import G from '../../Core/Globals.js';
import U from '../../Core/Utilities.js';
import Axis from '../../Core/Axis/Axis.js';
import standaloneNavigatorDefaults from './StandaloneNavigatorDefaults.js';
const { merge, addEvent, fireEvent, pick } = U;
/* *
*
* Class
*
* */
/**
* The StandaloneNavigator class. The StandaloneNavigator class allows for
* creating a standalone navigator component that synchronizes the extremes
* across multiple bound charts.
*
* @class
* @name Highcharts.StandaloneNavigator
*
* @param {string|Highcharts.HTMLDOMElement} [renderTo]
* The DOM element to render to, or its id.
*
* @param {StandaloneNavigatorOptions} userOptions
* The standalone navigator options.
*/
class StandaloneNavigator {
/* *
*
* Static Functions
*
* */
/**
* Factory function for standalone navigator.
*
* @function Highcharts.navigator
*
* @param {string|Highcharts.HTMLDOMElement} [renderTo]
* The DOM element to render to, or its id.
*
* @param {StandaloneNavigatorOptions} options
* The standalone navigator options with chart-like structure.
*
* Returns the navigator object.
*/
static navigator(renderTo, options) {
const nav = new StandaloneNavigator(renderTo, options);
if (!G.navigators) {
G.navigators = [nav];
}
else {
G.navigators.push(nav);
}
return nav;
}
/* *
*
* Constructor
*
* */
constructor(element, userOptions) {
this.boundAxes = [];
this.userOptions = userOptions;
this.chartOptions = merge(G.getOptions(), standaloneNavigatorDefaults, { navigator: userOptions });
if (this.chartOptions.chart && userOptions.height) {
this.chartOptions.chart.height = userOptions.height;
}
const chart = new Chart(element, this.chartOptions);
chart.options = merge(chart.options, { navigator: { enabled: true }, scrollbar: { enabled: true } });
if (this.chartOptions.navigator && this.chartOptions.scrollbar) {
this.chartOptions.navigator.enabled = true;
this.chartOptions.scrollbar.enabled = true;
}
this.navigator = new Navigator(chart);
chart.navigator = this.navigator;
this.initNavigator();
}
/**
* Binds an axis to the standalone navigator,
* allowing the navigator to control the axis' range.
*
* @sample stock/standalone-navigator/bind/
* Bind chart with a button
*
* @function Highcharts.StandaloneNavigator#bind
*
* @param {Axis | Chart} axisOrChart
* The Axis or Chart to bind to the navigator.
*
* @param {boolean} [twoWay=true]
* Enables two-way binding between the navigator and the axis/chart.
* When true, changes in the navigator's range will update the axis
* and vice versa. When false, changes in the navigator's range will
* be reflected in the axis, but changes in the axis ranges won't be
* reflected on the navigator.
*/
bind(axisOrChart, twoWay = true) {
const nav = this;
// If the chart is passed, bind the first xAxis
const axis = (axisOrChart instanceof Chart) ?
axisOrChart.xAxis[0] :
axisOrChart;
if (!(axis instanceof Axis)) {
return;
}
const { min, max } = this.navigator.xAxis, removeEventCallbacks = [];
if (twoWay) {
const removeSetExtremesEvent = addEvent(axis, 'setExtremes', (e) => {
if (e.trigger === 'pan' ||
e.trigger === 'zoom' ||
e.trigger === 'mouseWheelZoom') {
nav.setRange(e.min, e.max, true, e.trigger !== 'pan', { trigger: axis });
}
});
removeEventCallbacks.push(removeSetExtremesEvent);
}
const removeSetRangeEvent = addEvent(this.navigator, 'setRange', (e) => {
axis.setExtremes(e.min, e.max, e.redraw, e.animation);
});
removeEventCallbacks.push(removeSetRangeEvent);
let boundAxis = this.boundAxes.filter(function (boundAxis) {
return boundAxis.axis === axis;
})[0];
if (!boundAxis) {
boundAxis = { axis, callbacks: [] };
this.boundAxes.push(boundAxis);
}
boundAxis.callbacks = removeEventCallbacks;
// Show axis' series in navigator based on showInNavigator property
axis.series.forEach((series) => {
if (series.options.showInNavigator) {
nav.addSeries(series.options);
}
});
// Set extremes to match the navigator's extremes
axis.setExtremes(min, max);
// Unbind the axis before it's destroyed
addEvent(axis, 'destroy', (e) => {
if (!e.keepEvents) {
this.unbind(axis);
}
});
}
/**
* Unbinds a single axis or all bound axes from the standalone navigator.
*
* @sample stock/standalone-navigator/unbind/
* Unbind chart with a button
*
* @function Highcharts.StandaloneNavigator#unbind
*
* @param {Chart | Axis | undefined} axisOrChart
* Passing a Chart object unbinds the first X axis of the chart,
* an Axis object unbinds that specific axis,
* and undefined unbinds all axes bound to the navigator.
*/
unbind(axisOrChart) {
// If no axis or chart is provided, unbind all bound axes
if (!axisOrChart) {
this.boundAxes.forEach(({ callbacks }) => {
callbacks.forEach((removeCallback) => removeCallback());
});
this.boundAxes.length = 0;
return;
}
const axis = (axisOrChart instanceof Axis) ?
axisOrChart :
axisOrChart.xAxis[0];
for (let i = this.boundAxes.length - 1; i >= 0; i--) {
if (this.boundAxes[i].axis === axis) {
this.boundAxes[i].callbacks.forEach((callback) => callback());
this.boundAxes.splice(i, 1);
}
}
}
/**
* Destroys allocated standalone navigator elements.
*
* @function Highcharts.StandaloneNavigator#destroy
*/
destroy() {
// Disconnect events
this.boundAxes.forEach(({ callbacks }) => {
callbacks.forEach((removeCallback) => removeCallback());
});
this.boundAxes.length = 0;
this.navigator.destroy();
this.navigator.chart.destroy();
}
/**
* Updates the standalone navigator's options with a new set of user
* options.
*
* @sample stock/standalone-navigator/update/
* Bind chart with a button
*
* @function Highcharts.StandaloneNavigator#update
*
* @param {StandaloneNavigatorOptions} newOptions
* Updates the standalone navigator's options with new user options.
*
* @param {boolean | undefined} redraw
* Whether to redraw the standalone navigator. By default, if not
* specified, the standalone navigator will be redrawn.
*/
update(newOptions, redraw) {
this.chartOptions = merge(this.chartOptions, newOptions.height && { chart: { height: newOptions.height } }, { navigator: newOptions });
this.navigator.chart.update(this.chartOptions, redraw);
}
/**
* Redraws the standalone navigator.
*
* @function Highcharts.StandaloneNavigator#redraw
*/
redraw() {
this.navigator.chart.redraw();
}
/**
* Adds a series to the standalone navigator.
*
* @private
*
* @param {SeriesOptions} seriesOptions
* Options for the series to be added to the navigator.
*/
addSeries(seriesOptions) {
this.navigator.chart.addSeries(merge(seriesOptions, { showInNavigator: pick(seriesOptions.showInNavigator, true) }));
this.navigator.setBaseSeries();
}
/**
* Initialize the standalone navigator.
*
* @private
*/
initNavigator() {
const nav = this.navigator;
nav.top = 1;
nav.xAxis.setScale();
nav.yAxis.setScale();
nav.xAxis.render();
nav.yAxis.render();
nav.series?.forEach((s) => {
s.translate();
s.render();
s.redraw();
});
const { min, max } = this.getInitialExtremes();
nav.chart.xAxis[0].userMin = min;
nav.chart.xAxis[0].userMax = max;
nav.render(min, max);
}
/**
* Get the current range of the standalone navigator.
*
* @sample stock/standalone-navigator/getrange/
* Report the standalone navigator's range by clicking on a button
*
* @function Highcharts.StandaloneNavigator#getRange
*
* @return {Highcharts.ExtremesObject}
* The current range of the standalone navigator.
*/
getRange() {
const { min, max } = this.navigator.chart.xAxis[0].getExtremes(), { userMin, userMax, min: dataMin, max: dataMax } = this.navigator.xAxis.getExtremes();
return {
min: pick(min, dataMin),
max: pick(max, dataMax),
dataMin,
dataMax,
userMin,
userMax
};
}
/**
* Set the range of the standalone navigator.
*
* @sample stock/standalone-navigator/setrange/
* Set range from a button
*
* @function Highcharts.StandaloneNavigator#setRange
*
* @param {number | undefined} min
* The new minimum value.
*
* @param {number | undefined} max
* The new maximum value.
*
* @emits Highcharts.StandaloneNavigator#event:setRange
*/
setRange(min, max, redraw, animation, eventArguments) {
fireEvent(this.navigator, 'setRange', {
min,
max,
redraw,
animation,
eventArguments: merge(eventArguments, { trigger: 'navigator' })
});
}
/**
* Get the initial, options based extremes for the standalone navigator.
*
* @private
*
* @return {{ min: number, max: number }}
* The initial minimum and maximum extremes values.
*/
getInitialExtremes() {
const { min, max } = this.navigator.xAxis.getExtremes();
return {
min: min,
max: max
};
}
}
export default StandaloneNavigator;
/* *
*
* API Declarations
*
* */
/**
* Standalone Navigator options.
*
* @interface Highcharts.StandaloneNavigatorOptions
*/ /**
*/
''; // Detach doclets above