LS's JS lib of prototypes
A Pen by Lovro Selic on CodePen.
LS's JS lib of prototypes
A Pen by Lovro Selic on CodePen.
console.clear(); | |
var LIB = { | |
VERSION: 2.05 | |
}; | |
/* | |
Prototype and helpful functions library | |
as used by LS | |
version 2.06 | |
changelog: | |
2.00: new main version, no backwards compatibility | |
2.01: array.removeRandomPool(N) | |
2.02: vector.mul default parameter set | |
2.03: Grid.distanceDiagonal | |
2.04: Vector.isDiagonal | |
2.05: Point.add() | |
2.06: round10() | |
*/ | |
(function() { | |
function RND(start, end) { | |
return Math.floor(Math.random() * (++end - start) + start); | |
} | |
function coinFlip() { | |
let flip = RND(0, 1); | |
if (flip) return true; | |
return false; | |
} | |
function probable(x) { | |
let flip = RND(0, 99); | |
if (flip <= x) return true; | |
return false; | |
} | |
function round10(x) { | |
return Math.round(x / 10) * 10; | |
} | |
window.RND = RND; | |
window.coinFlip = coinFlip; | |
window.probable = probable; | |
window.round10 = round10; | |
})(); | |
// Converts from degrees to radians. | |
Math.radians = function(degrees) { | |
return degrees * Math.PI / 180; | |
}; | |
// Converts from radians to degrees. | |
Math.degrees = function(radians) { | |
return radians * 180 / Math.PI; | |
}; | |
CanvasRenderingContext2D.prototype.pixelAt = function(x, y, size) { | |
size = size || 1; // default | |
this.fillRect(x, y, size, size); | |
}; | |
CanvasRenderingContext2D.prototype.roundRect = function( | |
x, | |
y, | |
width, | |
height, | |
radius, | |
fill, | |
stroke | |
) { | |
var cornerRadius = { | |
upperLeft: 0, | |
upperRight: 0, | |
lowerLeft: 0, | |
lowerRight: 0 | |
}; | |
if (typeof stroke == "undefined") { | |
stroke = true; | |
} | |
if (typeof radius === "object") { | |
for (let side in radius) { | |
cornerRadius[side] = radius[side]; | |
} | |
} | |
this.beginPath(); | |
this.moveTo(x + cornerRadius.upperLeft, y); | |
this.lineTo(x + width - cornerRadius.upperRight, y); | |
this.quadraticCurveTo(x + width, y, x + width, y + cornerRadius.upperRight); | |
this.lineTo(x + width, y + height - cornerRadius.lowerRight); | |
this.quadraticCurveTo( | |
x + width, | |
y + height, | |
x + width - cornerRadius.lowerRight, | |
y + height | |
); | |
this.lineTo(x + cornerRadius.lowerLeft, y + height); | |
this.quadraticCurveTo(x, y + height, x, y + height - cornerRadius.lowerLeft); | |
this.lineTo(x, y + cornerRadius.upperLeft); | |
this.quadraticCurveTo(x, y, x + cornerRadius.upperLeft, y); | |
this.closePath(); | |
if (stroke) { | |
this.stroke(); | |
} | |
if (fill) { | |
this.fill(); | |
} | |
}; | |
/* collection of prototypes LS */ | |
Array.prototype.clear = function() { | |
if (!this) return false; | |
this.splice(0, this.length); | |
}; | |
Array.prototype.swap = function(x, y) { | |
let TMP = this[x]; | |
this[x] = this[y]; | |
this[y] = TMP; | |
return this; | |
}; | |
Array.prototype.shuffle = function() { | |
var i = this.length, | |
j; | |
while (--i > 0) { | |
j = RND(0, i); | |
this.swap(i, j); | |
} | |
return this; | |
}; | |
Array.prototype.sum = function() { | |
return this.reduce((a, b) => a + b, 0); | |
}; | |
Array.prototype.average = function() { | |
return this.reduce((a, b) => a + b) / this.length; | |
}; | |
Array.prototype.createPool = function(mx, N) { | |
if (!this) return false; | |
this.clear(); | |
var tempArray = []; | |
for (var ix = 0; ix < mx; ix++) { | |
tempArray[ix] = ix; | |
} | |
var top; | |
for (var iy = 0; iy < N; iy++) { | |
top = tempArray.length; | |
var addx = RND(0, top - 1); | |
this[iy] = tempArray[addx]; | |
tempArray.splice(addx, 1); | |
} | |
return this; | |
}; | |
Array.prototype.compare = function(array) { | |
if (!array) return false; | |
var LN = this.length; | |
if (LN !== array.length) return false; | |
for (var x = 0; x < LN; x++) { | |
if (this[x] !== array[x]) return false; | |
} | |
return true; | |
}; | |
Array.prototype.remove = function(value) { | |
var LN = this.length; | |
for (var x = 0; x < LN; x++) { | |
if (this[x] === value) { | |
this.splice(x, 1); | |
this.remove(value); | |
} | |
} | |
}; | |
Array.prototype.chooseRandom = function() { | |
let LN = this.length; | |
let choose = RND(1, LN) - 1; | |
return this[choose]; | |
}; | |
Array.prototype.removeRandom = function() { | |
let LN = this.length; | |
let choose = RND(1, LN) - 1; | |
return this.splice(choose, 1)[0]; | |
}; | |
Array.prototype.removeRandomPool = function(N) { | |
let LN = this.length; | |
if (N >= LN) { | |
let temp = this.clone(); | |
this.clear(); | |
return temp; | |
} | |
if (N <= 0) return []; | |
let temp = []; | |
do { | |
temp.push(this.removeRandom()); | |
N--; | |
} while (N > 0); | |
return temp; | |
}; | |
Array.prototype.clone = function() { | |
return [].concat(this); | |
}; | |
Array.prototype.sortByPropAsc = function(prop) { | |
this.sort(sort); | |
function sort(a, b) { | |
return a[prop] - b[prop]; | |
} | |
}; | |
Array.prototype.sortByPropDesc = function(prop) { | |
this.sort(sort); | |
function sort(a, b) { | |
return b[prop] - a[prop]; | |
} | |
}; | |
String.prototype.capitalize = function() { | |
return this.charAt(0).toUpperCase() + this.substr(1).toLowerCase(); | |
}; | |
String.prototype.trimSpace = function() { | |
let temp = this.split(" "); | |
temp.remove(""); | |
return temp.join(" "); | |
}; | |
String.prototype.changeChar = function(at, char) { | |
let LN = this.length - 1; | |
if (at > LN || at < 0) return -1; | |
const p1 = this.slice(0, at); | |
const p2 = this.slice(at + 1, ++LN); | |
return [p1, char, p2].join(""); | |
}; | |
class Grid { | |
constructor(x = 0, y = 0) { | |
this.x = parseInt(x, 10); | |
this.y = parseInt(y, 10); | |
} | |
static toClass(grid) { | |
return new Grid(grid.x, grid.y); | |
} | |
add(vector) { | |
return new Grid(this.x + vector.x, this.y + vector.y); | |
} | |
isInAt(dirArray) { | |
for (let q = 0; q < dirArray.length; q++) { | |
if (this.x === dirArray[q].x && this.y === dirArray[q].y) { | |
return q; | |
} | |
} | |
return -1; | |
} | |
direction(vector) { | |
var dx = (vector.x - this.x) / Math.abs(this.x - vector.x) || 0; | |
var dy = (vector.y - this.y) / Math.abs(this.y - vector.y) || 0; | |
return new Vector(dx, dy); | |
} | |
absDirection(vector) { | |
let dx = vector.x - this.x; | |
let dy = vector.y - this.y; | |
return new Vector(dx, dy); | |
} | |
same(vector) { | |
if (this.x === vector.x && this.y === vector.y) { | |
return true; | |
} else return false; | |
} | |
distance(vector) { | |
let distance = Math.abs(this.x - vector.x) + Math.abs(this.y - vector.y); | |
return distance; | |
} | |
distanceDiagonal(vector) { | |
let distance = (this.x - vector.x) ** 2 + (this.y - vector.y) ** 2; | |
distance = Math.floor(Math.sqrt(distance)); | |
return distance; | |
} | |
directionSolutions(vector) { | |
let solutions = []; | |
let dir = this.direction(vector); | |
let absDir = this.absDirection(vector); | |
let split = dir.ortoSplit(); | |
solutions.push(new Direction(split[0], Math.abs(absDir.x))); | |
solutions.push(new Direction(split[1], Math.abs(absDir.y))); | |
//SORT!! | |
if (solutions[0].len < solutions[1].len) solutions.swap(0, 1); //check | |
return solutions; | |
} | |
} | |
class Vector { | |
constructor(x = 0, y = 0) { | |
this.x = parseInt(x, 10); | |
this.y = parseInt(y, 10); | |
} | |
static toClass(vector) { | |
return new Vector(vector.x, vector.y); | |
} | |
isInAt(dirArray) { | |
for (let q = 0; q < dirArray.length; q++) { | |
if (this.x === dirArray[q].x && this.y === dirArray[q].y) { | |
return q; | |
} | |
} | |
return -1; | |
} | |
isInPointerArray(dirArray) { | |
for (let q = 0; q < dirArray.length; q++) { | |
if (this.x === dirArray[q].vector.x && this.y === dirArray[q].vector.y) { | |
return q; | |
} | |
} | |
return -1; | |
} | |
add(vector) { | |
return new Vector(this.x + vector.x, this.y + vector.y); | |
} | |
mul(vector, num = 1) { | |
return new Vector(this.x + num * vector.x, this.y + num * vector.y); | |
} | |
distance(vector) { | |
let distance = Math.abs(this.x - vector.x) + Math.abs(this.y - vector.y); | |
return distance; | |
} | |
mirror() { | |
let nx, ny; | |
if (this.x) { | |
nx = -this.x; | |
} else { | |
nx = 0; | |
} | |
if (this.y) { | |
ny = -this.y; | |
} else { | |
ny = 0; | |
} | |
return new Vector(nx, ny); | |
} | |
direction(vector) { | |
let dx = (vector.x - this.x) / Math.abs(this.x - vector.x) || 0; | |
let dy = (vector.y - this.y) / Math.abs(this.y - vector.y) || 0; | |
return new Vector(dx, dy); | |
} | |
absDirection(vector) { | |
let dx = vector.x - this.x; | |
let dy = vector.y - this.y; | |
return new Vector(dx, dy); | |
} | |
directionSolutions(vector) { | |
let solutions = []; | |
let dir = this.direction(vector); | |
let absDir = this.absDirection(vector); | |
let split = dir.ortoSplit(); | |
solutions.push(new Direction(split[0], Math.abs(absDir.x))); | |
solutions.push(new Direction(split[1], Math.abs(absDir.y))); | |
//SORT!! | |
if (solutions[0].len < solutions[1].len) solutions.swap(0, 1); //check | |
return solutions; | |
} | |
ortoSplit() { | |
let split = []; | |
split.push(new Vector(this.x, 0)); | |
split.push(new Vector(0, this.y)); | |
return split; | |
} | |
cw() { | |
let directions = [UP, RIGHT, DOWN, LEFT]; | |
let q; | |
for (q = 0; q < 4; q++) { | |
if (this.same(directions[q])) { | |
q++; | |
if (q > 3) q = 0; | |
return directions[q]; | |
} | |
} | |
return null; | |
} | |
ccw() { | |
let directions = [UP, RIGHT, DOWN, LEFT]; | |
let q; | |
for (q = 0; q < 4; q++) { | |
if (this.same(directions[q])) { | |
q--; | |
if (q < 0) q = 3; | |
return directions[q]; | |
} | |
} | |
return null; | |
} | |
same(vector) { | |
if (this.x === vector.x && this.y === vector.y) { | |
return true; | |
} else return false; | |
} | |
isOrto() { | |
return this.x * this.y === 0; | |
} | |
isDiagonal(){ | |
return Math.abs(this.x) === Math.abs(this.y); | |
} | |
isContra(vector) { | |
let X = this.x + vector.x; | |
let Y = this.y + vector.y; | |
return X === 0 && Y === 0; | |
} | |
getDirectionAxis() { | |
if (this.x !== 0) { | |
return "x"; | |
} else if (this.y !== 0) { | |
return "y"; | |
} else throw ("error getting direction axis from", this); | |
} | |
trimMirror(dirArray) { | |
let axis = this.getDirectionAxis(); | |
let LN = dirArray.length; | |
for (let q = LN - 1; q >= 0; q--) { | |
if (dirArray[q][axis] === this[axis]) dirArray.splice(q, 1); | |
} | |
return dirArray; | |
} | |
} | |
class Direction { | |
constructor(vector, len, weight) { | |
//this.dir = vector; | |
this.dir = new Vector(vector.x, vector.y); | |
this.len = len || 1; | |
this.weight = weight || 0; | |
} | |
isInAt(dirArray) { | |
for (let q = 0; q < dirArray.length; q++) { | |
if ( | |
this.dir.x === dirArray[q].dir.x && | |
this.dir.y === dirArray[q].dir.y | |
) { | |
return q; | |
} | |
} | |
return -1; | |
} | |
} | |
class Point { | |
constructor(x = 0, y = 0) { | |
this.x = parseInt(x, 10); | |
this.y = parseInt(y, 10); | |
} | |
static toClass(point) { | |
return new Grid(point.x, point.y); | |
} | |
translate(vector, len = ENGINE.INI.GRIDPIX) { | |
return new Point(this.x + vector.x * len, this.y + vector.y * len); | |
} | |
toViewport() { | |
//change to offset | |
this.x = this.x - ENGINE.VIEWPORT.vx; | |
this.y = this.y - ENGINE.VIEWPORT.vy; | |
} | |
add(vector) { | |
return new Point(this.x + vector.x, this.y + vector.y); | |
} | |
} | |
class Pointer { | |
constructor(grid, vector) { | |
this.grid = Grid.toClass(grid); | |
this.vector = Vector.toClass(vector); | |
} | |
} | |
class Square { | |
constructor(x, y, w, h) { | |
this.x = x; | |
this.y = y; | |
this.w = w; | |
this.h = h; | |
} | |
} | |
var UP = new Vector(0, -1); | |
var DOWN = new Vector(0, 1); | |
var LEFT = new Vector(-1, 0); | |
var RIGHT = new Vector(1, 0); | |
var float64ToInt64Binary = (function() { | |
//https://stackoverflow.com/questions/9939760/how-do-i-convert-an-integer-to-binary-in-javascript | |
var flt64 = new Float64Array(1); | |
var uint16 = new Uint16Array(flt64.buffer); | |
var MAX_SAFE = Math.pow(2, 53) - 1; | |
var MAX_INT32 = Math.pow(2, 31); | |
function uint16ToBinary() { | |
var bin64 = ""; | |
for (var word = 0; word < 4; word++) { | |
bin64 = uint16[word].toString(2).padStart(16, 0) + bin64; | |
} | |
return bin64; | |
} | |
return function float64ToInt64Binary(number) { | |
if (Math.abs(number) > MAX_SAFE) { | |
throw new RangeError("Absolute value must be less than 2**53"); | |
} | |
if (Math.abs(number) <= MAX_INT32) { | |
return (number >>> 0).toString(2).padStart(64, "0"); | |
} | |
// little endian byte ordering | |
flt64[0] = number; | |
// subtract bias from exponent bits | |
var exponent = ((uint16[3] & 0x7ff0) >> 4) - 1023 + 1; //+1!! | |
// encode implicit leading bit of mantissa | |
uint16[3] |= 0x10; | |
// clear exponent and sign bit | |
uint16[3] &= 0x1f; | |
// only keep integer part of mantissa | |
var bin64 = uint16ToBinary().substr(11, Math.max(exponent, 0)); | |
return bin64; | |
}; | |
})(); | |
///////////////////////// | |
console.log(`Prototype LIB ${LIB.VERSION} loaded!`); |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> |