hitTest method
bool
hitTest(
- Offset pos,
- Rect bounds,
- PriceRange priceRange,
- CoordinateConverter converter, {
- double threshold = 8.0,
Checks if pos hits this drawing (near line, inside box, or near handles).
Implementation
bool hitTest(
Offset pos,
Rect bounds,
PriceRange priceRange,
CoordinateConverter converter, {
double threshold = 8.0,
}) {
if (points.isEmpty) return false;
if (hitTestHandle(
pos,
bounds,
priceRange,
converter,
threshold: threshold + 4,
) !=
null) {
return true;
}
switch (tool) {
case DrawingTool.pointer:
return false;
case DrawingTool.trendline:
case DrawingTool.ruler:
if (points.length < 2) return false;
final x1 = converter.indexToX(points[0].candleIndex);
final y1 = CoordinateConverter.priceToY(
points[0].price,
bounds,
priceRange,
);
final x2 = converter.indexToX(points[1].candleIndex);
final y2 = CoordinateConverter.priceToY(
points[1].price,
bounds,
priceRange,
);
return distanceToSegment(pos, Offset(x1, y1), Offset(x2, y2)) <=
threshold;
case DrawingTool.horizontalLine:
final y = CoordinateConverter.priceToY(
points[0].price,
bounds,
priceRange,
);
return (pos.dy - y).abs() <= math.max(threshold, 10.0) &&
pos.dx >= bounds.left - 10 &&
pos.dx <= bounds.right + 10;
case DrawingTool.horizontalRay:
final x = converter.indexToX(points[0].candleIndex);
final y = CoordinateConverter.priceToY(
points[0].price,
bounds,
priceRange,
);
return (pos.dy - y).abs() <= math.max(threshold, 10.0) &&
pos.dx >= x - 10 &&
pos.dx <= bounds.right + 10;
case DrawingTool.verticalLine:
final x = converter.indexToX(points[0].candleIndex);
return (pos.dx - x).abs() <= math.max(threshold, 10.0) &&
pos.dy >= bounds.top - 10 &&
pos.dy <= bounds.bottom + 10;
case DrawingTool.rectangle:
if (points.length < 2) return false;
final x1 = converter.indexToX(points[0].candleIndex);
final y1 = CoordinateConverter.priceToY(
points[0].price,
bounds,
priceRange,
);
final x2 = converter.indexToX(points[1].candleIndex);
final y2 = CoordinateConverter.priceToY(
points[1].price,
bounds,
priceRange,
);
final rect = Rect.fromLTRB(
math.min(x1, x2),
math.min(y1, y2),
math.max(x1, x2),
math.max(y1, y2),
);
return rect.inflate(threshold).contains(pos);
case DrawingTool.fibonacci:
if (points.length < 2) return false;
final p1 = points[0];
final p2 = points[1];
final x1 = converter.indexToX(p1.candleIndex);
final x2 = converter.indexToX(p2.candleIndex);
final minX = math.min(x1, x2) - threshold;
final maxX = math.max(bounds.right, math.max(x1, x2)) + threshold;
if (pos.dx < minX || pos.dx > maxX) return false;
final priceDiff = p2.price - p1.price;
const ratios = [0.0, 0.236, 0.382, 0.500, 0.618, 0.786, 1.0];
for (final r in ratios) {
final levelPrice = p1.price + (priceDiff * r);
final y = CoordinateConverter.priceToY(
levelPrice,
bounds,
priceRange,
);
if ((pos.dy - y).abs() <= threshold) return true;
}
return false;
case DrawingTool.longPosition:
case DrawingTool.shortPosition:
final isLong = tool == DrawingTool.longPosition;
final entry = points.first;
final entryX = converter.indexToX(entry.candleIndex);
final widthSpan = (properties['widthSpan'] as double?) ?? (40 * 11.0);
final rightX = (entryX + widthSpan).clamp(entryX + 50.0, bounds.right);
final targetPrice = properties['targetPrice'] as double? ??
(isLong ? entry.price * 1.015 : entry.price * 0.985);
final stopPrice = properties['stopPrice'] as double? ??
(isLong ? entry.price * 0.9925 : entry.price * 1.0075);
final targetY = CoordinateConverter.priceToY(
targetPrice,
bounds,
priceRange,
);
final stopY = CoordinateConverter.priceToY(
stopPrice,
bounds,
priceRange,
);
final minY = math.min(targetY, stopY);
final maxY = math.max(targetY, stopY);
final totalRect = Rect.fromLTRB(entryX, minY, rightX, maxY);
return totalRect.inflate(threshold).contains(pos);
case DrawingTool.extendedTrendline:
case DrawingTool.arrow:
// Same as trendline — hits the segment
if (points.length < 2) return false;
final ax1 = converter.indexToX(points[0].candleIndex);
final ay1 = CoordinateConverter.priceToY(points[0].price, bounds, priceRange);
final ax2 = converter.indexToX(points[1].candleIndex);
final ay2 = CoordinateConverter.priceToY(points[1].price, bounds, priceRange);
return distanceToSegment(pos, Offset(ax1, ay1), Offset(ax2, ay2)) <= threshold;
case DrawingTool.parallelChannel:
if (points.length < 2) return false;
final cx1 = converter.indexToX(points[0].candleIndex);
final cy1 = CoordinateConverter.priceToY(points[0].price, bounds, priceRange);
final cx2 = converter.indexToX(points[1].candleIndex);
final cy2 = CoordinateConverter.priceToY(points[1].price, bounds, priceRange);
if (distanceToSegment(pos, Offset(cx1, cy1), Offset(cx2, cy2)) <= threshold) return true;
if (points.length >= 3) {
final cy3 = CoordinateConverter.priceToY(points[2].price, bounds, priceRange);
final midY = (cy1 + cy2) / 2;
final offset = cy3 - midY;
return distanceToSegment(
pos, Offset(cx1, cy1 + offset), Offset(cx2, cy2 + offset)) <= threshold;
}
return false;
case DrawingTool.textLabel:
if (points.isEmpty) return false;
final lx = converter.indexToX(points[0].candleIndex);
final ly = CoordinateConverter.priceToY(points[0].price, bounds, priceRange);
return (Offset(lx, ly) - pos).distance <= threshold * 2.5;
}
}