3 changed files with 441 additions and 435 deletions
@ -0,0 +1,434 @@ |
|||
|
|||
/** |
|||
* Class containing two numbers. |
|||
* Usually they represent coordinates, |
|||
* but they also might serve as length and width |
|||
* as this class provides several convenience methods. |
|||
*/ |
|||
class TwoDimPoint { |
|||
/** |
|||
* |
|||
* @param {number} x |
|||
* @param {number} y |
|||
*/ |
|||
constructor(x = -1, y = -1) { |
|||
this.x = x; |
|||
this.y = y; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @returns {string} |
|||
*/ |
|||
toString() { |
|||
return `P(${this.x},${this.y})`; |
|||
} |
|||
|
|||
/** |
|||
* Loads the width and height of an element into the x and y of this TDP. |
|||
* @param {HTMLElement} element |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
loadFromElementDimensions(element) { |
|||
let bcr = element.getBoundingClientRect(); |
|||
this.x = bcr.width; |
|||
this.y = bcr.height; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Loads the coordinates of the top-left corner of an element, |
|||
* into the x and y of this TDP. |
|||
* @param {HTMLElement} element |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
loadFromElementZero(element) { |
|||
let bcr = element.getBoundingClientRect(); |
|||
this.x = bcr.left; |
|||
this.y = bcr.top; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Loads the coordinates of the bottom-right corner of an element, |
|||
* into the x and y of this TDP. |
|||
* @param {HTMLElement} element |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
loadFromElementMax(element) { |
|||
let bcr = element.getBoundingClientRect(); |
|||
this.x = bcr.left; |
|||
this.y = bcr.top; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* If onConditionMet is true (default) and the value of x is positive |
|||
* the x of this TDP will be multiplied with -1, |
|||
* otherwise nothing will be done. |
|||
* @param {boolean} [onConditionMet = true] onConditionMet |
|||
* @returns {TwoDimPoint} this TDP Object |
|||
*/ |
|||
setXAsNegative(onConditionMet = true) { |
|||
if (onConditionMet && this.x > 0) { |
|||
this.x = this.x * -1; |
|||
} |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* If onConditionMet is true (default) and the value of y is positive |
|||
* the y of this TDP will be multiplied with -1, |
|||
* otherwise nothing will be done. |
|||
* @param {boolean} [onConditionMet = true] onConditionMet |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setYAsNegative(onConditionMet = true) { |
|||
if (onConditionMet && this.y > 0) { |
|||
this.y = this.y * -1; |
|||
} |
|||
return this; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* |
|||
* @param {boolean} onConditionMetX |
|||
* @param {boolean} onConditionMetY |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setAsNegative(onConditionMetX, onConditionMetY) { |
|||
this.setXAsNegative(onConditionMetX); |
|||
this.setYAsNegative(onConditionMetY); |
|||
return this; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Subtracts the given Delta from the x-value |
|||
* @param {number} delta |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setXMinus(delta) { |
|||
this.x = this.x - delta; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Adds the given Delta from the x-value |
|||
* @param {number} delta |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setXPlus(delta) { |
|||
this.x = this.x + delta; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Subtracts the given Delta from the y-value |
|||
* @param {number} delta |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setYMinus(delta) { |
|||
this.y = this.y - delta; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Adds the given Delta from the y-value |
|||
* @param {number} delta |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setYPlus(delta) { |
|||
this.y = this.y + delta; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Returns the absolute delta between this x and given ref |
|||
* @param {number} refnumber |
|||
* @returns {number} |
|||
*/ |
|||
getXDeltaTo(refnumber) { |
|||
return Math.abs(this.x - refnumber); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Returns the absolute delta between this y and given ref |
|||
* @param {number} refnumber |
|||
* @returns {number} |
|||
*/ |
|||
getYDeltaTo(refnumber) { |
|||
return Math.abs(this.y - refnumber); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {number} times |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setXMultiplied(times) { |
|||
this.x = this.x * times; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {number} times |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setYMultiplied(times) { |
|||
this.y = this.y * times; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {number} times |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setXDivided(times) { |
|||
if (times === 0) { |
|||
throw new Error("Dividing by 0 is not defined"); |
|||
} |
|||
this.x = this.x / times; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {number} times |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setYDivided(times) { |
|||
if (times === 0) { |
|||
throw new Error("Dividing by 0 is not defined"); |
|||
} |
|||
this.y = this.y / times; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Subtracts the given Delta {TwoDimPoint} TDP from this TDP |
|||
* @param {TwoDimPoint} delta |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setThisByMinusTDP(delta) { |
|||
this.x = this.x - delta.x; |
|||
this.y = this.y - delta.y; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Adds the given Delta {TwoDimPoint} TDP to this TDP |
|||
* @param {TwoDimPoint} delta |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setThisByPlusTDP(delta) { |
|||
this.x = this.x + delta.x; |
|||
this.y = this.y + delta.y; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {nr} tdp |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setByMultipliedByNumber(nr) { |
|||
this.x = this.x * nr; |
|||
this.y = this.y * nr; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {TwoDimPoint} tdp |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setByMultipliedByTDP(tdp) { |
|||
this.x = this.x * tdp.x; |
|||
this.y = this.y * tdp.y; |
|||
return this; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @param {nr} tdp |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setByDividedByNumber(nr) { |
|||
if (nr === 0) { |
|||
throw new Error("Dividing by 0 is not defined"); |
|||
} |
|||
this.x = this.x / nr; |
|||
this.y = this.y / nr; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {TwoDimPoint} tdp |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
setByDividedByTDP(tdp) { |
|||
if (tdp.x === 0 | tdp.y === 0) { |
|||
throw new Error("Dividing by 0 is not defined"); |
|||
} |
|||
this.x = this.x / tdp.x; |
|||
this.y = this.y / tdp.y; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Creates and returns a new TDP |
|||
* consisting of the absolute deltas of the x/y coordinates of this and the reference TDP. |
|||
* @param {TwoDimPoint} refTDP |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
getNewDeltaTDP(refTDP) { |
|||
return new TwoDimPoint( |
|||
this.getXDeltaTo(refTDP.x), |
|||
this.getYDeltaTo(refTDP.y) |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Returns the absolute Distance between two points. |
|||
* @param {TwoDimPoint} refTDP |
|||
* @returns {number} |
|||
*/ |
|||
getDistanceBetween(refTDP) { |
|||
return Math.hypot( |
|||
this.getXDeltaTo(refTDP.x), |
|||
this.getYDeltaTo(refTDP.y) |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Returns a new TDP where x and y are calculated, |
|||
* based on the given distance and angle (degree). |
|||
* @param {number} distance |
|||
* @param {number} degrees |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
getNewTDPByDistance( |
|||
distance, |
|||
degrees |
|||
) { |
|||
/** angle in radians */ |
|||
let angle = ((parseFloat(degrees) * Math.PI) / 180); |
|||
return new TwoDimPoint( |
|||
this.x + distance * Math.cos(angle), |
|||
this.y + distance * Math.sin(angle), |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Multiplies both (x,y) with -1 to inverse them. |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
inverse() { |
|||
this.x = this.x * -1 |
|||
this.y = this.y * -1 |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Flips/changes x and y with each other. |
|||
* @returns {TwoDimPoint} |
|||
*/ |
|||
flip() { |
|||
let oldX = this.x; |
|||
this.x = this.y; |
|||
this.y = oldX; |
|||
return this; |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {number} start |
|||
* @param {number} end |
|||
* @param {number} value |
|||
* @param {number} tolerance |
|||
* @param {boolean} usePercentage |
|||
* @returns {boolean} |
|||
*/ |
|||
function isValueInBounds(start, end, value, tolerance = 0, usePercentage = false) { |
|||
if (tolerance !== 0) { |
|||
if (usePercentage) { |
|||
start = start * (1 - tolerance / 100); |
|||
end = end * (1 + tolerance / 100); |
|||
} else { |
|||
start = start - tolerance; |
|||
end = end + tolerance; |
|||
} |
|||
} |
|||
|
|||
return value >= start && value <= end; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @param {number} x |
|||
* @param {number} y |
|||
* @param {Map<SideDirections,number>} area |
|||
* @param {number} tolerance |
|||
* @param {boolean} usePercentage if tolerance is given and this is set to true, |
|||
* the tolerance will be calculated by percentage, |
|||
* otherwise it will be subtracted/added |
|||
* @returns {boolean} |
|||
*/ |
|||
function areXYInArea(x, y, area, tolerance = 0, usePercentage = false) { |
|||
return isValueInBounds( |
|||
area.get(SideDirections.LEFT), |
|||
area.get(SideDirections.RIGHT), |
|||
x, |
|||
tolerance, |
|||
usePercentage |
|||
) && isValueInBounds( |
|||
area.get(SideDirections.TOP), |
|||
area.get(SideDirections.BOTTOM), |
|||
y, |
|||
tolerance, |
|||
usePercentage |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {TwoDimPoint} point |
|||
* @param {Map<SideDirections,number>} area |
|||
* @param {number} tolerance |
|||
* @param {boolean} usePercentage if tolerance is given and this is set to true, |
|||
* the tolerance will be calculated by percentage, |
|||
* otherwise it will be subtracted/added |
|||
*/ |
|||
function isPointInArea(point, area, tolerance = 0, usePercentage = false) { |
|||
return areXYInArea( |
|||
point.x, |
|||
point.y, |
|||
area, |
|||
tolerance, |
|||
usePercentage |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param {HTMLElement} element |
|||
* @returns {Object<SideDirections, number} |
|||
*/ |
|||
function getEnclosingBounds(element) { |
|||
let area = element.getBoundingClientRect(); |
|||
let parentArea = element.parentElement.getBoundingClientRect(); |
|||
return { |
|||
[SideDirections.LEFT]: Math.min(area.left, parentArea.left), |
|||
[SideDirections.RIGHT]: Math.max(area.right, parentArea.right), |
|||
[SideDirections.TOP]: Math.min(area.top, parentArea.top), |
|||
[SideDirections.BOTTOM]: Math.max(area.bottom, parentArea.bottom) |
|||
} |
|||
} |
Loading…
Reference in new issue