es/icon-point.mjs
/*!
* icon-point@1.2.0 https://github.com/EvitcaStudio/IconPoint
* Compiled Tue, 03 Dec 2024 03:22:56 UTC
*
* icon-point is licensed under the MIT License.
* http://www.opensource.org/licenses/mit-license
*/
/**
* The IconPoint class
* A point that exists inside/outside a virtual rectangle. The point's position inside/outside of the rectangle is maintained when the rectangle is rotated.
* @example <caption>Example usage of this class</caption>
* // Create a rectangle at the position of (0,0)
* const rectangle = { x: 0, y: 0 };
* // Make the dimensions of the rectangle 100x50
* const bounds = { width: 100, height: 50 };
* // Create a point at the top left corner of the rectangle
* const point = { x: 1, y: 1 };
* // Create an icon point that will track the point on this rectangle when it moves/rotates
* const tlPoint = new IconPoint(rectangle, bounds, point);
*/
class IconPoint {
/**
* Static offset to use when none is passed.
*/
static defaultOffset = { x: 0, y: 0 };
/**
* Static anchor to use when none is passed. Default value of 0.5 signifies the anchor stars in the middle.
*/
static defaultAnchor = { x: 0.5, y: 0.5 };
/**
* The version of the module.
*/
static version = "1.2.0";
/** The logger module this module uses to log errors / logs
* @private
* @type {Logger}
*/
static logger = new i({
type: 'Icon-Point-Module',
ansi: '#ff6600'
});
/**
* An object storing the position of the point that was set. This is the point on the rectangle.
* It can be changed at runtime.
* ________
* | |
* | x |
* | |
* |_______|
* @private
* @type {Point}
* @prop {number} x - The raw x pixel position of this point
* @prop {number} y - The raw y pixel position of this point
*/
iconPoint = { x: 0, y: 0 };
/**
* @private
* @type {Point}
* @prop {number} x - The raw x pixel position of this point
* @prop {number} y - The raw y pixel position of this point
*/
originalPoint = { x: 0, y: 0 };
/**
* An object storing the position of the rectangle.
* @private
* @type {Point}
* @prop {number} x - The x position of the rectangle.
* @prop {number} y - The y position of the rectangle.
*/
positionalPoint;
/**
* An object storing the point's position with rotation taken into account.
* @private
* @type {Point}
* @prop {number} x - The x position of the point after rotation is applied.
* @prop {number} y - The y position of the point after rotation is applied.
*/
point = { x: 0, y: 0 };
/**
* An object storing the rectangle's size.
* @private
* @type {Bounds}
* @prop {number} width - The width of the rectangle.
* @prop {number} height - The height of the rectangle.
*/
bounds = { width: 32, height: 32 };
/**
* @param {Point} pPoint - The rectangle this icon point exists inside/outside of.
* @prop {number} pPoint.x - The x coordinate of the rectangle.
* @prop {number} pPoint.y - The y coordinate of the rectangle.
* @param {Bounds} pBounds - The size of the rectangle.
* @prop {number} pBounds.width - The width of the rectangle.
* @prop {number} pBounds.height - The height of the rectangle.
* @param {PositionalPoint} pIconPoint - The point that exists inside/outside the rectangle. This is in relative positioning to the rectangle.
* @prop {number} pIconPoint.x - The x coordinate of the point inside/outside the rectangle.
* @prop {number} pIconPoint.y - The y coordinate of the point inside/outside the rectangle.
* @prop {boolean} [pIconPoint.isNormalized=false] - Whether or not this point is normalized in a 0-1 range.
*
* ## Normalized
If you want to specify the point `(50, 50)` in a rectangle that is `100x100` using normalized values you would use `0.5`
The calculation will be `0.5 * 100` in both axis, which resolves to `(50, 50)`. This is just an easier way to assign the values.
*/
constructor(pPoint, pBounds, pIconPoint) {
const { width, height } = pBounds;
this.bounds.width = width;
this.bounds.height = height;
this.positionalPoint = pPoint;
this.originalPoint = { ...pIconPoint };
this.setPoint(pIconPoint);
}
/**
* Gets the new point's position inside a rectangle after taking pAngle into account.
* @param {number} [pAngle=0] - Rotation of the rectangle this point exists inside/outside of in radians.
* @param {Offset} [pOffset={ x: 0, y: 0 }] - The offset of the rectangle.
* @prop {number} pOffset.x - The x offset of the rectangle.
* @prop {number} pOffset.y - The y offset of the rectangle.
* @param {Anchor} [pAnchor={ x: 0.5, y: 0.5}] - The anchor origin of the rectangle.
* @prop {number} pAnchor.x - The x anchor of the rectangle.
* @prop {number} pAnchor.y - The y anchor of the rectangle.
* @example <caption>Example usage of this method</caption>
* // Create a rectangle at the position of (0,0)
* const rectangle = { x: 0, y: 0 };
* // Make the dimensions of the rectangle 100x50
* const bounds = { width: 100, height: 50 };
* // Create a point at the top left corner of the rectangle
* const point = { x: 1, y: 1 };
* // Create an icon point that will track the point on this rectangle when it moves/rotates
* const tlPoint = new IconPoint(rectangle, bounds, point);
*
* // Verify the point is where it should be
* console.log(tlPoint.getPoint()) // { x: 0, y: 0 } This shows that the point is at the position (0,0) which is the top left position of the rectangle
*
* // Changing the position of the rectangle
* rectangle.x += 100;
* // Verify the point is where it should be after the rectangle changes positions
* console.log(tlPoint.getPoint()) // { x: 100, y: 0 } This shows that the point has moved to the updated position of the rectangle
*
* // Applying some offsets to the rectangle
* const rectangleOffsets = { x: 25, y: 25 };
* // Verify the point is where it should be after offsets have been applied to the rectangle
* console.log(tlPoint.getPoint(undefined, rectangleOffsets)) // { x: 125, y: 25 } This shows that the point has moved to the updated position based on the offsets of the rectangle
*
* // Applying some rotation to the rectangle
* const angle = Math.PI;
* // Verify the point is where it should be after rotating the rectangle by `angle`
* console.log(tlPoint.getPoint(angle)) // {x: 200, y: 50.00000000000001} This shows that the point has moved to the updated position after the rectangle had been rotated by `angle`.
*
* @returns {object} The point inside/outside of the rectangle after rotating.
*/
getPoint(pAngle = 0, pOffset = IconPoint.defaultOffset, pAnchor = IconPoint.defaultAnchor) {
// cx, cy - center of square coordinates
// x, y - coordinates of a corner point of the square
// angle is the angle of rotation
const cx = (this.positionalPoint.x + pOffset.x) + this.bounds.width * pAnchor.x;
const cy = (this.positionalPoint.y + pOffset.y) + this.bounds.height * pAnchor.y;
// We take away 1 from the position of the rectangle because we don't want to point to start inside the boundaries of the rectangle
// Otherwise we would have to use 0 to (rectangle.xy-1) for the points coordinates
const pointX = (this.positionalPoint.x + pOffset.x - 1) + this.iconPoint.x;
const pointY = (this.positionalPoint.y + pOffset.y - 1) + this.iconPoint.y;
// translate point to origin
const tempX = pointX - cx;
const tempY = pointY - cy;
// now apply rotation
const rotatedX = tempX * Math.cos(pAngle) - tempY * -Math.sin(pAngle);
const rotatedY = tempX * -Math.sin(pAngle) + tempY * Math.cos(pAngle);
// translate back
const x = rotatedX + cx;
const y = rotatedY + cy;
this.point.x = x;
this.point.y = y;
return this.point;
}
/**
* Sets the static point and defines the raw pixels value
* @private
* @param {PositionalPoint} pPoint - The point that exists inside/outside the rectangle.
* @prop {number} pPoint.x - The x coordinate of the point inside/outside the rectangle.
* @prop {number} pPoint.y - The y coordinate of the point inside/outside the rectangle.
* @prop {boolean} [pPoint.isNormalized] - If the point's value is normalized.
*/
setPoint(pPoint) {
const { x, y, isNormalized } = pPoint;
this.iconPoint.x = isNormalized ? x * this.bounds.width : x;
this.iconPoint.y = isNormalized ? y * this.bounds.height : y;
}
/**
* Resets the point to the original point.
*/
resetPoint() {
this.setPoint(this.originalPoint);
}
/**
* Updates the bounds of the rectangle this icon point exists inside/outside of.
* @param {Bounds} pBounds - The bounds to update the rectangle with.
* @prop {number} pBounds.width - The width of the new rectangle.
* @prop {number} pBounds.height - The height of the new rectangle.
*/
updateBounds(pBounds) {
const { width, height } = pBounds;
this.bounds.width = width;
this.bounds.height = height;
}
/**
* Transforms the x point.
* @param {number} pTransformX - The x transform to transform the x point to.
*/
transformX(pTransformX) {
const boundsX = Math.abs(pTransformX * this.bounds.width);
this.iconPoint.x = boundsX - this.originalPoint.x;
}
/**
* Transforms the y point.
* @param {number} pTransformY - The y transform to transform the y point to.
*/
transformY(pTransformY) {
const boundsY = Math.abs(pTransformY * this.bounds.height);
this.iconPoint.y = boundsY - this.originalPoint.y;
}
/**
* Transforms the point.
* @param {Transform} pTransform - The transform to transform the point to.
*/
transform(pTransform) {
this.transformX(pTransform.x);
this.transformY(pTransform.y);
}
}
export { IconPoint };
//# sourceMappingURL=icon-point.mjs.map