blue.js/libs/bluepixle.js

239 lines
8.2 KiB
JavaScript

// bluepixle.js
// This library is to help make using canvas tags easier
// requires bluemath.js
class shape {
constructor(type,coordinates,dimentions,rotation,fColor,bColor,bStyle,extraObject) {
this.type = "string" == typeof type ? (["rect","elipse","image"].includes(type) ? type : "rect") : "rect";
this.coordinates = coordinates instanceof vector ? coordinates : new vector([0,0]);
this.dimentions = dimentions instanceof vector ? dimentions : new vector([1,1]);
this.rotation = rotation instanceof vector ? rotation : new vector([0,1]);
this.fColor = "string" == typeof fColor ? fColor : undefined;
this.bColor = "string" == typeof bColor ? bColor : undefined;
this.bStyle = "number" == typeof bStyle ? bStyle : undefined;
this.extraObject = "object" == typeof extraObject ? extraObject : {};
if ("image" == this.type) {
this.imageData =
this.extraObject.imageData instanceof ImageData ?
this.extraObject.imageData :
new ImageData(
new Uint8ClampedArray([
255,0,0,255,
0,0,0,0,
255,0,0,255,
0,0,0,0,
255,0,0,255,
0,0,0,0,
255,0,0,255,
0,0,0,0,
255,0,0,255
]),3,3);
this.image = createImageBitmap(this.imageData);
}
}
render(ctx,position,rotation) {
// Save current defaults
var local = {};
local.fillStyle = "string" == typeof ctx.fillStyle ? ctx.fillStyle : undefined;
local.strokeStyle = "string" == ctx.strokeStyle ? ctx.strokeStyle : undefined;
local.lineWidth = "number" == ctx.lineWidth ? ctx.lineWidth : undefined;
local.imageSmoothingEnabled = ctx.imageSmoothingEnabled;
// calculate origin and rotation
var origin = this.coordinates.add(position instanceof vector ? position : new vector([0,0]));
var origRot = this.rotation.getRadAngle() + (rotation instanceof vector ? rotation : new vector([0,1])).getRadAngle();
var center = origin.add(this.dimentions.mag(0.5));
// Rotate
ctx.translate(center.d[0],center.d[1]);
ctx.rotate(origRot);
ctx.translate(-center.d[0],-center.d[1]);
// Draw
ctx.fillStyle = this.fcolor;
ctx.strokeStyle = this.bColor;
ctx.lineWidth = this.bStyle;
if("rect" == this.type) {
ctx.fillRect(origin.d[0],origin.d[1],this.dimentions.d[0],this.dimentions.d[1]);
ctx.strokeRect(origin.d[0],origin.d[1],this.dimentions.d[0],this.dimentions.d[1]);
} else if ("elipse" == this.type) {
ctx.beginPath();
ctx.ellipse(center.d[0],center.d[1],dimentions.d[0]/2,dimentions.d[1]/2,0,0,360);
ctx.stroke();
ctx.fill();
} else if ("image" == this.type) {
this.image.then(function (image) {
ctx.imageSmoothingEnabled = false;
ctx.drawImage(image,origin.d[0],origin.d[0],this.dimentions.d[0],this.dimentions.d[1]);
});
}
// restore context defaults
ctx.setTransform(1,0,0,1,0,0);
ctx.fillStyle = local.fillStyle;
ctx.strokeStyle = local.strokeStyle;
ctx.lineWidth = local.lineWidth;
ctx.imageSmoothingEnabled = local.imageSmoothingEnabled;
}
grow (amp) {
this.dimentions = this.dimentions.amp(amp);
}
}
class container {
constructor(coordinates,dimentions,rotation) {
this.coordinates = coordinates instanceof vector ? coordinates : new vector([0,0]);
this.size = dimentions instanceof vector ? dimentions : new vector([1,1]);
this.rotation = rotation instanceof vector ? rotation : new vector([0,1]);
this.movementVector = new vector([0,0]);
this.shapes = [];
this.containers = [];
}
addShape(myShape) {
if (myShape instanceof shape) {
this.shapes.push(myShape);
} else {
throw new TypeError("addShape Method must be given a shape object");
}
}
addContainer(myContainer) {
if (myContainer instanceof container) {
this.containers.push(container);
} else {
throw new TypeError("addContainer Method must be given a container object");
}
}
move(delta) {
delta = !isNaN(delta) ? delta : 0;
this.coordinates = this.coordinates.add(this.movementVector.mag(delta));
}
renderContainer(ctx,position,rotation) {
position = position instanceof vector ? position : new vector([0,0]);
rotation = rotation instanceof vector ? rotation : new vector([0,1]);
var refPos = this.coordinates.add(position);
var refRot = this.rotation.add(rotation);
if (this.shapes.length) {
this.shapes.forEach(shape => shape.render(ctx,refPos,refRot));
}
if (this.containers.length) {
this.containers.forEach(container => container.renderContainer(ctx,refPos,refRot));
}
}
grow(amp) {
amp = !isNaN(amp) ? amp : 1;
this.position.mag(amp);
if (this.shapes.length) {
this.shapes.forEach(shape => shape.grow(amp));
}
if (this.containers.length) {
this.containers.forEach( container => container.grow(amp));
}
}
bounce(surface) {
this.movementVector = this.movementVector.reflect(surface);
}
overlap(otherContainer, callbackFunction) {
var slowest = this.movementVector.getLength() <= otherContainer.movementVector.getLength() ? this : otherContainer;
var fastest = this.movementVector.getLength() <= otherContainer.movementVector.getLength() ? otherContainer : this;
var quickest = fastest.movementVector.getLength();
for (var t = 0; t <= quickest; t++) {
var tFraction = t/(quickest+1);
var Atop = slowest.coordinates.d[1]+(tFraction * slowest.movementVector.d[1]);
var Abottom = slowest.coordinates.d[1]+(tFraction * slowest.movementVector.d[1])+slowest.dimentions.d[0];
var Aleft = slowest.coordinates.d[0]+(tFraction * slowest.movementVector.d[0]);
var Aright = slowest.coordinates.d[0]+(tFraction * slowest.movementVector.d[0])+slowest.dimentions.d[1];
var Btop = fastest.coordinates.d[1]+(tFraction * fastest.movementVector.d[1]);
var Bbottom = fastest.coordinates.d[1]+(tFraction * fastest.movementVector.d[1])+fastest.dimentions.d[0];
var Bleft = fastest.coordinates.d[0]+(tFraction * fastest.movementVector.d[0]);
var Bright = fastest.coordinates.d[0]+(tFraction * fastest.movementVector.d[0])+fastest.dimentions.d[1];
var Abound = new bound([Aleft,Atop],[Aright,Abottom]);
var Bbound = new bound([Bleft,Btop],[Bright,Bbottom]);
if (
Bbound.inbounds([Aleft,Atop]) |
Bbound.inbounds([Aright,Atop]) |
Bbound.inbounds([Aleft,Abottom]) |
Bbound.inbounds([Aright,Abottom]) |
Abound.inbounds([Bleft,Btop]) |
Abound.inbounds([Bright,Btop]) |
Abound.inbounds([Bleft,Bbottom]) |
Abound.inbounds([Bright,Bbottom])
){
return callBackFunction(this,otherContainer,t);
}
}
return false;
}
}
function chase (source,target,max,minDis,acc) {
acc /= 100;
var sourceCenterX = source.x + (source.sizeX/2);
var sourceCenterY = source.y + (source.sizeY/2);
var targetCenterX = target.x + (target.sizeX/2);
var targetCenterY = target.y + (target.sizeY/2);
var deltaX = targetCenterX - sourceCenterX;
var deltaY = targetCenterY - sourceCenterY;
var theta = Math.atan2(deltaY,deltaX);
var dis = Math.sqrt(Math.pow(Math.abs(deltaX),2)+Math.pow(Math.abs(deltaY),2));
var dir = theta;
if (dis > minDis) {
dis = dis <= max ? dis : max;
source.direction = rad2deg(dir);
source.speed = (dis-minDis)*acc;
source.move(source.direction,source.speed);
}
}
function drawPixel (ctx, x, y, r, g, b, a) {
// Always validate your input
if (false == ctx instanceof CanvasRenderingContext2D) {
return new TypeError("ctx must be a 2D rendering context for canvas.");
}
x = x <= ctx.canvas.width ? x : ctx.canvas.width;
y = y <= ctx.canvas.height ? y : ctx.canvas.height;
r = r <= 255 ? r : 255;
r = r >= 0 ? r : 0;
g = g <= 255 ? g : 255;
g = g >= 0 ? g : 0;
b = b <= 255 ? b : 255;
b = b >= 0 ? b : 0;
a = a <= 255 ? a : 255;
a = a >= 0 ? a : 0;
// Do the thing
ctx.putImageData(new ImageData(new Uint8ClampedArray([r,g,b,a]),1,1),x,y);
}
class frameBuffer {
constructor(ctx, height, width) {
this.ctx = ctx;
this.height = height;
this.width = width;
this.containerArray = [];
}
addContainer(containerObject) { //might change this to auto create containers.
if (containerObject instanceof container) {
var index = this.containerArray.push(containerObject);
return this.containerArray[ index - 1];
} else {
throw new TypeError("addContainer Method must be given a container object");
}
}
pushFrame() {
var ctx = this.ctx;
ctx.clearRect(0,0,this.width,this.height);
this.containerArray.forEach(
function (container) { container.renderContainer(ctx,0,0); });
}
}