highcharts
Version:
JavaScript charting framework
162 lines (161 loc) • 5.34 kB
JavaScript
/* *
*
* Imports
*
* */
import { addEvent, correctFloat, defined, pick } from '../../Shared/Utilities.js';
/* *
*
* Functions
*
* */
/** @internal */
function chartGetHoverPane(eventArgs) {
const chart = this;
let hoverPane;
if (eventArgs) {
chart.pane.forEach((pane) => {
const x = eventArgs.chartX - chart.plotLeft, y = eventArgs.chartY - chart.plotTop;
if (isInsidePane(x, y, pane.center)) {
hoverPane = pane;
}
});
}
return hoverPane;
}
/**
* Adjusts the clipBox based on the position of panes.
* @internal
*/
function onSetClip({ clipBox }) {
if (!this.xAxis ||
!this.yAxis ||
(!this.chart.angular && !this.chart.polar)) {
return;
}
const { plotWidth, plotHeight } = this.chart, smallestSize = Math.min(plotWidth, plotHeight), xPane = this.xAxis.pane, yPane = this.yAxis.pane;
if (xPane && xPane.axis) {
clipBox.x += xPane.center[0] -
(xPane.center[2] / smallestSize) * plotWidth / 2;
}
if (yPane && yPane.axis) {
clipBox.y += yPane.center[1] -
(yPane.center[2] / smallestSize) * plotHeight / 2;
}
}
/** @internal */
function compose(ChartClass, PointerClass, SeriesClass) {
const chartProto = ChartClass.prototype;
if (!chartProto.getHoverPane) {
chartProto.collectionsWithUpdate.push('pane');
chartProto.getHoverPane = chartGetHoverPane;
addEvent(ChartClass, 'afterIsInsidePlot', onChartAfterIsInsiderPlot);
addEvent(PointerClass, 'afterGetHoverData', onPointerAfterGetHoverData);
addEvent(PointerClass, 'beforeGetHoverData', onPointerBeforeGetHoverData);
addEvent(SeriesClass, 'setClip', onSetClip);
}
}
/**
* Check whether element is inside or outside pane.
* @internal
* @param {number} x
* Element's x coordinate
* @param {number} y
* Element's y coordinate
* @param {Array<number>} center
* Pane's center (x, y) and diameter
* @param {number} startAngle
* Pane's normalized start angle in radians (<-PI, PI>)
* @param {number} endAngle
* Pane's normalized end angle in radians (<-PI, PI>)
*/
function isInsidePane(x, y, center, startAngle, endAngle) {
let insideSlice = true;
const cx = center[0], cy = center[1], twoPi = 2 * Math.PI;
const distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
if (defined(startAngle) && defined(endAngle)) {
// Round angle to N-decimals to avoid numeric errors
let angle = Math.atan2(correctFloat(y - cy, 8), correctFloat(x - cx, 8));
// Normalize angle to [0, 2π)
angle = (angle + twoPi) % (twoPi);
startAngle = (startAngle + twoPi) % (twoPi);
endAngle = (endAngle + twoPi) % (twoPi);
// Ignore full circle panes:
if (Math.abs(endAngle - startAngle) > 1e-6) {
// If the normalized start angle is greater than the end angle,
// it means the arc wraps around 0°. In this case, we check
// if the angle falls into either [startAngle, 2π) or [0, endAngle].
if (startAngle > endAngle) {
insideSlice = (angle >= startAngle ||
angle <= endAngle);
}
else {
// In this case, we simply check if angle is within the
// [startAngle, endAngle] range
insideSlice = angle >= startAngle &&
angle <= endAngle;
}
}
}
else {
// If no start/end angles are defined, treat it as a full circle
insideSlice = true;
}
// Round up radius because x and y values are rounded
return distance <= Math.ceil(center[2] / 2) && insideSlice;
}
/**
* Check if (x, y) position is within pane for polar.
* @internal
*/
function onChartAfterIsInsiderPlot(e) {
const chart = this;
if (chart.polar) {
if (e.options.inverted) {
[e.x, e.y] = [e.y, e.x];
}
e.isInsidePlot = chart.pane.some((pane) => isInsidePane(e.x, e.y, pane.center, pane.axis && pane.axis.normalizedStartAngleRad, pane.axis && pane.axis.normalizedEndAngleRad));
}
}
/**
* @internal
*/
function onPointerAfterGetHoverData(eventArgs) {
const chart = this.chart;
if (eventArgs.hoverPoint &&
eventArgs.hoverPoint.plotX &&
eventArgs.hoverPoint.plotY &&
chart.hoverPane &&
!isInsidePane(eventArgs.hoverPoint.plotX, eventArgs.hoverPoint.plotY, chart.hoverPane.center)) {
eventArgs.hoverPoint = void 0;
}
}
/** @internal */
function onPointerBeforeGetHoverData(eventArgs) {
const chart = this.chart;
if (chart.polar) {
// Find pane we are currently hovering over.
chart.hoverPane = chart.getHoverPane(eventArgs);
// Edit filter method to handle polar
eventArgs.filter = function (s) {
return (s.visible &&
!(!eventArgs.shared && s.directTouch) && // #3821
pick(s.options.enableMouseTracking, true) &&
(!chart.hoverPane || s.xAxis.pane === chart.hoverPane));
};
}
else {
chart.hoverPane = void 0;
}
}
/* *
*
* Default Export
*
* */
/** @internal */
const PaneComposition = {
compose
};
/** @internal */
export default PaneComposition;