New folder in codebase
This commit is contained in:
419
src/API/DOM/Canvas.ts
Normal file
419
src/API/DOM/Canvas.ts
Normal file
@ -0,0 +1,419 @@
|
||||
import { OscilloscopeConfig } from "../../DOM/Visuals/Oscilloscope";
|
||||
import { ShapeObject, createConicGradient, createLinearGradient, createRadialGradient, drawBackground, drawBox, drawBall, drawBalloid, drawDonut, drawEquilateral, drawImage, drawPie, drawSmiley, drawStar, drawStroke, drawText, drawTriangular } from "../DOM/Visuals/CanvasVisuals";
|
||||
import { Editor } from "../../main";
|
||||
|
||||
|
||||
export const loadHydra = (app: Editor) => (): void => {
|
||||
app.ensureHydraLoaded()
|
||||
}
|
||||
|
||||
export const w = (app: Editor) => (): number => {
|
||||
const canvas: HTMLCanvasElement = app.interface.feedback as HTMLCanvasElement;
|
||||
return canvas.clientWidth;
|
||||
};
|
||||
|
||||
export const pulseLocation = (app: Editor) => (): number => {
|
||||
return ((app.api.epulse() / app.api.pulsesForBar()) * w(app)()) % w(app)();
|
||||
};
|
||||
|
||||
export const clear = (app: Editor) => (): boolean => {
|
||||
const canvas: HTMLCanvasElement = app.interface.feedback as HTMLCanvasElement;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
export const h = (app: Editor) => (): number => {
|
||||
const canvas: HTMLCanvasElement = app.interface.feedback as HTMLCanvasElement;
|
||||
return canvas.clientHeight;
|
||||
};
|
||||
|
||||
export const hc = (app: Editor) => (): number => {
|
||||
return h(app)() / 2;
|
||||
};
|
||||
|
||||
export const wc = (app: Editor) => (): number => {
|
||||
return w(app)() / 2;
|
||||
};
|
||||
|
||||
export const background = (app: Editor) => (color: string | number, ...gb: number[]): boolean => {
|
||||
drawBackground(app.interface.feedback as HTMLCanvasElement, color, ...gb);
|
||||
return true;
|
||||
};
|
||||
export const bg = background;
|
||||
|
||||
export const linearGradient = (app: Editor) => (x1: number, y1: number, x2: number, y2: number, ...stops: (number | string)[]): CanvasGradient => {
|
||||
return createLinearGradient(app.interface.feedback as HTMLCanvasElement, x1, y1, x2, y2, ...stops);
|
||||
};
|
||||
|
||||
export const radialGradient = (app: Editor) => (x1: number, y1: number, r1: number, x2: number, y2: number, r2: number, ...stops: (number | string)[]) => {
|
||||
return createRadialGradient(app.interface.feedback as HTMLCanvasElement, x1, y1, r1, x2, y2, r2, ...stops);
|
||||
};
|
||||
|
||||
export const conicGradient = (app: Editor) => (x: number, y: number, angle: number, ...stops: (number | string)[]) => {
|
||||
return createConicGradient(app.interface.feedback as HTMLCanvasElement, x, y, angle, ...stops);
|
||||
};
|
||||
|
||||
export const draw = (app: Editor) => (func: Function): boolean => {
|
||||
if (typeof func === "string") {
|
||||
drawText(app.interface.feedback as HTMLCanvasElement, func, 24, 0, "Arial", wc(app)(), hc(app)(), "white", "none");
|
||||
} else {
|
||||
const canvas: HTMLCanvasElement = app.interface.feedback as HTMLCanvasElement;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
func(ctx);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Additional drawing and utility functions in canvas.ts
|
||||
export const balloid = (app: Editor) => (
|
||||
curves: number | ShapeObject = 6,
|
||||
radius: number = hc(app)() / 2,
|
||||
curve: number = 1.5,
|
||||
fillStyle: string = "white",
|
||||
secondary: string = "black",
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof curves === "object") {
|
||||
fillStyle = curves.fillStyle || "white";
|
||||
x = curves.x || wc(app)();
|
||||
y = curves.y || hc(app)();
|
||||
curve = curves.curve || 1.5;
|
||||
radius = curves.radius || hc(app)() / 2;
|
||||
curves = curves.curves || 6;
|
||||
}
|
||||
drawBalloid(app.interface.feedback as HTMLCanvasElement, curves, radius, curve, fillStyle, secondary, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const equilateral = (app: Editor) => (
|
||||
radius: number | ShapeObject = hc(app)() / 3,
|
||||
fillStyle: string = "white",
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof radius === "object") {
|
||||
fillStyle = radius.fillStyle || "white";
|
||||
x = radius.x || wc(app)();
|
||||
y = radius.y || hc(app)();
|
||||
rotation = radius.rotation || 0;
|
||||
radius = radius.radius || hc(app)() / 3;
|
||||
}
|
||||
drawEquilateral(app.interface.feedback as HTMLCanvasElement, radius, fillStyle, rotation, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const triangular = (app: Editor) => (
|
||||
width: number | ShapeObject = hc(app)() / 3,
|
||||
height: number = hc(app)() / 3,
|
||||
fillStyle: string = "white",
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof width === "object") {
|
||||
fillStyle = width.fillStyle || "white";
|
||||
x = width.x || wc(app)();
|
||||
y = width.y || hc(app)();
|
||||
rotation = width.rotation || 0;
|
||||
height = width.height || hc(app)() / 3;
|
||||
width = width.width || hc(app)() / 3;
|
||||
}
|
||||
drawTriangular(app.interface.feedback as HTMLCanvasElement, width, height, fillStyle, rotation, x, y);
|
||||
return true;
|
||||
};
|
||||
export const pointy = triangular;
|
||||
|
||||
export const ball = (app: Editor) => (
|
||||
radius: number | ShapeObject = hc(app)() / 3,
|
||||
fillStyle: string = "white",
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof radius === "object") {
|
||||
fillStyle = radius.fillStyle || "white";
|
||||
x = radius.x || wc(app)();
|
||||
y = radius.y || hc(app)();
|
||||
radius = radius.radius || hc(app)() / 3;
|
||||
}
|
||||
drawBall(app.interface.feedback as HTMLCanvasElement, radius, fillStyle, x, y);
|
||||
return true;
|
||||
};
|
||||
export const circle = ball;
|
||||
|
||||
export const donut = (app: Editor) => (
|
||||
slices: number | ShapeObject = 3,
|
||||
eaten: number = 0,
|
||||
radius: number = hc(app)() / 3,
|
||||
hole: number = hc(app)() / 12,
|
||||
fillStyle: string = "white",
|
||||
secondary: string = "black",
|
||||
stroke: string = "black",
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof slices === "object") {
|
||||
fillStyle = slices.fillStyle || "white";
|
||||
x = slices.x || wc(app)();
|
||||
y = slices.y || hc(app)();
|
||||
rotation = slices.rotation || 0;
|
||||
radius = slices.radius || hc(app)() / 3;
|
||||
eaten = slices.eaten || 0;
|
||||
hole = slices.hole || hc(app)() / 12;
|
||||
secondary = slices.secondary || "black";
|
||||
stroke = slices.stroke || "black";
|
||||
slices = slices.slices || 3;
|
||||
}
|
||||
drawDonut(app.interface.feedback as HTMLCanvasElement, slices, eaten, radius, hole, fillStyle, secondary, stroke, rotation, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const pie = (app: Editor) => (
|
||||
slices: number | ShapeObject = 3,
|
||||
eaten: number = 0,
|
||||
radius: number = hc(app)() / 3,
|
||||
fillStyle: string = "white",
|
||||
secondary: string = "black",
|
||||
stroke: string = "black",
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof slices === "object") {
|
||||
fillStyle = slices.fillStyle || "white";
|
||||
x = slices.x || wc(app)();
|
||||
y = slices.y || hc(app)();
|
||||
rotation = slices.rotation || 0;
|
||||
radius = slices.radius || hc(app)() / 3;
|
||||
secondary = slices.secondary || "black";
|
||||
stroke = slices.stroke || "black";
|
||||
eaten = slices.eaten || 0;
|
||||
slices = slices.slices || 3;
|
||||
}
|
||||
drawPie(app.interface.feedback as HTMLCanvasElement, slices, eaten, radius, fillStyle, secondary, stroke, rotation, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const star = (app: Editor) => (
|
||||
points: number | ShapeObject = 5,
|
||||
radius: number = hc(app)() / 3,
|
||||
fillStyle: string = "white",
|
||||
rotation: number = 0,
|
||||
outerRadius: number = radius / 100,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof points === "object") {
|
||||
radius = points.radius || hc(app)() / 3;
|
||||
fillStyle = points.fillStyle || "white";
|
||||
x = points.x || wc(app)();
|
||||
y = points.y || hc(app)();
|
||||
rotation = points.rotation || 0;
|
||||
outerRadius = points.outerRadius || radius / 100;
|
||||
points = points.points || 5;
|
||||
}
|
||||
drawStar(app.interface.feedback as HTMLCanvasElement, points, radius, fillStyle, rotation, outerRadius, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const stroke = (app: Editor) => (
|
||||
width: number | ShapeObject = 1,
|
||||
strokeStyle: string = "white",
|
||||
rotation: number = 0,
|
||||
x1: number = wc(app)() - wc(app)() / 10,
|
||||
y1: number = hc(app)(),
|
||||
x2: number = wc(app)() + wc(app)() / 5,
|
||||
y2: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof width === "object") {
|
||||
strokeStyle = width.strokeStyle || "white";
|
||||
x1 = width.x1 || wc(app)() - wc(app)() / 10;
|
||||
y1 = width.y1 || hc(app)();
|
||||
x2 = width.x2 || wc(app)() + wc(app)() / 5;
|
||||
y2 = width.y2 || hc(app)();
|
||||
rotation = width.rotation || 0;
|
||||
width = width.width || 1;
|
||||
}
|
||||
drawStroke(app.interface.feedback as HTMLCanvasElement, width, strokeStyle, rotation, x1, y1, x2, y2);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const box = (app: Editor) => (
|
||||
width: number | ShapeObject = wc(app)() / 4,
|
||||
height: number = wc(app)() / 4,
|
||||
fillStyle: string = "white",
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)() - wc(app)() / 8,
|
||||
y: number = hc(app)() - hc(app)() / 8,
|
||||
): boolean => {
|
||||
if (typeof width === "object") {
|
||||
fillStyle = width.fillStyle || "white";
|
||||
x = width.x || wc(app)() - wc(app)() / 4;
|
||||
y = width.y || hc(app)() - hc(app)() / 2;
|
||||
rotation = width.rotation || 0;
|
||||
height = width.height || wc(app)() / 4;
|
||||
width = width.width || wc(app)() / 4;
|
||||
}
|
||||
drawBox(app.interface.feedback as HTMLCanvasElement, width, height, fillStyle, rotation, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const smiley = (app: Editor) => (
|
||||
happiness: number | ShapeObject = 0,
|
||||
radius: number = hc(app)() / 3,
|
||||
eyeSize: number = 3.0,
|
||||
fillStyle: string = "yellow",
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
): boolean => {
|
||||
if (typeof happiness === "object") {
|
||||
fillStyle = happiness.fillStyle || "yellow";
|
||||
x = happiness.x || wc(app)();
|
||||
y = happiness.y || hc(app)();
|
||||
rotation = happiness.rotation || 0;
|
||||
eyeSize = happiness.eyeSize || 3.0;
|
||||
radius = happiness.radius || hc(app)() / 3;
|
||||
happiness = happiness.happiness || 0;
|
||||
}
|
||||
drawSmiley(app.interface.feedback as HTMLCanvasElement, happiness, radius, eyeSize, fillStyle, rotation, x, y);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const text = (app: Editor) => (
|
||||
text: string | ShapeObject,
|
||||
fontSize: number = 24,
|
||||
rotation: number = 0,
|
||||
font: string = "Arial",
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
fillStyle: string = "white",
|
||||
filter: string = "none",
|
||||
): boolean => {
|
||||
if (typeof text === "object") {
|
||||
fillStyle = text.fillStyle || "white";
|
||||
x = text.x || wc(app)();
|
||||
y = text.y || hc(app)();
|
||||
rotation = text.rotation || 0;
|
||||
font = text.font || "Arial";
|
||||
fontSize = text.fontSize || 24;
|
||||
filter = text.filter || "none";
|
||||
text = text.text || "";
|
||||
}
|
||||
drawText(app.interface.feedback as HTMLCanvasElement, text, fontSize, rotation, font, x, y, fillStyle, filter);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const image = (app: Editor) => (
|
||||
url: string | ShapeObject,
|
||||
width: number = wc(app)() / 2,
|
||||
height: number = hc(app)() / 2,
|
||||
rotation: number = 0,
|
||||
x: number = wc(app)(),
|
||||
y: number = hc(app)(),
|
||||
filter: string = "none",
|
||||
): boolean => {
|
||||
if (typeof url === "object") {
|
||||
if (!url.url) return true;
|
||||
x = url.x || wc(app)();
|
||||
y = url.y || hc(app)();
|
||||
rotation = url.rotation || 0;
|
||||
width = url.width || 100;
|
||||
height = url.height || 100;
|
||||
filter = url.filter || "none";
|
||||
url = url.url || "";
|
||||
}
|
||||
drawImage(app.interface.feedback as HTMLCanvasElement, url, width, height, rotation, x, y, filter);
|
||||
return true;
|
||||
};
|
||||
|
||||
export const randomChar = () => (length: number = 1, min: number = 0, max: number = 65536): string => {
|
||||
return Array.from(
|
||||
{ length }, () => String.fromCodePoint(Math.floor(Math.random() * (max - min) + min))
|
||||
).join('');
|
||||
};
|
||||
|
||||
export const randomFromRange = () => (min: number, max: number): string => {
|
||||
const codePoint = Math.floor(Math.random() * (max - min) + min);
|
||||
return String.fromCodePoint(codePoint);
|
||||
};
|
||||
|
||||
export const emoji = () => (n: number = 1): string => {
|
||||
return randomChar()(n, 0x1f600, 0x1f64f);
|
||||
};
|
||||
|
||||
export const food = () => (n: number = 1): string => {
|
||||
return randomChar()(n, 0x1f32d, 0x1f37f);
|
||||
};
|
||||
|
||||
export const animals = () => (n: number = 1): string => {
|
||||
return randomChar()(n, 0x1f400, 0x1f4d3);
|
||||
};
|
||||
|
||||
export const expressions = () => (n: number = 1): string => {
|
||||
return randomChar()(n, 0x1f910, 0x1f92f);
|
||||
};
|
||||
|
||||
export const gif = (app: Editor) => (options: any): void => {
|
||||
const {
|
||||
url,
|
||||
posX = 0,
|
||||
posY = 0,
|
||||
opacity = 1,
|
||||
size = "auto",
|
||||
center = false,
|
||||
rotation = 0,
|
||||
filter = 'none',
|
||||
duration = 10
|
||||
} = options;
|
||||
|
||||
let real_duration = duration * app.clock.pulse_duration * app.clock.ppqn;
|
||||
let fadeOutDuration = real_duration * 0.1;
|
||||
let visibilityDuration = real_duration - fadeOutDuration;
|
||||
const gifElement = document.createElement("img");
|
||||
gifElement.src = url;
|
||||
gifElement.style.position = "fixed";
|
||||
gifElement.style.left = center ? "50%" : `${posX}px`;
|
||||
gifElement.style.top = center ? "50%" : `${posY}px`;
|
||||
gifElement.style.opacity = `${opacity}`;
|
||||
gifElement.style.zIndex = "1000"; // Ensure it's on top, fixed zIndex
|
||||
if (size !== "auto") {
|
||||
gifElement.style.width = size;
|
||||
gifElement.style.height = size;
|
||||
}
|
||||
const transformRules = [`rotate(${rotation}deg)`];
|
||||
if (center) {
|
||||
transformRules.unshift("translate(-50%, -50%)");
|
||||
}
|
||||
gifElement.style.transform = transformRules.join(" ");
|
||||
gifElement.style.filter = filter;
|
||||
gifElement.style.transition = `opacity ${fadeOutDuration}s ease`;
|
||||
document.body.appendChild(gifElement);
|
||||
|
||||
// Start the fade-out at the end of the visibility duration
|
||||
setTimeout(() => {
|
||||
gifElement.style.opacity = "0";
|
||||
}, visibilityDuration * 1000);
|
||||
|
||||
// Remove the GIF from the DOM after the fade-out duration
|
||||
setTimeout(() => {
|
||||
if (document.body.contains(gifElement)) {
|
||||
document.body.removeChild(gifElement);
|
||||
}
|
||||
}, real_duration * 1000);
|
||||
};
|
||||
|
||||
export const scope = (app: Editor) => (config: OscilloscopeConfig): void => {
|
||||
/**
|
||||
* Configures the oscilloscope.
|
||||
* @param config - The configuration object for the oscilloscope.
|
||||
*/
|
||||
app.osc = {
|
||||
...app.osc,
|
||||
...config,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user