mirror of
https://github.com/beestat/app.git
synced 2025-05-24 02:14:03 -04:00
814 lines
21 KiB
JavaScript
814 lines
21 KiB
JavaScript
/**
|
|
* A chart. Mostly just a wrapper for the Highcharts stuff so the defaults
|
|
* don't have to be set every single time.
|
|
*/
|
|
beestat.component.chart = function() {
|
|
var self = this;
|
|
|
|
this.addEventListener('render', function() {
|
|
self.reflow();
|
|
});
|
|
|
|
beestat.component.apply(this, arguments);
|
|
};
|
|
beestat.extend(beestat.component.chart, beestat.component);
|
|
|
|
beestat.component.chart.charts_ = [];
|
|
|
|
/**
|
|
* Decorate. Calls all the option getters and renders the chart.
|
|
*
|
|
* @param {rocket.Elements} parent
|
|
*/
|
|
beestat.component.chart.prototype.decorate_ = function(parent) {
|
|
const self = this;
|
|
|
|
const options = {};
|
|
|
|
options.credits = this.get_options_credits_();
|
|
options.exporting = this.get_options_exporting_();
|
|
options.chart = this.get_options_chart_();
|
|
options.title = this.get_options_title_();
|
|
options.subtitle = this.get_options_subtitle_();
|
|
options.legend = this.get_options_legend_();
|
|
options.plotOptions = this.get_options_plotOptions_();
|
|
options.xAxis = this.get_options_xAxis_();
|
|
options.yAxis = this.get_options_yAxis_();
|
|
options.series = this.get_options_series_();
|
|
options.tooltip = this.get_options_tooltip_();
|
|
options.boost = this.get_options_boost_();
|
|
|
|
options.chart.renderTo = parent[0];
|
|
|
|
this.chart_ = Highcharts.chart(options);
|
|
|
|
this.addEventListener('render', function() {
|
|
/**
|
|
* Clean up old charts. Charts only get added to this array once they
|
|
* actually get rendered to the page, so it's safe to assume that if they
|
|
* no longer exist in the DOM they can be destroyed.
|
|
*/
|
|
for (let i = beestat.component.chart.charts_.length - 1; i >= 0; i--) {
|
|
if (document.body.contains(beestat.component.chart.charts_[i].chart_.container) === false) {
|
|
beestat.component.chart.charts_[i].chart_.destroy();
|
|
beestat.component.chart.charts_.splice(i, 1);
|
|
}
|
|
}
|
|
|
|
// Add this chart to the charts list.
|
|
beestat.component.chart.charts_.push(self);
|
|
});
|
|
|
|
this.docked_tooltip_container_ = $.createElement('div');
|
|
this.docked_tooltip_container_.style({
|
|
'margin-top': (beestat.style.size.gutter / 2) + 'px'
|
|
});
|
|
parent.appendChild(this.docked_tooltip_container_);
|
|
};
|
|
|
|
/**
|
|
* Reset the chart zoom level all the way out.
|
|
*/
|
|
beestat.component.chart.prototype.reset_zoom = function() {
|
|
this.chart_.zoomOut();
|
|
};
|
|
|
|
/**
|
|
* Export the chart to a PNG.
|
|
*/
|
|
beestat.component.chart.prototype.export = function() {
|
|
this.chart_.exportChartLocal();
|
|
};
|
|
|
|
/**
|
|
* Get the legend options.
|
|
*
|
|
* @return {object} The legend options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_legend_ = function() {
|
|
return {
|
|
'enabled': this.get_options_legend_enabled_(),
|
|
'itemStyle': {
|
|
'color': '#ecf0f1',
|
|
'font-weight': '500'
|
|
},
|
|
'itemHoverStyle': {
|
|
'color': '#bdc3c7'
|
|
},
|
|
'itemHiddenStyle': {
|
|
'color': '#7f8c8d'
|
|
},
|
|
'labelFormatter': this.get_options_legend_labelFormatter_()
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the legend labelFormatter options.
|
|
*
|
|
* @return {Function} The legend labelFormatter options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_legend_labelFormatter_ = function() {
|
|
return function() {
|
|
return beestat.series[this.name].name;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the legend enabled options.
|
|
*
|
|
* @return {Function} The legend enabled options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_legend_enabled_ = function() {
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Get the plotOptions.
|
|
*
|
|
* @return {object} The plotOptions.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_plotOptions_ = function() {
|
|
var self = this;
|
|
|
|
return {
|
|
'series': {
|
|
'animation': false,
|
|
'marker': {
|
|
'enabled': false
|
|
},
|
|
'states': {
|
|
'hover': {
|
|
'enabled': false
|
|
},
|
|
'inactive': {
|
|
'opacity': 1
|
|
}
|
|
},
|
|
'connectNulls': this.get_options_plotOptions_series_connectNulls_(),
|
|
'events': {
|
|
'legendItemClick': function() {
|
|
// Delay the event dispatch so the series is actually toggled to the correct visibility.
|
|
window.setTimeout(function() {
|
|
self.dispatchEvent('legend_item_click');
|
|
}, 0);
|
|
}
|
|
},
|
|
'borderRadius': {
|
|
'radius': 0
|
|
}
|
|
},
|
|
'column': {
|
|
'pointPadding': 0,
|
|
'borderWidth': 0,
|
|
'stacking': 'normal',
|
|
'dataLabels': {
|
|
'enabled': false
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get whether or not to connect nulls.
|
|
*
|
|
* @return {boolean} Whether or not to connect nulls.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_plotOptions_series_connectNulls_ = function() {
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Get the title options.
|
|
*
|
|
* @return {object} The title options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_title_ = function() {
|
|
return {
|
|
'text': null
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the subtitle options
|
|
*
|
|
* @return {object} The subtitle options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_subtitle_ = function() {
|
|
return {
|
|
'text': null
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the chart options.
|
|
*
|
|
* @return {object} The chart options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_ = function() {
|
|
return {
|
|
'style': {
|
|
'fontFamily': 'Montserrat'
|
|
},
|
|
'spacing': this.get_options_chart_spacing_(),
|
|
// For consistent left spacing on charts with no y-axis values
|
|
'marginLeft': this.get_options_chart_marginLeft_(),
|
|
'marginRight': this.get_options_chart_marginRight_(),
|
|
'marginBottom': this.get_options_chart_marginBottom_(),
|
|
'zoomType': this.get_options_chart_zoomType_(),
|
|
'panning': true,
|
|
'panKey': 'ctrl',
|
|
'backgroundColor': beestat.style.color.bluegray.base,
|
|
'resetZoomButton': {
|
|
'theme': {
|
|
'style': {
|
|
'display': 'none'
|
|
}
|
|
}
|
|
},
|
|
'height': this.get_options_chart_height_(),
|
|
'events': this.get_options_chart_events_()
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the left margin for the chart.
|
|
*
|
|
* @return {number} The left margin for the chart.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_marginLeft_ = function() {
|
|
return undefined;
|
|
};
|
|
|
|
/**
|
|
* Get the right margin for the chart.
|
|
*
|
|
* @return {number} The right margin for the chart.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_marginRight_ = function() {
|
|
return undefined;
|
|
};
|
|
|
|
/**
|
|
* Get the bottom margin for the chart.
|
|
*
|
|
* @return {number} The right margin for the chart.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_marginBottom_ = function() {
|
|
return undefined;
|
|
};
|
|
|
|
/**
|
|
* Get the spacing for the chart.
|
|
*
|
|
* @return {number} The spacing for the chart.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_spacing_ = function() {
|
|
return [
|
|
(beestat.style.size.gutter / 2),
|
|
0,
|
|
0,
|
|
0
|
|
];
|
|
};
|
|
|
|
/**
|
|
* Get the events list for the chart.
|
|
*
|
|
* @return {number} The events list for the chart.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_events_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the height of the chart.
|
|
*
|
|
* @return {number} The height of the chart.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_height_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the zoomType option. Return null for no zoom.
|
|
*
|
|
* @return {string} The zoom type.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_chart_zoomType_ = function() {
|
|
return 'x';
|
|
};
|
|
|
|
/**
|
|
* Get the export options.
|
|
*
|
|
* @return {object} The export options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_exporting_ = function() {
|
|
return {
|
|
'enabled': false,
|
|
'sourceWidth': 980,
|
|
'scale': 1,
|
|
'filename': this.get_options_exporting_filename_(),
|
|
'chartOptions': {
|
|
'credits': {
|
|
'text': 'beestat.io'
|
|
},
|
|
'title': {
|
|
'align': 'left',
|
|
'text': this.get_options_exporting_chartOptions_title_text_(),
|
|
'margin': beestat.style.size.gutter,
|
|
'style': {
|
|
'color': '#fff',
|
|
'font-weight': beestat.style.font_weight.bold,
|
|
'font-size': beestat.style.font_size.large
|
|
}
|
|
},
|
|
'subtitle': {
|
|
'align': 'left',
|
|
'text': this.get_options_exporting_chartOptions_subtitle_text_(),
|
|
'style': {
|
|
'color': '#fff',
|
|
'font-weight': beestat.style.font_weight.light,
|
|
'font-size': beestat.style.font_size.normal
|
|
}
|
|
},
|
|
'chart': {
|
|
'style': {
|
|
'fontFamily': 'Montserrat, Helvetica, Sans-Serif'
|
|
},
|
|
'spacing': [
|
|
beestat.style.size.gutter,
|
|
beestat.style.size.gutter,
|
|
beestat.style.size.gutter,
|
|
beestat.style.size.gutter
|
|
],
|
|
'events': this.get_options_exporting_chart_events_()
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the exported chart title.
|
|
*
|
|
* @return {string} The exported chart title.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_exporting_chartOptions_title_text_ = function() {
|
|
return this.data_.metadata.chart.title;
|
|
};
|
|
|
|
/**
|
|
* Get the exported chart subtitle.
|
|
*
|
|
* @return {string} The exported chart subtitle.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_exporting_chartOptions_subtitle_text_ = function() {
|
|
return this.data_.metadata.chart.subtitle;
|
|
};
|
|
|
|
/**
|
|
* Get the exported chart filename.
|
|
*
|
|
* @return {string} The exported chart filename.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_exporting_filename_ = function() {
|
|
var title = this.get_options_exporting_chartOptions_title_text_();
|
|
var subtitle = this.get_options_exporting_chartOptions_subtitle_text_();
|
|
|
|
var filename = [];
|
|
if (title !== null) {
|
|
filename.push(title);
|
|
}
|
|
|
|
if (subtitle !== null) {
|
|
filename.push('-');
|
|
filename.push(subtitle);
|
|
}
|
|
|
|
if (filename.length === 0) {
|
|
filename.push('beestat');
|
|
}
|
|
|
|
return filename.join(' ');
|
|
};
|
|
|
|
/**
|
|
* Get the events list for the chart on export.
|
|
*
|
|
* @return {string} The events list for the chart on export.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_exporting_chart_events_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the credits options.
|
|
*
|
|
* @return {boolean} The credits options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_credits_ = function() {
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Get the xAxis options.
|
|
*
|
|
* @return {object} The xAxis options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_xAxis_ = function() {
|
|
var self = this;
|
|
|
|
return {
|
|
'categories': this.data_.x,
|
|
'lineColor': beestat.style.color.bluegray.light,
|
|
'tickLength': 0,
|
|
'labels': {
|
|
'style': {
|
|
'color': beestat.style.color.gray.base,
|
|
'font-size': '12px'
|
|
},
|
|
'formatter': this.get_options_xAxis_labels_formatter_()
|
|
},
|
|
'crosshair': this.get_options_xAxis_crosshair_(),
|
|
'events': {
|
|
'afterSetExtremes': function() {
|
|
self.dispatchEvent('after_set_extremes');
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the crosshair.
|
|
*
|
|
* @return {object} The crosshair.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_xAxis_crosshair_ = function() {
|
|
return {
|
|
'width': this.get_options_xAxis_crosshair_width_(),
|
|
'zIndex': 100,
|
|
'color': 'rgba(255, 255, 255, 0.2)',
|
|
'snap': this.get_options_xAxis_crosshair_snap_()
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the crosshair width.
|
|
*
|
|
* @return {object} The crosshair width.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_xAxis_crosshair_width_ = function() {
|
|
return 2;
|
|
};
|
|
|
|
/**
|
|
* Get the crosshair snap.
|
|
*
|
|
* @return {object} The crosshair snap.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_xAxis_crosshair_snap_ = function() {
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Get the xAxis label formatter options. Needs to be overridden.
|
|
*
|
|
* @return {object} The xAxis label formatter options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_xAxis_labels_formatter_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the yAxis label formatter options. Needs to be overridden.
|
|
*
|
|
* @return {object} The yAxis label formatter options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_yAxis_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the series options. Needs to be overridden.
|
|
*
|
|
* @return {object} The series options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_series_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the tooltip options.
|
|
*
|
|
* @return {object} The tooltip options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_tooltip_ = function() {
|
|
return {
|
|
'shared': true,
|
|
'useHTML': true,
|
|
'borderWidth': 0,
|
|
'shadow': false,
|
|
'backgroundColor': null,
|
|
'followPointer': true,
|
|
'hideDelay': 1,
|
|
'positioner': this.get_options_tooltip_positioner_(),
|
|
'formatter': this.get_options_tooltip_formatter_()
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the tooltip formatter. Needs to be overridden.
|
|
*
|
|
* @return {Function} The tooltip formatter.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_tooltip_formatter_ = function() {
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Get the tooltip positioner. Makes sure the tooltip is positioned nicely.
|
|
*
|
|
* @return {Function} The tooltip positioner.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_tooltip_positioner_ = function() {
|
|
var self = this;
|
|
return function(tooltip_width, tooltip_height, point) {
|
|
return {
|
|
'x': self.get_options_tooltip_positioner_x_(tooltip_width, tooltip_height, point),
|
|
'y': self.get_options_tooltip_positioner_y_(tooltip_width, tooltip_height, point)
|
|
};
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the tooltip positioner x value. This remembers which way you're moving
|
|
* the mouse and attempts to position the tooltip out of the way of the
|
|
* direction of movement.
|
|
*
|
|
* @param {number} tooltip_width Tooltip width.
|
|
* @param {number} tooltip_height Tooltip height.
|
|
* @param {point} point Highcharts current point.
|
|
*
|
|
* @return {number} The tooltip x value.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_tooltip_positioner_x_ = function(tooltip_width, tooltip_height, point) {
|
|
const plot_width = this.chart_.plotWidth;
|
|
|
|
const tooltip_x_history_size = 20;
|
|
if (this.last_tooltip_x_ === undefined) {
|
|
this.last_tooltip_x_ = [];
|
|
}
|
|
|
|
this.last_tooltip_x_.push(point.plotX);
|
|
if (this.last_tooltip_x_.length > tooltip_x_history_size) {
|
|
this.last_tooltip_x_.shift();
|
|
}
|
|
|
|
const prefer_left = this.last_tooltip_x_[0] <= this.last_tooltip_x_[this.last_tooltip_x_.length - 1];
|
|
|
|
const fits_on_left = (point.plotX - tooltip_width) > 0;
|
|
const fits_on_right = (point.plotX + tooltip_width) < plot_width;
|
|
|
|
let x;
|
|
|
|
if (fits_on_left === false && fits_on_right === false) {
|
|
x = this.chart_.plotLeft;
|
|
} else {
|
|
if (prefer_left === true) {
|
|
if (fits_on_left === true) {
|
|
x = point.plotX - tooltip_width + this.chart_.plotLeft;
|
|
} else {
|
|
x = point.plotX + this.chart_.plotLeft;
|
|
}
|
|
} else {
|
|
if (fits_on_right === true) {
|
|
x = point.plotX + this.chart_.plotLeft;
|
|
} else {
|
|
x = point.plotX - tooltip_width + this.chart_.plotLeft;
|
|
}
|
|
}
|
|
}
|
|
|
|
return x;
|
|
};
|
|
|
|
/**
|
|
* Get the tooltip positioner y value.
|
|
*
|
|
* @param {number} tooltip_width Tooltip width.
|
|
* @param {number} tooltip_height Tooltip height.
|
|
* @param {point} point Highcharts current point.
|
|
*
|
|
* @return {number} The tooltip y value.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_tooltip_positioner_y_ = function(tooltip_width, tooltip_height, point) {
|
|
return 60;
|
|
};
|
|
|
|
/**
|
|
* Get the HTML needed to render a tooltip.
|
|
*
|
|
* @param {string} title The tooltip title.
|
|
* @param {array} sections Data inside the tooltip.
|
|
*
|
|
* @return {string} The tooltip HTML.
|
|
*/
|
|
beestat.component.chart.prototype.tooltip_formatter_helper_ = function(title, sections) {
|
|
var tooltip = $.createElement('div')
|
|
.style({
|
|
'background-color': beestat.style.color.bluegray.dark,
|
|
'padding': beestat.style.size.gutter / 2,
|
|
'border-radius': beestat.style.size.border_radius,
|
|
'box-shadow': '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)'
|
|
});
|
|
|
|
if (title !== null) {
|
|
var title_div = $.createElement('div')
|
|
.style({
|
|
'font-weight': beestat.style.font_weight.bold,
|
|
'font-size': beestat.style.font_size.large,
|
|
'margin-bottom': beestat.style.size.gutter / 4,
|
|
'color': beestat.style.color.gray.light
|
|
})
|
|
.innerText(title);
|
|
tooltip.appendChild(title_div);
|
|
}
|
|
|
|
var table = $.createElement('table')
|
|
.setAttribute({
|
|
'cellpadding': '0',
|
|
'cellspacing': '0'
|
|
});
|
|
tooltip.appendChild(table);
|
|
|
|
sections.forEach(function(section, i) {
|
|
if (section.length > 0) {
|
|
section.forEach(function(item) {
|
|
var tr = $.createElement('tr').style('color', item.color);
|
|
table.appendChild(tr);
|
|
|
|
var td_label = $.createElement('td')
|
|
.style({
|
|
'font-weight': beestat.style.font_weight.bold,
|
|
'font-size': '12px',
|
|
'line-height': '12px'
|
|
})
|
|
.innerText(item.label);
|
|
tr.appendChild(td_label);
|
|
|
|
var td_value = $.createElement('td').innerText(item.value)
|
|
.style({
|
|
'padding-left': beestat.style.size.gutter / 4,
|
|
'font-size': '12px',
|
|
'line-height': '12px'
|
|
});
|
|
tr.appendChild(td_value);
|
|
});
|
|
|
|
if (i < sections.length) {
|
|
var spacer_tr = $.createElement('tr');
|
|
table.appendChild(spacer_tr);
|
|
|
|
var spacer_td = $.createElement('td')
|
|
.style('padding-bottom', beestat.style.size.gutter / 4);
|
|
spacer_tr.appendChild(spacer_td);
|
|
}
|
|
}
|
|
});
|
|
|
|
if (this.get_dock_tooltip_() === true) {
|
|
this.docked_tooltip_container_.innerHTML(tooltip[0].outerHTML);
|
|
return '';
|
|
} else {
|
|
this.docked_tooltip_container_.innerHTML('');
|
|
return tooltip[0].outerHTML;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get the boost options.
|
|
*
|
|
* @return {object} The boost options.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_boost_ = function() {
|
|
return {
|
|
'enabled': this.get_options_boost_enabled_(),
|
|
'useGPUTranslations': true,
|
|
'usePreallocated': true
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get the boost enabled option.
|
|
*
|
|
* @return {object} The boost enabled option.
|
|
*/
|
|
beestat.component.chart.prototype.get_options_boost_enabled_ = function() {
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Get whether or not the tooltip should be docked.
|
|
*
|
|
* @return {boolean}
|
|
*/
|
|
beestat.component.chart.prototype.get_dock_tooltip_ = function() {
|
|
return (
|
|
beestat.setting('ui.always_dock_tooltips') === true ||
|
|
window.innerWidth < 600
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Get the Highcharts chart object.
|
|
*
|
|
* @return {Highcharts} The Highcharts chart object.
|
|
*/
|
|
beestat.component.chart.prototype.get_chart = function() {
|
|
return this.chart_;
|
|
};
|
|
|
|
/**
|
|
* Sync extremes of this chart with extremes of another chart.
|
|
*
|
|
* @param {beestat.component.chart} source_chart The source chart.
|
|
*/
|
|
beestat.component.chart.prototype.sync_extremes = function(source_chart) {
|
|
var self = this;
|
|
|
|
source_chart.addEventListener('after_set_extremes', function() {
|
|
var extremes = source_chart.get_chart().axes[0].getExtremes();
|
|
self.get_chart().axes[0].setExtremes(
|
|
extremes.min,
|
|
extremes.max,
|
|
undefined,
|
|
false
|
|
);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Sync crosshair of this chart with crosshair of another chart.
|
|
*
|
|
* @param {beestat.component.chart} source_chart The source chart.
|
|
*/
|
|
beestat.component.chart.prototype.sync_crosshair = function(source_chart) {
|
|
var self = this;
|
|
|
|
[
|
|
'mousemove',
|
|
'touchmove',
|
|
'touchstart'
|
|
].forEach(function(event_type) {
|
|
source_chart.get_chart().container.addEventListener(
|
|
event_type,
|
|
function(e) {
|
|
// https://github.com/highcharts/highcharts/issues/17756
|
|
let first_visible_series;
|
|
for (let i = 0; i < self.get_chart().series.length; i++) {
|
|
if (self.get_chart().series[i].visible === true) {
|
|
first_visible_series = self.get_chart().series[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
var point = first_visible_series.searchPoint(
|
|
self.get_chart().pointer.normalize(e),
|
|
true
|
|
);
|
|
if (point !== undefined) {
|
|
self.get_chart().tooltip.refresh([point]);
|
|
self.get_chart().xAxis[0].drawCrosshair(e);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
// When I leave the source chart, hide the crosshair and tooltip in this chart.
|
|
source_chart.get_chart().container.addEventListener('mouseout', function() {
|
|
self.get_chart().xAxis[0].hideCrosshair();
|
|
self.get_chart().tooltip.hide(1);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Reflow the chart; useful if the GUI changes and the chart needs resized.
|
|
*
|
|
* @link https://api.highcharts.com/class-reference/Highcharts.Chart#reflow
|
|
*/
|
|
beestat.component.chart.prototype.reflow = function() {
|
|
this.chart_.reflow();
|
|
};
|
|
|
|
/**
|
|
* A generic function to update any element of the chart. Elements can be
|
|
* enabled and disabled, moved, re-styled, re-formatted etc.
|
|
*
|
|
* @param {object} options The options to change.
|
|
*
|
|
* @link https://api.highcharts.com/class-reference/Highcharts.Chart#update
|
|
*/
|
|
beestat.component.chart.prototype.update = function(options) {
|
|
this.chart_.update(options);
|
|
};
|