scichart
Version:
Fast WebGL JavaScript Charting Library and Framework
704 lines (703 loc) • 40.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hitTestHelpers = void 0;
var Deleter_1 = require("../../../../Core/Deleter");
var Point_1 = require("../../../../Core/Point");
var ErrorDirection_1 = require("../../../../types/ErrorDirection");
var pointUtil_1 = require("../../../../utils/pointUtil");
var ColumnMode_1 = require("../../../../types/ColumnMode");
var HitTestInfo_1 = require("./HitTestInfo");
var TriangleSeriesDrawMode_1 = require("../../../../types/TriangleSeriesDrawMode");
var interpolateLinear = function (x, x1, y1, x2, y2) {
return y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
};
// TODO: take isVertical property into account
/**
*
* @param renderableSeries
* @param xCoordinateCalculator
* @param yCoordinateCalculator
* @param isVerticalChart
* @param dataSeries
* @param xNativeValues
* @param yNativeValues
* @param xHitCoord the X coordinate on the screen relative to seriesViewRect, X and Y swapped for vertical charts
* @param yHitCoord the Y coordinate on the screen relative to seriesViewRect, X and Y swapped for vertical charts
* @param nearestPointIndex
* @param hitTestRadius
*/
var createHitTestInfo = function (renderableSeries, xCoordinateCalculator, yCoordinateCalculator, isVerticalChart, dataSeries, xNativeValues, yNativeValues, xHitCoord, yHitCoord, nearestPointIndex, hitTestRadius, distance, dataCoordWidth) {
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var hitTestInfo = new HitTestInfo_1.HitTestInfo(renderableSeries);
hitTestInfo.seriesName = renderableSeries.seriesName;
hitTestInfo.dataSeriesType = dataSeries.type;
hitTestInfo.hitTestPoint = new Point_1.Point(xHitCoord, yHitCoord);
var hitTestPointXValue = xCoordinateCalculator.getDataValue(xHitCoord);
var hitTestPointYValue = yCoordinateCalculator.getDataValue(yHitCoord);
hitTestInfo.hitTestPointValues = new Point_1.Point(hitTestPointXValue, hitTestPointYValue);
hitTestInfo.dataSeriesIndex = nearestPointIndex;
hitTestInfo.hitTestRadius = hitTestRadius;
hitTestInfo.isCategoryAxis = isCategoryAxis;
hitTestInfo.distance = distance;
// If there is no data, don't attempt to access it.
if (nearestPointIndex >= 0) {
var yValueByName = dataSeries.valueNames.reduce(function (map, name) {
map[name] = dataSeries.getNativeValue(dataSeries.getYValuesByName(name), nearestPointIndex);
return map;
}, {});
var xValue = isCategoryAxis ? nearestPointIndex : dataSeries.getNativeValue(xNativeValues, nearestPointIndex);
var yValue = dataSeries.getNativeValue(yNativeValues, nearestPointIndex);
hitTestInfo.xCoord = xCoordinateCalculator.getCoordinate(xValue);
hitTestInfo.yCoord = yCoordinateCalculator.getCoordinate(yValue);
// TODO: It might be worth to flip them to make the API better
// if (isVerticalChart) {
// const temp = hitTestInfo.xCoord;
// hitTestInfo.xCoord = hitTestInfo.yCoord;
// hitTestInfo.yCoord = temp;
// }
hitTestInfo.xValue = xValue;
if (isCategoryAxis) {
hitTestInfo.xCategoryValue = xNativeValues.get(nearestPointIndex);
}
hitTestInfo.yValueByName = yValueByName;
hitTestInfo.yValue = yValue;
// let xFirstValue = isCategoryAxis ? 0 : dataSeries.getNativeValue(xNativeValues, 0);
// let xLastValue = isCategoryAxis
// ? xNativeValues.size() - 1
// : dataSeries.getNativeValue(xNativeValues, xNativeValues.size() - 1);
var xRange = isCategoryAxis ? dataSeries.getIndicesRange(dataSeries.getXRange()) : dataSeries.getXRange();
var dataWidth = dataCoordWidth !== undefined ? xCoordinateCalculator.getDataWidth(dataCoordWidth) : 0;
hitTestInfo.isWithinDataBounds = (0, pointUtil_1.testIsInInterval)(hitTestPointXValue, xRange.min, xRange.max, dataWidth / 2);
hitTestInfo.metadata = dataSeries.getMetadataAt(nearestPointIndex);
}
else {
hitTestInfo.isWithinDataBounds = false;
}
hitTestInfo.isHit = undefined;
return hitTestInfo;
};
var getNearestXPoint = function (webAssemblyContext, xCoordinateCalculator, dataSeries, xHitCoord, isSorted) {
var result = getNearestXyPoint(webAssemblyContext, xCoordinateCalculator, xCoordinateCalculator, dataSeries, xHitCoord, 0, 0);
return result.nearestPointIndex;
};
var getNearestXyPoint = function (webassemblyContext, xCoordinateCalculator, yCoordinateCalculator, dataSeries, xHitCoord, yHitCoord, hitTestRadius) {
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var dataX = isCategoryAxis ? dataSeries.getNativeIndexes() : dataSeries.getNativeXValues();
var dataY = dataSeries.getNativeYValues();
return getNearestPoint(webassemblyContext, xCoordinateCalculator, yCoordinateCalculator, dataX, dataY, dataSeries.dataDistributionCalculator.isSortedAscending, xHitCoord, yHitCoord, hitTestRadius);
};
var getNearestPoint = function (webassemblyContext, xCoordinateCalculator, yCoordinateCalculator, xValues, yValues, isSorted, xHitCoord, yHitCoord, hitTestRadius) {
var result;
try {
result = webassemblyContext.SCRTHitTestHelper.GetNearestXyPoint(xCoordinateCalculator.nativeCalculator, yCoordinateCalculator.nativeCalculator, xValues, yValues, isSorted, xHitCoord, yHitCoord, hitTestRadius !== null && hitTestRadius !== void 0 ? hitTestRadius : 1 // Default to 1 here so unsorted data will get nearest by x and y
);
return { nearestPointIndex: result.minD, distance: result.maxD };
}
finally {
(0, Deleter_1.deleteSafe)(result);
}
};
var getNearestXyyPoint = function (webassemblyContext, xCoordinateCalculator, yCoordinateCalculator, dataSeries, xHitCoord, yHitCoord, hitTestRadius) {
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var dataX = isCategoryAxis ? dataSeries.getNativeIndexes() : dataSeries.getNativeXValues();
var dataY = dataSeries.getNativeYValues();
var result;
var nearestY;
var distanceY;
try {
result = webassemblyContext.SCRTHitTestHelper.GetNearestXyPoint(xCoordinateCalculator.nativeCalculator, yCoordinateCalculator.nativeCalculator, dataX, dataY, dataSeries.dataDistributionCalculator.isSortedAscending, xHitCoord, yHitCoord, hitTestRadius !== null && hitTestRadius !== void 0 ? hitTestRadius : 1);
nearestY = result.minD;
distanceY = result.maxD;
}
finally {
(0, Deleter_1.deleteSafe)(result);
}
try {
result = webassemblyContext.SCRTHitTestHelper.GetNearestXyPoint(xCoordinateCalculator.nativeCalculator, yCoordinateCalculator.nativeCalculator, dataX, dataSeries.getNativeY1Values(), dataSeries.dataDistributionCalculator.isSortedAscending, xHitCoord, yHitCoord, hitTestRadius !== null && hitTestRadius !== void 0 ? hitTestRadius : 1);
if (distanceY < result.maxD) {
// Y is nearer
return { nearestPointIndex: nearestY, distance: distanceY };
}
else {
return { nearestPointIndex: result.minD, distance: result.maxD };
}
}
finally {
(0, Deleter_1.deleteSafe)(result);
}
};
var getNearestUniformHeatmapPoint = function (xCoordinateCalculator, yCoordinateCalculator, heatmapDataSeries, xHitCoord, yHitCoord) {
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
var yHitValue = yCoordinateCalculator.getDataValue(yHitCoord);
var xIndex = Math.floor((xHitValue - heatmapDataSeries.xStart) / heatmapDataSeries.xStep);
var yIndex = Math.floor((yHitValue - heatmapDataSeries.yStart) / heatmapDataSeries.yStep);
if (xIndex < 0 || xIndex >= heatmapDataSeries.arrayWidth || yIndex < 0 || yIndex >= heatmapDataSeries.arrayHeight) {
return { xIndex: -1, yIndex: -1, zValue: undefined };
}
var zValue = heatmapDataSeries.getZValue(yIndex, xIndex);
return { xIndex: xIndex, yIndex: yIndex, zValue: zValue };
};
var getNearestNonUniformHeatmapPoint = function (xCoordinateCalculator, yCoordinateCalculator, heatmapDataSeries, xHitCoord, yHitCoord) {
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
var yHitValue = yCoordinateCalculator.getDataValue(yHitCoord);
var xCellOffsets = heatmapDataSeries.xCellOffsets, yCellOffsets = heatmapDataSeries.yCellOffsets;
var xIndex = -1;
if (xHitValue >= xCellOffsets[0] && xHitValue <= xCellOffsets[xCellOffsets.length - 1]) {
for (var i = 0; i < xCellOffsets.length; i++) {
var isWithinCellOffsets = xHitValue >= xCellOffsets[i] && xHitValue <= xCellOffsets[i + 1];
if (isWithinCellOffsets) {
xIndex = i;
break;
}
}
}
var yIndex = -1;
if (yHitValue >= yCellOffsets[0] && yHitValue <= yCellOffsets[yCellOffsets.length - 1]) {
for (var i = 0; i < yCellOffsets.length - 1; i++) {
var isWithinCellOffsets = yHitValue >= yCellOffsets[i] && yHitValue <= yCellOffsets[i + 1];
if (isWithinCellOffsets) {
yIndex = i;
break;
}
}
}
// TODO shouldn't we return a nearest cell anyway?
if (xIndex < 0 || xIndex >= heatmapDataSeries.arrayWidth || yIndex < 0 || yIndex >= heatmapDataSeries.arrayHeight) {
return { xIndex: -1, yIndex: -1, zValue: undefined };
}
var zValue = heatmapDataSeries.getZValue(yIndex, xIndex);
return { xIndex: xIndex, yIndex: yIndex, zValue: zValue };
};
/**
* Finds a Triangle that has been hit and return indices of the first and the last vertex of this triangle,
* If there is no hit return -1, -1
*/
var getNearestTriangle = function (wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, yValues, xHitCoord, yHitCoord, drawMode, polygonVertices) {
var isPolygon = drawMode === TriangleSeriesDrawMode_1.ETriangleSeriesDrawMode.Polygon || drawMode === TriangleSeriesDrawMode_1.ETriangleSeriesDrawMode.List;
var vertices = drawMode === TriangleSeriesDrawMode_1.ETriangleSeriesDrawMode.List ? 3 : polygonVertices;
var res = wasmContext.SCRTHitTestHelper.GetNearestTriangle(isPolygon, vertices, xCoordinateCalculator.nativeCalculator, yCoordinateCalculator.nativeCalculator, xValues, yValues, xHitCoord, yHitCoord);
return { nearestPointIndex: res.minD, nearestPointIndex2: res.maxD, isHit: res.minD >= 0 };
};
var getNearestLineSegment = function (xCoordinateCalculator, yCoordinateCalculator, numberOfSegments, getXFn, getYFn, getX1Fn, getY1Fn, xHitCoord, yHitCoord, hitTestRadius) {
var minX = Number.MAX_VALUE;
var maxX = Number.NEGATIVE_INFINITY;
var minY = Number.MAX_VALUE;
var maxY = Number.NEGATIVE_INFINITY;
var updateMinMaxFn = function (getXFn$, getYFn$) {
for (var i = 0; i < numberOfSegments; i++) {
var x = getXFn$(i);
var y = getYFn$(i);
minX = x < minX ? x : minX;
maxX = x > maxX ? x : maxX;
minY = y < minY ? y : minY;
maxY = y > maxY ? y : maxY;
}
};
updateMinMaxFn(getXFn, getYFn);
updateMinMaxFn(getX1Fn, getY1Fn);
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
var yHitValue = yCoordinateCalculator.getDataValue(yHitCoord);
var isWithinDataBounds = minX <= xHitValue && xHitValue <= maxX && minY <= yHitValue && yHitValue <= maxY;
// Test for lines
var minDistance = Number.MAX_VALUE;
var minDistanceIndex = -1;
for (var i = 0; i < numberOfSegments; i++) {
var x = getXFn(i);
var y = getYFn(i);
var x1 = getX1Fn(i);
var y1 = getY1Fn(i);
var xCoord = xCoordinateCalculator.getCoordinate(x);
var yCoord = yCoordinateCalculator.getCoordinate(y);
var x1Coord = xCoordinateCalculator.getCoordinate(x1);
var y1Coord = yCoordinateCalculator.getCoordinate(y1);
var lineSegmentLength = (0, pointUtil_1.calcDistance)(xCoord, yCoord, x1Coord, y1Coord);
var distanceToPoint = (0, pointUtil_1.calcDistance)(xCoord, yCoord, xHitCoord, yHitCoord);
var distanceToPoint1 = (0, pointUtil_1.calcDistance)(x1Coord, y1Coord, xHitCoord, yHitCoord);
if (distanceToPoint <= lineSegmentLength + hitTestRadius &&
distanceToPoint1 <= lineSegmentLength + hitTestRadius) {
var distanceToLine = (0, pointUtil_1.calcDistanceFromLine)(xHitCoord, yHitCoord, xCoord, yCoord, x1Coord, y1Coord);
if (distanceToLine <= minDistance) {
minDistance = distanceToLine;
minDistanceIndex = i;
}
}
}
return {
isHit: minDistance <= hitTestRadius,
isWithinDataBounds: isWithinDataBounds,
nearestPointIndex: minDistanceIndex,
nearestDistance: minDistanceIndex >= 0 ? minDistance : undefined
};
};
var testIsHitForPoint = function (xCoordinateCalculator, yCoordinateCalculator, xValues, yValues, pointIndex, xHitCoord, yHitCoord, hitTestRadius, dataSeries) {
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yValue = dataSeries.getNativeValue(yValues, pointIndex);
var dataXCoord = xCoordinateCalculator.getCoordinate(xValue);
var dataYCoord = yCoordinateCalculator.getCoordinate(yValue);
var distance = (0, pointUtil_1.calcDistance)(xHitCoord, yHitCoord, dataXCoord, dataYCoord);
return distance < hitTestRadius;
};
/**
*
* @param xCoordinateCalculator
* @param yCoordinateCalculator
* @param xValues
* @param yValues
* @param pointIndex
* @param xHitCoord The X coordinate, isVertical property is already taken into account
* @param yHitCoord The Y coordinate, isVertical property is already taken into account
* @param hitTestRadius
*/
var testIsHitForLine = function (xCoordinateCalculator, yCoordinateCalculator, xValues, yValues, pointIndex, xHitCoord, yHitCoord, hitTestRadius, dataSeries) {
var isHit;
var secondPointIndex;
var xLeft, xRight, yLeft, yRight;
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yValue = dataSeries.getNativeValue(yValues, pointIndex);
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
if (xValue <= xHitValue) {
xLeft = xValue;
yLeft = yValue;
xRight = isCategoryAxis ? pointIndex + 1 : dataSeries.getNativeValue(xValues, pointIndex + 1);
yRight = dataSeries.getNativeValue(yValues, pointIndex + 1);
secondPointIndex = pointIndex + 1;
}
else {
xLeft = isCategoryAxis ? pointIndex - 1 : dataSeries.getNativeValue(xValues, pointIndex - 1);
yLeft = dataSeries.getNativeValue(yValues, pointIndex - 1);
secondPointIndex = pointIndex - 1;
xRight = xValue;
yRight = yValue;
}
var xLeftCoord = xCoordinateCalculator.getCoordinate(xLeft);
var xRightCoord = xCoordinateCalculator.getCoordinate(xRight);
var yLeftCoord = yCoordinateCalculator.getCoordinate(yLeft);
var yRightCoord = yCoordinateCalculator.getCoordinate(yRight);
var lineSegmentLength = (0, pointUtil_1.calcDistance)(xLeftCoord, yLeftCoord, xRightCoord, yRightCoord);
var distanceToLeftPoint = (0, pointUtil_1.calcDistance)(xLeftCoord, yLeftCoord, xHitCoord, yHitCoord);
var distanceToRightPoint = (0, pointUtil_1.calcDistance)(xRightCoord, yRightCoord, xHitCoord, yHitCoord);
// Because the line that goes through two points is infinite it could happen that mouse click is near this line
// but far away from the line segment, especially if the segment is almost a vertical line
// in this case we set isHit = false
if (distanceToLeftPoint > lineSegmentLength + hitTestRadius ||
distanceToRightPoint > lineSegmentLength + hitTestRadius) {
isHit = false;
}
else {
isHit =
(0, pointUtil_1.calcDistanceFromLine)(xHitCoord, yHitCoord, xLeftCoord, yLeftCoord, xRightCoord, yRightCoord) <
hitTestRadius;
}
return { isHit: isHit, secondPointIndex: secondPointIndex };
};
var testIsHitForBand = function (isDigitalLine, xCoordinateCalculator, yCoordinateCalculator, xValues, getYValue, getY1Value, pointIndex, xHitCoord, yHitCoord, dataSeries) {
var isHit;
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var isLeftHit = xValue <= xHitValue;
var secondPointIndex = isLeftHit ? pointIndex + 1 : pointIndex - 1;
if (secondPointIndex < 0 || secondPointIndex >= xValues.size()) {
return { isHit: false, secondPointIndex: undefined };
}
var secondPointXValue = isCategoryAxis ? secondPointIndex : dataSeries.getNativeValue(xValues, secondPointIndex);
var xLeft = isLeftHit ? xValue : secondPointXValue;
var yLeft = isLeftHit ? getYValue(pointIndex) : getYValue(secondPointIndex);
var y1Left = isLeftHit ? getY1Value(pointIndex) : getY1Value(secondPointIndex);
var xRight = isLeftHit ? secondPointXValue : xValue;
var yRight = isLeftHit ? getYValue(secondPointIndex) : getYValue(pointIndex);
var y1Right = isLeftHit ? getY1Value(secondPointIndex) : getY1Value(pointIndex);
var xLeftCoord = xCoordinateCalculator.getCoordinate(xLeft);
var xRightCoord = xCoordinateCalculator.getCoordinate(xRight);
var yLeftCoord = yCoordinateCalculator.getCoordinate(yLeft);
var yRightCoord = yCoordinateCalculator.getCoordinate(yRight);
var y1LeftCoord = yCoordinateCalculator.getCoordinate(y1Left);
var y1RightCoord = yCoordinateCalculator.getCoordinate(y1Right);
if (isDigitalLine) {
if (yLeftCoord < y1LeftCoord) {
isHit = yHitCoord >= yLeftCoord && yHitCoord <= y1LeftCoord;
}
else {
isHit = yHitCoord >= y1LeftCoord && yHitCoord <= yLeftCoord;
}
}
else {
var interpolatedLineY = interpolateLinear(xHitCoord, xLeftCoord, yLeftCoord, xRightCoord, yRightCoord);
var interpolatedLineY1 = interpolateLinear(xHitCoord, xLeftCoord, y1LeftCoord, xRightCoord, y1RightCoord);
if (interpolatedLineY < interpolatedLineY1) {
isHit = yHitCoord >= interpolatedLineY && yHitCoord <= interpolatedLineY1;
}
else {
isHit = yHitCoord >= interpolatedLineY1 && yHitCoord <= interpolatedLineY;
}
}
return { isHit: isHit, secondPointIndex: secondPointIndex };
};
var testIsHitForColumn = function (xCoordinateCalculator, yCoordinateCalculator, columnWidth, zeroLineY, dataSeries, xValues, yValues, pointIndex, xHitCoord, yHitCoord, distance) {
if (distance === void 0) { distance = undefined; }
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yValue = dataSeries.getNativeValue(yValues, pointIndex);
var xCoord = xCoordinateCalculator.getCoordinate(xValue);
var yCoord = yCoordinateCalculator.getCoordinate(yValue);
var zeroLineYCoord = yCoordinateCalculator.getCoordinate(zeroLineY);
var halfWidth = columnWidth / 2;
var topColumnSide = zeroLineYCoord > yCoord ? zeroLineYCoord : yCoord;
var bottomColumnSide = zeroLineYCoord > yCoord ? yCoord : zeroLineYCoord;
if (distance !== undefined) {
var isXHit = distance <= halfWidth;
var isYHit = yHitCoord <= topColumnSide && yHitCoord >= bottomColumnSide;
return isXHit && isYHit;
}
else {
return (0, pointUtil_1.testIsInBounds)(xHitCoord, yHitCoord, xCoord - halfWidth, topColumnSide, xCoord + halfWidth, bottomColumnSide);
}
};
var testIsHitForBoxPlot = function (xCoordinateCalculator, yCoordinateCalculator, columnWidth, dataSeries, xValues, yMinValues, yMaxValues, pointIndex, xHitCoord, yHitCoord) {
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yMinValue = dataSeries.getNativeValue(yMinValues, pointIndex);
var yMaxValue = dataSeries.getNativeValue(yMaxValues, pointIndex);
var xCoord = xCoordinateCalculator.getCoordinate(xValue);
var yCoord = yCoordinateCalculator.getCoordinate(yMinValue);
var y1Coord = yCoordinateCalculator.getCoordinate(yMaxValue);
var halfWidth = columnWidth / 2;
var topColumnSide = y1Coord > yCoord ? y1Coord : yCoord;
var bottomColumnSide = y1Coord > yCoord ? yCoord : y1Coord;
return (0, pointUtil_1.testIsInBounds)(xHitCoord, yHitCoord, xCoord - halfWidth, topColumnSide, xCoord + halfWidth, bottomColumnSide);
};
var testIsHitForErrorBars = function (xCoordinateCalculator, yCoordinateCalculator, renderableSeries, xValues, yValues, pointIndex, xHitCoord, yHitCoord) {
var getDataPointWidth = renderableSeries.getDataPointWidth, dataPointWidth = renderableSeries.dataPointWidth, errorDirection = renderableSeries.errorDirection, dataSeries = renderableSeries.dataSeries, dataPointWidthMode = renderableSeries.dataPointWidthMode;
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var isVerticalDirection = errorDirection === ErrorDirection_1.EErrorDirection.Vertical;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yValue = dataSeries.getNativeValue(yValues, pointIndex);
var highValue = dataSeries.getNativeValue(dataSeries.getNativeHighValues(), pointIndex);
var lowValue = dataSeries.getNativeValue(dataSeries.getNativeLowValues(), pointIndex);
if (isNaN(highValue))
highValue = yValue;
if (isNaN(lowValue))
lowValue = yValue;
var xCoord = xCoordinateCalculator.getCoordinate(xValue);
var yCoord = yCoordinateCalculator.getCoordinate(yValue);
var highCoord = isVerticalDirection
? yCoordinateCalculator.getCoordinate(highValue)
: xCoordinateCalculator.getCoordinate(highValue);
var lowCoord = isVerticalDirection
? yCoordinateCalculator.getCoordinate(lowValue)
: xCoordinateCalculator.getCoordinate(lowValue);
var columnWidth = getDataPointWidth(isVerticalDirection ? xCoordinateCalculator : yCoordinateCalculator, dataPointWidth, dataPointWidthMode);
var halfWidth = columnWidth / 2;
var isHit = false;
var upperErrorBoundary = highCoord > lowCoord ? highCoord : lowCoord;
var lowerErrorBoundary = highCoord > lowCoord ? lowCoord : highCoord;
if (isVerticalDirection) {
isHit = (0, pointUtil_1.testIsInBounds)(xHitCoord, yHitCoord, xCoord - halfWidth, upperErrorBoundary, xCoord + halfWidth, lowerErrorBoundary);
}
else {
isHit = (0, pointUtil_1.testIsInBounds)(xHitCoord, yHitCoord, lowerErrorBoundary, yCoord + halfWidth, upperErrorBoundary, yCoord - halfWidth);
}
return { isHit: isHit, highValue: highValue, lowValue: lowValue };
};
var testIsHitForImpulse = function (xCoordinateCalculator, yCoordinateCalculator, renderableSeries, xValues, yValues, pointIndex, xHitCoord, yHitCoord, hitTestRadius) {
var zeroLineY = renderableSeries.zeroLineY, dataSeries = renderableSeries.dataSeries;
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yValue = dataSeries.getNativeValue(yValues, pointIndex);
var xCoord = xCoordinateCalculator.getCoordinate(xValue);
var yCoord = yCoordinateCalculator.getCoordinate(yValue);
var zeroLineYCoord = yCoordinateCalculator.getCoordinate(zeroLineY);
var topColumnSide = zeroLineYCoord > yCoord ? zeroLineYCoord : yCoord;
var bottomColumnSide = zeroLineYCoord > yCoord ? yCoord : zeroLineYCoord;
return (0, pointUtil_1.testIsInBounds)(xHitCoord, yHitCoord, xCoord, topColumnSide, xCoord, bottomColumnSide, hitTestRadius);
};
var testIsHitForOHLC = function (xCoordinateCalculator, yCoordinateCalculator, renderableSeries, dataSeries, pointIndex, xHitCoord, yHitCoord, hitTestRadius) {
var getDataPointWidth = renderableSeries.getDataPointWidth, dataPointWidth = renderableSeries.dataPointWidth, dataPointWidthMode = renderableSeries.dataPointWidthMode;
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(dataSeries.getNativeXValues(), pointIndex);
var xCoord = xCoordinateCalculator.getCoordinate(xValue);
var openValue = dataSeries.getNativeValue(dataSeries.getNativeOpenValues(), pointIndex);
var openCoord = yCoordinateCalculator.getCoordinate(openValue);
var highValue = dataSeries.getNativeValue(dataSeries.getNativeHighValues(), pointIndex);
var highCoord = yCoordinateCalculator.getCoordinate(highValue);
var lowValue = dataSeries.getNativeValue(dataSeries.getNativeLowValues(), pointIndex);
var lowCoord = yCoordinateCalculator.getCoordinate(lowValue);
var closeValue = dataSeries.getNativeValue(dataSeries.getNativeCloseValues(), pointIndex);
var closeCoord = yCoordinateCalculator.getCoordinate(closeValue);
var columnWidth = getDataPointWidth(xCoordinateCalculator, dataPointWidth, dataPointWidthMode);
var halfWidth = columnWidth / 2;
var topSide = closeCoord > openCoord ? closeCoord : openCoord;
var bottomSide = closeCoord > openCoord ? openCoord : closeCoord;
// test candle body
var isCandleBodyHit = (0, pointUtil_1.testIsInBounds)(xHitCoord, yHitCoord, xCoord - halfWidth, topSide, xCoord + halfWidth, bottomSide);
// test candle wicks
var distanceToWicks = (0, pointUtil_1.calcDistanceFromLineSegment)(xHitCoord, yHitCoord, xCoord, highCoord, xCoord, lowCoord);
var isHit = isCandleBodyHit || distanceToWicks < hitTestRadius;
return { isHit: isHit, openValue: openValue, highValue: highValue, lowValue: lowValue, closeValue: closeValue };
};
var testIsHitForMountain = function (isDigitalLine, xCoordinateCalculator, yCoordinateCalculator, dataSeries, zeroLineY, pointIndex, xHitCoord, yHitCoord) {
var isHit;
var xValues = dataSeries.getNativeXValues();
var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
var xValue = isCategoryAxis ? pointIndex : dataSeries.getNativeValue(xValues, pointIndex);
var yValues = dataSeries.getNativeYValues();
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
var isLeftHit = xValue <= xHitValue;
var secondPointIndex = isLeftHit ? pointIndex + 1 : pointIndex - 1;
if (secondPointIndex < 0 || secondPointIndex >= dataSeries.count()) {
return { isHit: false, secondPointIndex: undefined };
}
var secondPointXValue = isCategoryAxis ? secondPointIndex : xValues.get(secondPointIndex);
var xLeft = isLeftHit ? xValue : secondPointXValue;
var yLeft = isLeftHit
? dataSeries.getNativeValue(yValues, pointIndex)
: dataSeries.getNativeValue(yValues, secondPointIndex);
var xRight = isLeftHit ? secondPointXValue : xValue;
var yRight = isLeftHit
? dataSeries.getNativeValue(yValues, secondPointIndex)
: dataSeries.getNativeValue(yValues, pointIndex);
var xLeftCoord = xCoordinateCalculator.getCoordinate(xLeft);
var xRightCoord = xCoordinateCalculator.getCoordinate(xRight);
var yLeftCoord = yCoordinateCalculator.getCoordinate(yLeft);
var yRightCoord = yCoordinateCalculator.getCoordinate(yRight);
var zeroLineYCoord = yCoordinateCalculator.getCoordinate(zeroLineY);
if (isDigitalLine) {
if (yLeftCoord < zeroLineYCoord) {
isHit = yHitCoord >= yLeftCoord && yHitCoord <= zeroLineYCoord;
}
else {
isHit = yHitCoord >= zeroLineYCoord && yHitCoord <= yLeftCoord;
}
}
else {
var interpolatedLineY = interpolateLinear(xHitCoord, xLeftCoord, yLeftCoord, xRightCoord, yRightCoord);
if (interpolatedLineY < zeroLineYCoord) {
isHit = yHitCoord >= interpolatedLineY && yHitCoord <= zeroLineYCoord;
}
else {
isHit = yHitCoord >= zeroLineYCoord && yHitCoord <= interpolatedLineY;
}
}
return { isHit: isHit, secondPointIndex: secondPointIndex };
};
var testPolarIsHitForColumn = function (wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, x1Values, yValues, xHitCoord, yHitCoord, zeroLineY, columnWidth, polarColumnMode, isVertical, isSorted) {
// TODO: for unsorted data
// if (!isSorted) {
// console.error("not implemented");
// return { isHit: false, nearestPointIndex: -1 };
// }
var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
var xHitCoordMinus2Pi = xHitCoord - 2 * Math.PI;
var xHitValueMinus2Pi = xCoordinateCalculator.getDataValue(xHitCoordMinus2Pi);
var xHitCoordPlus2Pi = xHitCoord + 2 * Math.PI;
var xHitValuePlus2Pi = xCoordinateCalculator.getDataValue(xHitCoordPlus2Pi);
var testIsYHit = function (resPointIndex$) {
var yValue$ = yValues.get(resPointIndex$);
var yCoord$ = yCoordinateCalculator.getCoordinate(yValue$);
var zeroLineYCoord$ = yCoordinateCalculator.getCoordinate(zeroLineY);
var maxYValueForColumn$ = zeroLineYCoord$ > yCoord$ ? zeroLineYCoord$ : yCoord$;
var minYValueForColumn$ = zeroLineYCoord$ > yCoord$ ? yCoord$ : zeroLineYCoord$;
return minYValueForColumn$ <= yHitCoord && yHitCoord <= maxYValueForColumn$;
};
if (polarColumnMode === ColumnMode_1.EColumnMode.Mid || polarColumnMode === ColumnMode_1.EColumnMode.Start) {
var xOffset = polarColumnMode === ColumnMode_1.EColumnMode.Mid ? 0 : columnWidth / 2;
var xIndex = wasmContext.NumberUtil.FindIndex(xValues, xHitValue - xOffset, wasmContext.SCRTFindIndexSearchMode.Nearest, true);
var xIndexMinus2Pi = wasmContext.NumberUtil.FindIndex(xValues, xHitValueMinus2Pi - xOffset, wasmContext.SCRTFindIndexSearchMode.Nearest, true);
var xIndexPlus2Pi = wasmContext.NumberUtil.FindIndex(xValues, xHitValuePlus2Pi - xOffset, wasmContext.SCRTFindIndexSearchMode.Nearest, true);
if (xIndex < 0 || xIndexMinus2Pi < 0 || xIndexPlus2Pi < 0) {
return { isHit: false, nearestPointIndex: -1, isWithinDataBounds: false };
}
else {
var resPointIndex = xIndex;
var xCoord = xCoordinateCalculator.getCoordinate(xValues.get(xIndex));
var resDist = Math.abs(xCoord + xOffset - xHitCoord);
var xCoordMinus2Pi = xCoordinateCalculator.getCoordinate(xValues.get(xIndexMinus2Pi));
var xDistMinus2Pi = Math.abs(xCoordMinus2Pi + xOffset - xHitCoordMinus2Pi);
if (xDistMinus2Pi < resDist) {
resPointIndex = xIndexMinus2Pi;
resDist = xDistMinus2Pi;
}
var xCoordPlus2Pi = xCoordinateCalculator.getCoordinate(xValues.get(xIndexPlus2Pi));
var xDistPlus2Pi = Math.abs(xCoordPlus2Pi + xOffset - xHitCoordPlus2Pi);
if (xDistPlus2Pi < resDist) {
resPointIndex = xIndexPlus2Pi;
resDist = xDistPlus2Pi;
}
var isXHit = resDist <= columnWidth / 2;
var isYHit = testIsYHit(resPointIndex);
return { nearestPointIndex: resPointIndex, isHit: isXHit && isYHit, isWithinDataBounds: isXHit };
}
}
var xVectorSize = xValues.size();
// if (polarColumnMode === EColumnMode.Width) {
// const xSumCoords: SCRTDoubleVector = new wasmContext.SCRTDoubleVector();
// if (xVectorSize > 0) {
// let cur = 0;
// xSumCoords.push_back(cur);
// for (let i = 0; i < xVectorSize; i++) {
// const xValue = xValues.get(i);
// const xCoord = xCoordinateCalculator.getCoordinate(xValue);
// cur += xCoord;
// xSumCoords.push_back(cur);
// }
// const getNearestXIndexFn = (
// xHitCoord$: number
// ): {
// index: number;
// dist: number;
// isHitCoordGreater: boolean;
// } => {
// const xIndex$ = wasmContext.NumberUtil.FindIndex(
// xSumCoords,
// xHitCoord$,
// wasmContext.SCRTFindIndexSearchMode.Nearest,
// true
// );
// const xCoord$ = xSumCoords.get(xIndex$);
// return {
// index: xIndex$,
// dist: Math.abs(xHitCoord$ - xCoord$),
// isHitCoordGreater: xHitCoord$ >= xCoord$
// };
// };
// let xNearestIndex = -1;
// let xDist = Number.MAX_VALUE;
// let isHitCoordGreater = false;
// [xHitCoord, xHitCoordMinus2Pi, xHitCoordPlus2Pi].forEach(c => {
// const r = getNearestXIndexFn(c);
// if (r.dist < xDist) {
// xNearestIndex = r.index;
// xDist = r.dist;
// isHitCoordGreater = r.isHitCoordGreater;
// }
// });
// if (xNearestIndex === -1) {
// return { nearestPointIndex: -1, isHit: false, isWithinDataBounds: false };
// } else if (xNearestIndex === 0) {
// return {
// nearestPointIndex: 0,
// isHit: isHitCoordGreater ? testIsYHit(0) : false,
// isWithinDataBounds: isHitCoordGreater
// };
// } else if (xNearestIndex === xVectorSize) {
// return {
// nearestPointIndex: xVectorSize - 1,
// isHit: isHitCoordGreater ? false : testIsYHit(xVectorSize - 1),
// isWithinDataBounds: !isHitCoordGreater
// };
// } else {
// const xIndex = isHitCoordGreater ? xNearestIndex : xNearestIndex - 1;
// return { nearestPointIndex: xIndex, isHit: testIsYHit(xIndex), isWithinDataBounds: true };
// }
// }
// xSumCoords.delete();
// return { isHit: false, nearestPointIndex: -1, isWithinDataBounds: false };
// }
if ([ColumnMode_1.EColumnMode.MidWidth, ColumnMode_1.EColumnMode.StartWidth, ColumnMode_1.EColumnMode.StartEnd].includes(polarColumnMode)) {
var xCenterValuesVector_1;
var widthVector_1;
if (polarColumnMode === ColumnMode_1.EColumnMode.StartWidth) {
xCenterValuesVector_1 = new wasmContext.SCRTDoubleVector();
widthVector_1 = x1Values;
for (var i = 0; i < xVectorSize; i++)
xCenterValuesVector_1.push_back(xValues.get(i) + x1Values.get(i) / 2);
}
else if (polarColumnMode === ColumnMode_1.EColumnMode.StartEnd) {
xCenterValuesVector_1 = new wasmContext.SCRTDoubleVector();
widthVector_1 = new wasmContext.SCRTDoubleVector();
for (var i = 0; i < xVectorSize; i++) {
var startVal = xValues.get(i);
var endVal = x1Values.get(i);
var width = endVal - startVal;
xCenterValuesVector_1.push_back(startVal + width / 2);
widthVector_1.push_back(width);
}
}
else {
xCenterValuesVector_1 = xValues;
widthVector_1 = x1Values;
}
var getNearestXIndexFn_1 = function (xHitValue$) {
var xIndex$ = wasmContext.NumberUtil.FindIndex(xCenterValuesVector_1, xHitValue$, wasmContext.SCRTFindIndexSearchMode.Nearest, true);
var xValue$ = xCenterValuesVector_1.get(xIndex$);
var columnWidth$ = widthVector_1.get(xIndex$);
var dist$ = Math.max(Math.abs(xHitValue$ - xValue$) - columnWidth$ / 2, 0);
if (dist$ === 0) {
return {
index: xIndex$,
dist: 0,
isWithinDataBounds: true
};
}
var isHitCoordGreater = xHitValue$ > xValue$;
var xIndex2$ = isHitCoordGreater ? xIndex$ + 1 : xIndex$ - 1;
var dist2$ = Number.MAX_VALUE;
if (xIndex2$ >= 0 && xIndex2$ < xVectorSize) {
var xValue2$ = xCenterValuesVector_1.get(xIndex2$);
var columnWidth2$ = widthVector_1.get(xIndex2$);
dist2$ = Math.max(Math.abs(xHitValue$ - xValue2$) - columnWidth2$ / 2, 0);
}
var xIndexRes$ = dist$ < dist2$ ? xIndex$ : xIndex2$;
var distRes$ = dist$ < dist2$ ? dist$ : dist2$;
var isWithinDataBounds$ = true;
if (xIndexRes$ === 0 && xHitValue$ < xCenterValuesVector_1.get(0) && distRes$ > 0) {
isWithinDataBounds$ = false;
}
if (xIndexRes$ === xVectorSize - 1 &&
xHitValue$ > xCenterValuesVector_1.get(xVectorSize - 1) &&
distRes$ > 0) {
isWithinDataBounds$ = false;
}
return {
index: xIndexRes$,
dist: distRes$,
isWithinDataBounds: isWithinDataBounds$
};
};
var xNearestIndex_1 = -1;
var xDist_1 = Number.MAX_VALUE;
var isWithinDataBounds_1 = false;
[xHitValue, xHitValueMinus2Pi, xHitValuePlus2Pi].forEach(function (c) {
var r = getNearestXIndexFn_1(c);
if (r.dist < xDist_1) {
xNearestIndex_1 = r.index;
xDist_1 = r.dist;
isWithinDataBounds_1 = r.isWithinDataBounds;
}
});
if (polarColumnMode === ColumnMode_1.EColumnMode.StartWidth) {
xCenterValuesVector_1.delete();
}
if (polarColumnMode === ColumnMode_1.EColumnMode.StartEnd) {
widthVector_1.delete();
}
return {
isHit: xDist_1 === 0 && testIsYHit(xNearestIndex_1),
nearestPointIndex: xNearestIndex_1,
isWithinDataBounds: isWithinDataBounds_1
};
}
return { isHit: false, nearestPointIndex: -1, isWithinDataBounds: false };
};
exports.hitTestHelpers = {
createHitTestInfo: createHitTestInfo,
getNearestPoint: getNearestPoint,
getNearestXPoint: getNearestXPoint,
getNearestXyPoint: getNearestXyPoint,
getNearestXyyPoint: getNearestXyyPoint,
getNearestUniformHeatmapPoint: getNearestUniformHeatmapPoint,
getNearestNonUniformHeatmapPoint: getNearestNonUniformHeatmapPoint,
getNearestTriangle: getNearestTriangle,
getNearestLineSegment: getNearestLineSegment,
testIsHitForPoint: testIsHitForPoint,
testIsHitForLine: testIsHitForLine,
testIsHitForBand: testIsHitForBand,
testIsHitForColumn: testIsHitForColumn,
testIsHitForOHLC: testIsHitForOHLC,
testIsHitForMountain: testIsHitForMountain,
testIsHitForErrorBars: testIsHitForErrorBars,
testIsHitForImpulse: testIsHitForImpulse,
testIsHitForBoxPlot: testIsHitForBoxPlot
};