Gathering detailed insights and metrics for @ericrovell/vector
Gathering detailed insights and metrics for @ericrovell/vector
Gathering detailed insights and metrics for @ericrovell/vector
Gathering detailed insights and metrics for @ericrovell/vector
npm install @ericrovell/vector
Typescript
Module System
Node Version
NPM Version
70.8
Supply Chain
99.3
Quality
76.8
Maintenance
100
Vulnerability
100
License
v1.0.0: Stable release
Published on 21 Mar 2024
0.17.0
Published on 22 May 2023
0.16.0
Published on 20 May 2023
0.15.0: Mapping
Published on 12 Dec 2022
0.14.0: Math utils & missing mutable methods
Published on 12 Dec 2022
0.13.0: Inverse Scaling
Published on 10 Dec 2022
TypeScript (98.6%)
JavaScript (1.4%)
Total Downloads
3,524
Last Day
1
Last Week
21
Last Month
36
Last Year
636
181 Commits
1 Watching
1 Branches
1 Contributors
Latest Version
1.0.0
Package Id
@ericrovell/vector@1.0.0
Unpacked Size
47.62 kB
Size
10.64 kB
File Count
5
NPM Version
10.5.0
Node Version
21.7.1
Publised On
21 Mar 2024
Cumulative downloads
Total Downloads
Last day
0%
1
Compared to previous day
Last week
600%
21
Compared to previous week
Last month
157.1%
36
Compared to previous month
Last year
-59.8%
636
Compared to previous year
Euclidean vector (also known as "Geometric" vector) library written in Typescript. A vector is an entity that has both magnitude and direction. Both 2D and 3D vectors are supported.
Package available via npm:
npm i @ericrovell/vector
1import { vector } from "@ericrovell/vector"; 2 3vector(1, 2).toString(); // -> "(1, 2, 0)"
Types for supported input are included into the package.
(x: number = 0, y: number = 0, z: number = 0)
Parses vector components from arguments.
1vector().toString(); // -> "(0, 0, 0)" 2vector(1).toString(); // -> "(1, 0, 0)" 3vector(1, 2).toString(); // -> "(1, 2, 0)" 4vector(1, 2, 3).toString(); // -> "(1, 2, 3)"
({ x: number = 0, y: number = 0, z: number = 0 }: Cartesian)
Parses the given input from Cartesian
object and returns a new Vector
instance.
1/** 2* Vector state defined in Cartesian coordinate system. 3*/ 4interface Cartesian { 5 x?: number; 6 y?: number; 7 z?: number; 8} 9 10vector({ x: 1 }).toString(); // -> "(1, 0, 0)" 11vector({ x: 1, y: 2 }).toString(); // -> "(1, 2, 0)" 12vector({ x: 1, y: 2, z: 3 }).toString(); // -> "(1, 2, 3)"
The Cartesian
object is considered valid if it is contains at least one of coordinate components: x
, y
, or z
. All missed components defaults to zero, extra data are simply ignored.
1vector({ x: 1, data: "hello!" }).toString(); // -> "(1, 0, 0)" 2vector({ x: 1, y: 2, z: 3, data: "hello!" }).toString(); // -> "(1, 2, 3)"
([ x: number, y: number = 0, z: number = 0 ]: CartesianTuple)
Parses the given input from CartesianTuple
and returns a new Vector
instance.
1/** 2* Tuple defining vector state defined in Cartesian coordinate system. 3*/ 4type CartesianTuple = readonly [ x: number, y?: number, z?: number ]; 5 6vector([ 1 ]).toString(); // -> "(1, 0, 0)" 7vector([ 1, 2 ]).toString(); // -> "(0, 2, 0)" 8vector([ 1, 2, 3 ]).toString(); // -> "(0, 0, 3)"
({ degrees?: boolean, magnitude?: number = 1, phi: number = 0, theta: number = Math.PI / 2 }: Polar)
Parses the Polar
input representing the vector in polar coordinates and returns a new Vector
instance:
1/** 2* Vector state defined in Polar coordinate system: 3*/ 4interface Polar { 5 degrees?: boolean = false; 6 magnitude?: number = 1; 7 phi: number; 8 theta?: number = Math.PI / 2; 9} 10 11vector({ phi: 0 }).toString() // -> "(1, 0, 0)" 12 13vector({ phi: Math.PI / 2 })); // -> "(0, 1, 0)"; 14 15vector({ 16 phi: Math.PI / 2, 17 theta: Math.PI / 2, 18 magnitude: 2 19}) // -> "(0, 2, 0)";
By default angles input require radians. To use degrees, pass a degrees
boolean argument:
1vector({ degrees: true, phi: 0 }) // -> "(1, 0, 0)"); 2vector({ degrees: true, phi: 90 }) // -> "(0, 1, 0)"); 3vector({ degrees: true, phi: 90, theta: 0, magnitude: 2 }) // -> "(0, 0, 2)"); 4vector({ degrees: true, phi: 90, theta: 90, magnitude: 2 }) // -> "(0, 2, 0)");
The Polar
object is considered valid if it is contains at least one of angle properties: phi
or theta
. The magnitude
defaults to a unit length.
({ degrees?: boolean, p?: number = 1, phi: number = 0, z: number = 0 }: Cylindrical)
Parses the given input from Cylindrical
representing the vector in cylindrical coordinate system and returns a new Vector
instance:
1/** 2* Vector state defined in Cylindrical coordinate system: 3*/ 4interface Cylindrical { 5 degrees?: boolean = false; 6 p: number = 1; 7 phi: number = 0; 8 z: number = 0; 9} 10 11vector({ p: Math.SQRT2, phi: Math.PI / 4, z: 5 })) // -> "(1, 1, 5)" 12vector({ p: 7.0711, phi: -Math.PI / 4, z: 12 })) // -> "(5, -5, 12)"
By default angles input require radians. To use degrees, pass a degrees
boolean argument:
1vector({ degrees: true, p: Math.SQRT2, phi: 45, z: 5 })) // -> "(1, 1, 5)" 2vector({ degrees: true, p: 7.0711, phi: -45, z: 12 })) // -> "(5, -5, 12)"
The Cylindrical
object is considered valid if it is contains all the properties: p
, phi
, and z
. Only degrees
property is optional.
Most methods input arguments signature is:
1(x: VectorInput | number, y?: number, z?: number)
Where the VectorInput
is any supported valid vector input representation. This way the valid input besides numeric arguments are:
Cartesian
;CartesianTuple
;Polar
;Cylindrical
;Vector
instance;1const instance = vector(1, 2, 3); 2 3vector(1, 2, 3).add({ x: 1, y: 2, z: 3 }).toString(); // "(2, 4, 6)"; 4vector(1, 2, 3).add(instance).toString() // "(2, 4, 6)"; 5vector({ x: 1, y: 2, z: 3 }).add([ 1, 2, 3]).toString(); // "(2, 4, 6)";
.add(x: VectorInput | number, y?: number, z?: number): Vector
Performs the addition and returns the sum as new Vector
instance.
1vector(1, 2).add(3, 4).toString(); // -> "(4, 6, 0)"
.addSelf(x: VectorInput | number, y?: number, z?: number): Vector
Adds the another Vector
instance or a valid vector input to this vector.
1const v1 = vector(1, 2, 3).addSelf(1, 2, 3); 2const v2 = vector(1, 2, 3); 3 4v1.addSelf(v2); 5v1.toString(); // -> "(2, 4, 6)"
.angle(input: VectorInput, signed = false, degrees = false): number
Calculates the angle between the vector instance and another valid vector input.
The angle can be signed if signed
boolean argument is passed.
1vector(1, 2, 3).angle(4, 5, 6) // -> 0.22573 2vector(1, 2, 3).angle(4, 5, 6, true) // -> -0.22573 3vector(1, 2, 3).angle(4, 5, 6, true, true) // -> -12.93315
Note: this method do not accept simple arguments input.
.ceilSelf(places = 0): Vector
Rounds this vector's components values to the next upper bound with defined precision.
1vector(1.12345, 2.45678, 3.78921).ceilSelf().toString() // -> "(2, 3, 4)"); 2vector(Math.SQRT2, Math.PI, 2 * Math.PI).ceilSelf(3).toString() // -> "(1.415, 3.142, 6.284)");
.clamp(min = 0, max = 1): Vector
Clamps this vector's component values between an upper and lower bound.
1vector(1.2, -1).clamp().toString() // -> "(1, 0, 0)"); 2vector(5, 10, -2).clamp(2, 8).toString() // -> "(5, 8, 2)");
.copy(): Vector
Returns a copy of the vector instance.
1const a = vector(1, 2, 3); 2const b = a.copy(); 3 4b.toString(); // -> "(1, 2, 3)"
.cross(x: VectorInput | number, y?: number, z?: number): Vector
Calculates the cross product between the instance and another valid vector input and returns a new Vector
instance.
1vector(1, 2, 3).cross(4, 5, 6) // -> (-3, 6, -3)
.crossSelf(x: VectorInput | number, y?: number, z?: number): Vector
Sets this vector to the cross product between the original vector and another valid input.
1vector(1, 2, 3).crossSelf(4, 5, 6) // -> (-3, 6, -3)
.distance(x: VectorInput | number, y?: number, z?: number): number
Calculates the Euclidean distance between the vector and another valid vector input, considering a point as a vector.
1vector(1, 2, 3).distance(4, 5, 6) // -> 5.19615
.distanceSq(x: VectorInput | number, y?: number, z?: number): number
Calculates the squared Euclidean distance between the vector and another valid vector input, considering a point as a vector. Slightly more efficient to calculate, useful to comparing.
1vector(1, 2, 3).distanceSq(4, 5, 6) // -> 27
.dot(x: VectorInput | number, y?: number, z?: number): number
Calculates the dot product of the vector and another valid vector input.
1vector(1, 2, 3).dot(4, 5, 6) // -> 32
.equals(x: VectorInput | number, y?: number, z?: number): boolean
Performs an equality check against another valid vector input.
1vector(1, 2, 3).equals(1, 2, 3); // -> true 2vector({ x: 1, y: 2 }).equals([ 1, 2 ]); // -> true 3vector({ x: -1, y: -2 }).equals({ x: -1, y: 2}); // -> false
.floorSelf(places = 0): Vector
Rounds this vector's components values to the next lower bound with defined precision.
1vector(1.12345, 2.45678, 3.78921).floorSelf(4).toString() // -> "(1.1234, 2.4567, 3.7892)"); 2vector(Math.SQRT2, Math.PI, 2 * Math.PI).floorSelf(3).toString() // -> "(1.414, 3.141, 6.283)");
.getPhi(degrees = false): number
Calculates vector's azimuthal angle.
1vector(3, 4).getPhi(); // -> 0.927295 2vector(1, -2, 3).getPhi(true); // -> 53.130102
.getTheta(degrees = false): number
Calculates vector's elevation angle.
1vector(3, 4, 5).getTheta(); // -> 0.785398 2vector(3, 4, 5).getTheta(true); // -> 45
.inverted: Vector
Returns an inverted Vector
instance.
1vector(-1, 2).inverted; // -> "(1, -2, 0)"
.lerp(input: VectorInput, coef = 1): Vector
Linearly interpolate the vector to another vector.
1const a = vector([ 4, 8, 16 ]); 2const b = vector([ 8, 24, 48 ]); 3 4a.lerp(b) // -> "(4, 8, 16)" 5a.lerp(b, -0.5) // -> "(4, 8, 16)" 6a.lerp(b, 0.25) // -> "(5, 12, 24)" 7a.lerp(b, 0.5) // -> "(6, 16, 32)" 8a.lerp(b, 0.75) // -> "(7, 20, 40)" 9a.lerp(b, 1) // -> "(8, 24, 48)" 10a.lerp(b, 1.5) // -> "(8, 24, 48)"
Note: this method do not accept simple arguments input.
.limit(value: number): Vector
Limits the magnitude of the vector and returns the result as new Vector
instance.
1const v = vector(3, 4, 12); // magnitude is 13 2 3v.limit(15).magnitude // -> 13 4v.limit(10).magnitude // -> 10 5v.limit(13).magnitude // -> 13
.limitSelf(value: number): Vector
Limits the magnitude of this vector and returns itself.
1const v = vector(3, 4, 12); // magnitude is 13 2 3v.limitSelf(15).magnitude // -> 13 4v.limitSelf(10).magnitude // -> 10 5v.limitSelf(13).magnitude // -> 13
.magnitude: number
Calculates the magnitude of the vector:
1vector(0).magnitude; // -> 0 2vector(3, 4).magnitude; // -> 5 3vector(3, 4, 12).magnitude; // -> 13
.map(fn: (value: number) => number): Vector
Calls a defined callback on every vector component and returns a new Vector
instance:
1vector(1, 2, 3) 2.map(value => value * 2) 3.toString() // -> "(2, 4, 6)"
.mapSelf(fn: (value: number) => number): Vector
Calls a defined callback on each of this vector component.
1const v = vector(1, 2, 3); 2v.mapSelf(value => value * 2); 3v.toString() // -> "(2, 4, 6)"
.magnitudeSq: number
Calculates the squared magnitude of the vector. It may be useful and faster where the real value is not that important. For example, to compare two vectors' length.
1vector(0).magnitudeSq; // -> 0 2vector(3, 4).magnitudeSq; // -> 25 3vector(3, 4, 12).magnitudeSq; // -> 169
.normalize(): Vector
Normalizes the vector and returns a new Vector
instance as unit vector:
1vector().normalize().magnitude; // -> 1 2vector(3, 4, 5).normalize().magnitude; // -> 1
.normalizeSelf(): Vector
Makes the current vector a unit vector.
1vector().normalizeSelf().magnitude; // -> 0 2vector(3, 4, 12).normalizeSelf().magnitude; // -> 13
.random2d(random = Math.random): Vector
Creates a random planar unit vector (OXY plane).
1vector().random2d().toString() // -> "(0.23565, 0.75624, 0)"
.random3d(random = Math.random): Vector
Creates a random 3D unit vector.
Correct distribution thanks to wolfram.
1vector().random3d().toString() // -> "(0.23565, 0.75624, -0.56571)"
.reflect(x: VectorInput | number, y?: number, z?: number): Vector
Reflects the vector about a normal line for 2D vector, or about a normal to a plane in 3D.
Here, in an example the vector a
can be viewed as the incident ray, the vector n
as the normal, and the resulting vector should be the reflected ray.
1const a = vector([ 4, 6 ]); 2const n = vector([ 0, -1 ]); 3 4a.reflect(n).toString() // -> "(4, -6, 0)"
.rotate(value: number, degrees = false): Vector
Rotates the vector by an azimuthal angle (XOY plane) and returns a new Vector
instance.
1vector(1, 2).rotate(Math.PI / 3); 2vector(1, 2).rotate(60, true);
.rotateSelf(value: number, degrees = false): Vector
Rotates the current vector by an azimuthal angle (XOY plane).
1vector(1, 2).rotateSelf(Math.PI / 3); 2vector(1, 2).rotateSelf(60, true);
.rotate3d(phi: number = 0, theta: number = 0, degrees = false): Vector
Rotates the vector by an azimuthal and elevation angles and returns a new Vector
instance.
1vector(1, 2, 3).rotate3d(Math.PI / 3, Math.PI / 6); 2vector(1, 2, 3).rotate3d(60, 30, true);
.rotateSelf3d(phi: number = 0, theta: number = 0, degrees = false): Vector
Rotates the current vector by an azimuthal and elevation angles.
1vector(1, 2, 3).rotateSelf3d(Math.PI / 3, Math.PI / 6); 2vector(1, 2, 3).rotateSelf3d(60, 30, true);
.roundSelf(places = 0): Vector
Rounds this vector's component values to the closest bound with defined precision.
1vector(1.12345, 2.45678, 3.78921).roundSelf(4).toString() // -> "(1.1235, 2.4568, 3.7892)"); 2vector(Math.SQRT2, Math.PI, 2 * Math.PI).roundSelf(3).toString() // -> "(1.414, 3.142, 6.283)");
.scale(value: number, inverse = false): Vector
Performs the scalar vector multiplication and returns a new Vector
instance:
1vector(1, 2).scale(2).toString(); // -> "(2, 4, 0)" 2vector(1, 2, 3).scale(-2).toString(); // -> "(-2, -4, -6)"
The second argument turns the passed value
into reciprocal, in other words the division will be performed:
1vector(2, 4, 6).scale(2, true).toString(); // -> "(1, 2, 3)"
Although the same effect can be obtained just with .scale(0.5)
, it is useful when the variable may have zero value. In case of zero division the zero vector will be returned and marked as invalid.
1const v = vector(1, 2, 3).scale(0, true); 2 3v.valid // -> false 4v.toString() // -> "(0, 0, 0)"
.scaleSelf(value: number, inverse = false): Vector
Scales this vector by a scalar value.
1const a = vector(-1, 2, 3).scaleSelf(5); 2 3a.toString() // -> "(-5, 10, 15)"
The second parameter turns the passed value
into reciprocal, in other words the division will be performed:
1const v = vector(-12, -18, -24).scale(2, true); 2v.toString(); // -> "(-6, -9, -12)"
It is useful when the variable may have zero value. In this case the vector components won't change.
.setSelf(x: VectorInput | number, y?: number, z?: number): Vector
Set's the current vector state from another Vector
instance or valid vector input.
1const v1 = vector(1, 2, 3); 2v1.setSelf(-1, -2, -3); 3 4v1.toString() // -> "(-1, -2, -3)"
.setComponent(component: Component, value: number): Vector
Creates and returns a new Vector
instance with modified component value.
1vector(1, 2, 3).setComponent("x", 2).toString(); // -> "(2, 2, 3)" 2vector(1, 2, 3).setComponent("y", 3).toString(); // -> "(1, 3, 3)" 3vector(1, 2, 3).setComponent("z", 4).toString(); // -> "(1, 2, 4)"
.setComponentSelf(component: Component, value: number): Vector
Sets the vector instance component value.
1const v = vector(1, 2, 3) 2 .setComponentSelf("x", 0) 3 .setComponentSelf("y", 0) 4 .setComponentSelf("z", 0) 5 6v.toString() // -> "(0, 0, 0)"
.setMagnitude(value: number): Vector
Sets the magnitude of the vector and returns a new Vector
instance.
1vector(1).setMagnitude(5).magnitude // -> 5; 2vector(1, 2, 3).setMagnitude(5).magnitude // -> 5;
.setMagnitudeSelf(value: number): Vector
Sets the magnitude of this vector.
1vector(1).setMagnitudeSelf(5).magnitude // -> 5; 2vector(1, 2, 3).setMagnitudeSelf(-5).magnitude // -> 5;
.setPhi(value: number, degrees = false): Vector
Rotates the vector instance to a specific azimuthal angle (OXY plane) and returns a new Vector
instance.
1vector(1, 2).setPhi(Math.PI / 3); 2vector(1, 2, 3).setPhi(60, true);
.setPhiSelf(value: number, degrees = false): Vector
Rotates the vector instance to a specific azimuthal angle (OXY plane).
1vector(1, 2).setPhiSelf(Math.PI / 3); 2vector(1, 2, 3).setPhiSelf(60, true);
.setTheta(value: number, degrees = false): Vector
Rotates the vector instance to a specific elevation angle and returns a new Vector
instance.
1vector(1, 2).setTheta(Math.PI / 3); 2vector(1, 2, 3).setTheta(60, true);
.setThetaSelf(value: number, degrees = false): Vector
Rotates the vector instance to a specific elevation angle.
1vector(1, 2).setThetaSelf(Math.PI / 3); 2vector(1, 2, 3).setThetaSelf(60, true);
.sub(x: VectorInput | number, y?: number, z?: number): Vector
Performs the subtraction and returns the result as new Vector
instance.
1vector(1, 2, 3).sub(2, 3, 4).toString() // -> "(-1, -1, -1)"
.subSelf(x: VectorInput | number, y?: number, z?: number): Vector
Subtracts another Vector
instance or valid vector input from this vector.
1const v1 = vector(1, 2, 3); 2const v2 = vector(2, 1, 5); 3 4v1.subSelf(v2); 5v1.toString(); // -> "(-1, 1, -2)"
.toArray(): number[]
Returns vector's components packed into array.
1vector(1).toArray(); // -> [ 1, 0, 0 ] 2vector(1, 2).toArray(); // -> [ 1, 2, 0 ] 3vector(1, 2, 3).toArray(); // -> [ 1, 2, 3 ]
.toString(): `(x: number, y: number, z: number)`
Returns a Vector
string representation.
1vector(1).toString(); // -> "(1, 0, 0)" 2vector(1, 2).toString(); // -> "(1, 2, 0)" 3vector(1, 2, 3).toString(); // -> "(1, 2, 3)"
.valid: boolean
Passing an invalid input does not throw error. Getter returns a boolean indicating whether user input was valid or not.
Invalid input defaults to zero vector.
1vector([ 1, 2 ]).valid; // -> true 2vector([ NaN ]).valid; // -> false 3vector({ x: 1, y: 2 }).valid; // -> true 4vector({ a: 1, b: 2 }).valid; // -> false
.valueOf(): number
Converts the vector instance to primitive value - it's magnitude. May be useful when using type coercion.
1const a = vector(3, 4); 2const b = vector(6, 8); 3 4a + b // -> 15
All operations have both mutable and immutable methods. They are easy to distinguish by self
postfix:
.add()
is immutable;addSelf()
is mutable;To extend the functionality for your needs, extend the parent Vector
class:
1import { Vector, type VectorInput } from "@ericrovell/vector"; 2 3class VectorExtended extends Vector { 4 constructor(input: VectorInput) { 5 super(input); 6 } 7 8 get sum() { 9 return this.x + this.y + this.z; 10 } 11} 12 13const instance = new VectorExtended([ 1, 2, 3 ]); 14instance.sum; // -> 6
Most of the methods are chainable, no matter is it mutable or immutable method:
1const v = vector(1, 2, 3) 2 .add(1, 2, 3) 3 .sub(1, 2, 3) 4 .scale(2) 5 .toString(); // "(2, 4, 6)"; 6 7const v = vector(1, 2, 3) 8 .addSelf(1, 2, 3) 9 .subSelf(1, 2, 3) 10 .scaleSelf(2) 11 .toString(); // "(2, 4, 6)";
The Vector
instance can be iterated via for ... of
loop to loop through the vector's components:
1const v = vector(1, 2, 3); 2 3for (const component of v) { 4 console.log(component); 5 // -> yielding 1, 2, 3 6}
The same way the spread operator can be used, Array.from()
, and all other methods and functions that operates on iterables.
Tha package includes all necessary types useful for all possible valid input options are available for import:
1export type { 2 Cartesian, 3 CartesianTuple, 4 Polar, 5 Cylindrical, 6 VectorInput, 7 Vector 8} from "@ericrovell/vector";
To run the tests use the npm run test
command.
Vector's logo is done thanks to FreakAddL
No vulnerabilities found.
No security vulnerabilities found.