@avolutions/canvas-painter
Version:
CanvasPainter.js is a simple yet powerful JavaScript library for drawing basic shapes (rectangles, circles, etc.) on HTML5 Canvas with ease. Perfect for creating 2D graphics in your web projects.
162 lines (161 loc) • 6.26 kB
JavaScript
import { InvalidConstructorArgumentsError } from "../errors/InvalidConstructorArgumentsError.js";
import { LineDefinition } from "../definitions/LineDefinition.js";
import { LineOptions } from "../options/LineOptions.js";
import { LineStyle } from "../styles/LineStyle.js";
import { Point } from "../types/Point.js";
import { Shape } from "./Shape.js";
/**
* Represents a line shape that extends the generic Shape class.
* It uses LineDefinition for defining the start and end points,
* LineStyle for styling, and LineOptions for additional options.
*/
export class Line extends Shape {
/**
* Creates an instance of the `Line` class.
*
* The `Line` can be created either by passing two `Point` objects representing the start and end of the line,
* or by providing the individual coordinates for the start and end points.
*
* @throws {@link InvalidConstructorArgumentsError} if invalid arguments are passed.
*/
constructor(arg1, arg2, arg3, arg4, arg5, arg6) {
let definition;
let style;
let options;
if (typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && typeof arg4 === 'number') {
// Constructor with coordinates
const start = new Point(arg1, arg2);
const end = new Point(arg3, arg4);
definition = new LineDefinition(start, end);
style = arg5;
options = arg6;
}
else if (arg1 instanceof Point && arg2 instanceof Point) {
// Constructor with Point objects
definition = new LineDefinition(arg1, arg2);
style = arg3;
options = arg4;
}
else {
throw new InvalidConstructorArgumentsError();
}
super(definition, new LineStyle(style), new LineOptions(options));
}
// Getters
/**
* Gets the starting point of the line.
*
* @returns The starting point of the line.
*/
get start() {
return this._definition.start;
}
/**
* Gets the ending point of the line.
*
* @returns The ending point of the line.
*/
get end() {
return this._definition.end;
}
// Setters
/**
* Sets the starting point of the line.
*
* @param start - The new starting point of the line.
*/
set start(start) {
this._definition.start = start;
}
/**
* Sets the ending point of the line.
*
* @param end - The new ending point of the line.
*/
set end(end) {
this._definition.end = end;
}
/**
* Moves the start point of the line by the specified deltas along the x and y axes.
*
* @param deltaX - The amount to move the start point along the x-axis.
* @param deltaY - The amount to move the start point along the y-axis.
*/
moveStart(deltaX = 0, deltaY = 0) {
this.start.move(deltaX, deltaY);
}
/**
* Moves the end point of the line by the specified deltas along the x and y axes.
*
* @param deltaX - The amount to move the end point along the x-axis.
* @param deltaY - The amount to move the end point along the y-axis.
*/
moveEnd(deltaX = 0, deltaY = 0) {
this.end.move(deltaX, deltaY);
}
/**
* Moves the start & end point of the line by the specified deltas along the x and y axes.
*
* @param deltaX - The amount to move the start & end point along the x-axis.
* @param deltaY - The amount to move the start & end point along the y-axis.
*/
move(deltaX = 0, deltaY = 0) {
this.moveStart(deltaX, deltaY);
this.moveEnd(deltaX, deltaY);
}
/**
* Renders the line on a canvas context.
*
* @param context - The canvas rendering context to draw the line.
*/
render(context) {
context.save(); // Save the current canvas state
context.lineWidth = this.stateStyle.width;
context.strokeStyle = this.stateStyle.color;
context.beginPath();
context.moveTo(this.start.x, this.start.y);
context.lineTo(this.end.x, this.end.y);
context.stroke();
context.restore(); // Restore the canvas state to before the transformations
}
/**
* Determines if the mouse is currently over the shape.
*
* @param mousePosition - The current mouse position.
* @returns True if the mouse is over the shape, false otherwise.
*/
isMouseOver(mousePosition) {
// Get the line width and calculate the tolerance distance
const lineWidth = this.stateStyle.width / 2;
// Calculate the vector components for the line and the point-to-start vector
const dx = this.end.x - this.start.x;
const dy = this.end.y - this.start.y;
const lengthSquared = dx * dx + dy * dy;
// If the line is effectively a point (start and end are the same), just check distance to the point
if (lengthSquared === 0) {
const distanceToStart = Math.hypot(mousePosition.x - this.start.x, mousePosition.y - this.start.y);
return distanceToStart <= lineWidth;
}
// Project the mouse position onto the line to find the closest point
const t = ((mousePosition.x - this.start.x) * dx + (mousePosition.y - this.start.y) * dy) / lengthSquared;
// Ensure t is within the segment [0, 1] to restrict the closest point to the line segment
if (t < 0 || t > 1) {
return false;
}
// Calculate the closest point on the line segment to the mouse position
const closestX = this.start.x + t * dx;
const closestY = this.start.y + t * dy;
// Calculate the distance from the mouse position to the closest point
const distanceToLine = Math.hypot(mousePosition.x - closestX, mousePosition.y - closestY);
// Check if this distance is within the tolerance (half the line width)
return distanceToLine <= lineWidth;
}
/**
* Handles the drag operation by applying the given delta to the current position.
*
* @param delta - The change in position represented as a `Point`.
*/
onDrag(delta) {
this.move(delta.x, delta.y);
}
}