const framerate = 20;
const pixelSize = 100;
const maxUpdateRate = 6000;
const pixelFuzz = document.getElementById("pixelfuzz");
const foreground = document.getElementById("foreground");
const borders = document.getElementById("borders");
const context = document.getElementById("context");
const cType = document.getElementById("c-type");
const cMod = document.getElementById("c-mod");
const cModText = document.getElementById("c-mod-text");
const cLittleMod = document.getElementById("c-littlemod");
const cValue = document.getElementById("c-value");
const cWarnings = document.getElementById("c-warnings");
const cSave = document.getElementById("c-save");
const pixel = document.createElement("div");
pixel.classList.add("pixel");
pixel.style.width = `${100/pixelSize}vw`;
pixel.style.height = pixel.style.width;
pixel.setAttribute("datatype", "undefined");
pixel.setAttribute("value", 0);
const border = document.createElement("div");
border.classList.add("border");
let mouse = [0,0];
document.addEventListener("mousemove", event => {
mouse = [event.clientX, event.clientY];
});
document.addEventListener("touchmove", event => {
const touch = event.touches[0];
mouse = [touch.clientX, touch.clientY];
});
let movingContext = false;
let originalMouse = [0,0];
let originalPos = [0, 0];
function setColor(type, value) {
if (type == "bool") {
if (value == 0) {
return "#000";
} else if (value == 1) {
return "#f00";
} else {
return `hsl(${60 * value / 255}, 30%, 50%)`;
}
} else if (type == "char") {
return `hsl(15, 100%, ${50 * value / 255}%)`;
} else if (type == "string") {
return `hsl(35, 100%, ${50 * value / 255}%)`;
} else if (type == "UTF8char") {
return `hsl(210, 100%, ${50 * value / 255}%)`;
} else if (type == "UTF8string") {
return `hsl(190, 100%, ${50 * value / 255}%)`;
} else if (type == "UTF16char") {
return `hsl(300, 100%, ${50 * value / 255}%)`;
} else if (type == "UTF16string") {
return `hsl(275, 100%, ${50 * value / 255}%)`;
} else if (type == "int8") {
return `hsl(75, 100%, ${50 * value / 255}%)`;
} else if (type == "int16") {
return `hsl(90, 100%, ${50 * value / 255}%)`;
} else if (type == "int32") {
return `hsl(120, 100%, ${50 * value / 255}%)`;
} else if (type == "int64") {
return `hsl(170, 100%, ${50 * value / 255}%)`;
} else {
return `rgb(${value}, ${value}, ${value})`;
}
}
/*
* byte/int8 (8b) -> vihertävä keltainen
* short/int16 (16b) -> kellertävä vihreä
* int/int32 (32b) -> vihreä
* long/int64 (64b) -> turkoosi
* [EHKÄ] BigInt -> tummankeltaisesta vihreään ja turkoosiin
* (float ja double ehkä joskus myöhemmin)
* char (8b) -> punertava oranssi
* string (char[>2]) -> oranssi
* UTF8char (8b-32b) -> alkupään sininen
* UTF8string (UTF8char[>2]) -> sinertävä syaani
* UTF16char (16b, 32b) -> magenta
* UTF16string (UTF16char[>2]) -> violetti
* bool (8b) -> musta (false) / punainen (true) / hieman harmaansävyinen punainen-keltainen (true>1)
*/
function updateColor(cell) {
const color = setColor(cell.getAttribute("datatype"), cell.getAttribute("value"));
cell.style.backgroundColor = color;
cell.style.borderColor = color;
}
let allocs = [];
let editing = null;
let autosave;
function setAutosave(value, updateAuto=true) {
if (updateAuto) {
autosave = value;
}
cSave.disabled = value;
}
setAutosave(true);
function setEditing(alloc) {
movingContext = false;
const original = editing;
editing?.getParent().classList.remove("selected");
editing = alloc;
editing?.getParent().classList.add("selected");
if (editing) {
const ctxStyles = window.getComputedStyle(context);
const ctxSizes = [parseFloat(ctxStyles.width), parseFloat(ctxStyles.height)];
context.style.left = `${Math.min(mouse[0], window.innerWidth - ctxSizes[0])}px`;
context.style.top = `${Math.min(mouse[1], window.innerHeight - ctxSizes[1])}px`;
context.style.visibility = "visible";
context.style.scale = 1;
context.style.opacity = 1;
} else {
context.style.visibility = "";
context.style.scale = "";
context.style.opacity = "";
}
if (editing == original) return; // Don't continue if unchanged
else if (editing) {
const datatype = editing.getDatatype();
if (datatype == "undefined") {
cType.value = "undefined";
updateCMod();
updateCValue();
} else if (datatype == "bool") {
cType.value = "bool";
updateCMod();
updateCValue();
} else if (datatype.includes("char") || datatype.includes("string")) {
cType.value = "char";
const encoding = updateCMod();
updateCValue();
const cValueText = cValue.querySelector("textarea");
if (datatype.includes("UTF8")) {
encoding.value = "UTF-8";
cValueText.value = editing.getString("UTF-8");
} else if (datatype.includes("UTF16")) {
encoding.value = "UTF-16";
cValueText.value = editing.getString("UTF-16");
} else {
encoding.value = "ASCII";
cValueText.value = editing.getString("ASCII");
}
updateCValue();
} else if (datatype.includes("int")) {
cType.value = "int";
const type = updateCMod();
updateCValue();
type.value = datatype;
}
}
}
function deselectAlloc() {
setEditing(null);
}
function deallocate() {
if (editing) {
editing.dealloc();
setEditing(null);
}
}
function clearAlloc() {
if (editing) {
editing.clear();
updateCValue();
}
}
pixelFuzz.addEventListener("mousedown", deselectAlloc);
pixelFuzz.addEventListener("touchstart", deselectAlloc);
document.addEventListener("keydown", event => {
if (event.key == "Escape") {
deselectAlloc();
}
});
function contextMouseDown(event) {
event.stopPropagation();
if (event instanceof MouseEvent && event.button == 1) {
event.preventDefault();
originalPos = [parseFloat(context.style.left), parseFloat(context.style.top)];
originalMouse = [event.clientX, event.clientY];
movingContext = true;
context.style.transition = "none";
}
// TODO: For mobile
}
context.addEventListener("mousedown", contextMouseDown);
context.addEventListener("touchstart", contextMouseDown);
class Allocation {
constructor(cells, index) {
this._cells = cells ? cells : [];
this._parent = border.cloneNode(true);
this._index = index;
this._unsigned = false;
this._parent.addEventListener("mousedown", event => {
event.stopPropagation();
});
this._parent.addEventListener("touchstart", event => {
event.stopPropagation();
});
this._parent.addEventListener("click", event => {
event.stopPropagation();
setEditing(this);
});
}
getCells() {
return this._cells;
}
getParent() {
return this._parent;
}
getIndex() {
return this._index;
}
getUnsigned() {
return this._unsigned;
}
setUnsigned(boolean) {
this._unsigned = boolean;
}
getDatatype() {
return this.getCells()[0].getAttribute("datatype");
}
updateIndex() {
this._index = allocs.indexOf(this);
}
setupBorder(appending=false) {
const parent = this.getParent();
const cells = this.getCells();
const pos0 = cells[0];
const pos1 = cells[cells.length - 1];
parent.style.left = `calc(${pos0.style.left} + 1.25px)`;
parent.style.top = `calc(${pos0.style.top} + 1.25px)`;
const computedStyles = [window.getComputedStyle(pos0), window.getComputedStyle(pos1)];
parent.style.width = `${parseFloat(computedStyles[1].left) - parseFloat(computedStyles[0].left) + parseFloat(computedStyles[1].width) - 2.5}px`;
parent.style.height = `${parseFloat(computedStyles[1].top) - parseFloat(computedStyles[0].top) + parseFloat(computedStyles[1].height) - 2.5}px`;
if (appending) borders.appendChild(parent);
}
add(cell) {
this._cells[this._cells.length] = cell;
}
clear(datatype=null) {
this.getCells().forEach(cell => {
if (datatype) {
cell.setAttribute("datatype", datatype);
}
cell.setAttribute("value", 0);
});
}
convert(datatype="undefined") {
this.getCells().forEach(cell => {
cell.setAttribute("datatype", datatype);
});
}
setInt(integer, bytesize=4, firstcell=0, unsigned=false) {
let rawInt;
if (bytesize == 8) {
rawInt = unsigned ? new BigInt64Array([BigInt(integer)]) : new BigUint64Array([BigInt(integer)]);
} else if (bytesize == 4) {
rawInt = unsigned ? new Uint32Array([integer]) : new Int32Array([integer]);
} else if (bytesize == 2) {
rawInt = unsigned ? new Uint16Array([integer]) : new Int16Array([integer]);
} else {
rawInt = unsigned ? new Uint8Array([integer]) : new Int8Array([integer]);
}
const bytes = new Uint8Array(rawInt.buffer);
const amount = Math.min(this.getCells().length - firstcell, bytesize);
const intrinsicAmount = Math.min(this.getCells().length, bytesize);
for (let i = 0; i < amount; i++) {
this.getCells()[firstcell + i].setAttribute("value", bytes[i]);
}
}
setString(string, encoding="UTF-8") {
let usableEncoding = encoding.toUpperCase();
let bytes;
if (usableEncoding == "ASCII" || usableEncoding == "UTF-8") {
bytes = new TextEncoder().encode(string);
} else if (usableEncoding == "UTF-16") {
const rawBytepairs = [];
for (let i = 0; i < string.length; i++) {
rawBytepairs.push(string.charCodeAt(i));
}
bytes = new Uint8Array(new Uint16Array(rawBytepairs).buffer);
}
for (let i = 0; i < bytes.length; i++) {
this.setInt(bytes[i], 1, i, true);
}
}
getTooLongMsg(string, encoding="UTF-8") {
let usableEncoding = encoding.toUpperCase();
let bytes;
if (usableEncoding == "ASCII" || usableEncoding == "UTF-8") {
bytes = new TextEncoder().encode(string);
} else if (usableEncoding == "UTF-16") {
const rawBytepairs = [];
for (let i = 0; i < string.length; i++) {
rawBytepairs.push(string.charCodeAt(i));
}
bytes = new Uint8Array(new Uint16Array(rawBytepairs).buffer);
}
const overflow = bytes.length - this.getCells().length;
return (overflow > 0) ? `Warning: String is ${overflow} byte${(overflow > 1) ? "s" : ""} too long, truncating.` : "";
}
getInt(bytesize=4, firstcell=0, unsigned=false) {
const rawValues = [];
const amount = Math.min(this.getCells().length - firstcell, bytesize);
for (let i = 0; i < amount; i++) {
rawValues.push(parseInt(this.getCells()[firstcell + i].getAttribute("value")));
}
const missingValues = (rawValues.length % bytesize == 0) ? 0 : bytesize - rawValues.length % bytesize;
for (let i = 0; i < missingValues; i++) {
rawValues.push(0);
}
const values = new Uint8Array(rawValues);
if (bytesize == 8) {
return unsigned ? new BigUint64Array(values.buffer)[0] : new BigInt64Array(values.buffer)[0];
} else if (bytesize == 4) {
return unsigned ? new Uint32Array(values.buffer)[0] : new Int32Array(values.buffer)[0];
} else if (bytesize == 2) {
return unsigned ? new Uint16Array(values.buffer)[0] : new Int16Array(values.buffer)[0];
} else {
return unsigned ? new Uint8Array(values.buffer)[0] : new Int8Array(values.buffer)[0];
}
}
getString(encoding="UTF-8") {
let usableEncoding = encoding.toUpperCase();
const rawBytes = [];
for (let i = 0; i < this.getCells().length; i++) {
rawBytes.push(parseInt(this.getCells()[i].getAttribute("value")));
}
let rawString = "";
if (usableEncoding == "ASCII") {
const decoder = new TextDecoder("UTF-8");
for (let i = 0; i < rawBytes.length; i++) {
rawString += (rawBytes[i] > 127) ? "\uFFFD" : decoder.decode(new Uint8Array([rawBytes[i]]));
}
} else if (usableEncoding == "UTF-8") {
rawString = new TextDecoder("UTF-8").decode(new Uint8Array(rawBytes));
} else if (usableEncoding == "UTF-16") {
let odd = (rawBytes.length % 2 == 1);
if (odd) {
rawBytes.push(0);
}
rawString = new TextDecoder("UTF-16").decode(new Uint8Array(rawBytes));
if (odd) {
rawBytes.pop();
}
}
let string = "";
let stringCache = "";
for (let i = 0; i < rawString.length; i++) { // Truncate trailing NULs
stringCache += rawString[i];
if (rawString[i] != '\x00') {
string += stringCache;
stringCache = "";
}
}
return string;
}
isString(encoding="UTF-8") {
const value = this.getString(encoding);
return (value.length > 1)
}
dealloc() {
this.convert();
this.getCells().forEach(cell => {
pixelFuzz.appendChild(cell);
});
for (let i = 0; i < allocs.length; i++) {
if (allocs[i] === this) allocs.splice(i, 1);
break;
}
this.getParent().remove();
if (editing === this) {
setEditing(null);
}
delete this;
}
updateColors() {
this.getCells().forEach(cell => {
updateColor(cell);
})
}
}
let nowString = false;
function updateSelectedType() {
if (editing) {
if (cType.value == "undefined") {
editing.convert("undefined");
} else if (cType.value == "bool") {
editing.convert("bool");
} else if (cType.value == "char") {
const encoding = cMod.querySelector("select");
nowString = editing.isString(encoding.value);
if (encoding.value == "ASCII") {
editing.convert((nowString) ? "string" : "char");
} else if (encoding.value == "UTF-8") {
editing.convert((nowString) ? "UTF8string" : "UTF8char");
} else {
editing.convert((nowString) ? "UTF16string" : "UTF16char");
}
} else if (cType.value == "int") {
const type = cMod.querySelector("select");
editing.convert(type.value);
}
}
}
function updateCMod() {
if (editing) {
setAutosave(true);
cMod.innerHTML = "";
cLittleMod.innerHTML = "";
if (cType.value == "undefined") {
cModText.textContent = "Modifier:";
const empty = document.createElement("span");
empty.textContent = "undefined";
cMod.appendChild(empty);
return empty;
} else if (cType.value == "bool") {
cModText.textContent = "Modifier:";
const single = document.createElement("span");
single.textContent = "bool";
cMod.appendChild(single);
return single;
} else if (cType.value == "char") {
cModText.textContent = "Encoding:";
const encoding = document.createElement("select");
encoding.innerHTML = `
`;
encoding.name = "char-encoding";
encoding.value = "UTF-8";
encoding.addEventListener("input", () => {
updateSelectedType();
updateCValue();
});
cMod.appendChild(encoding);
return encoding;
} else if (cType.value == "int") {
cModText.textContent = "Size:";
const type = document.createElement("select");
type.innerHTML = `
`;
type.name = "int-type";
type.value = "int32";
type.addEventListener("input", () => {
updateSelectedType();
updateCValue();
});
cMod.appendChild(type);
const littleModText = document.createElement("span");
littleModText.textContent = "Unsigned:";
const unsigned = document.createElement("input");
unsigned.type = "checkbox";
unsigned.name = "int-unsigned";
unsigned.checked = editing.getUnsigned();
unsigned.addEventListener("input", () => {
editing.setUnsigned(unsigned.checked);
updateSelectedType();
updateCValue();
});
cLittleMod.appendChild(littleModText);
cLittleMod.appendChild(unsigned);
return type;
}
}
}
function saveCharType() {
const textArea = cValue.querySelector("textarea");
if (editing && textArea) {
setAutosave(true);
editing.clear();
editing.setString(textArea.value, cMod.querySelector("select").value);
if (textArea.value.length > 1 && !nowString) {
nowString = true;
updateSelectedType();
} else if (textArea.value.length <= 1 && nowString) {
nowString = false;
updateSelectedType();
}
}
}
function updateCValue() {
if (!editing) return;
const datatype = editing.getDatatype();
cValue.innerHTML = "";
cWarnings.innerHTML = "";
if (datatype == "undefined") {
cValue.innerHTML = "^^^
Choose a type to start...";
} else if (datatype == "bool") {
for (let i = 0; i < editing.getCells().length; i++) {
const boolean = document.createElement("div");
const index = document.createElement("span");
index.textContent = `[${i}]: `;
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.id = `alloc-value-${i}`;
checkbox.checked = (editing.getCells()[i].getAttribute("value") >= 1);
const textValue = document.createElement("label");
textValue.setAttribute("for", checkbox.id);
if (editing.getCells()[i].getAttribute("value") <= 1) {
textValue.style.fontWeight = "bold";
textValue.style.fontStyle = "normal";
textValue.textContent = (checkbox.checked) ? "TRUE" : "FALSE";
} else {
textValue.style.fontWeight = "normal";
textValue.style.fontStyle = "italic";
textValue.textContent = `true (${editing.getCells()[i].getAttribute("value")})`;
}
checkbox.addEventListener("input", () => {
if (editing) {
editing.getCells()[i].setAttribute("value", checkbox.checked ? 1 : 0);
updateColor(editing.getCells()[i]);
textValue.style.fontWeight = "bold";
textValue.style.fontStyle = "normal";
textValue.textContent = (checkbox.checked) ? "TRUE" : "FALSE";
}
});
boolean.appendChild(index);
boolean.appendChild(checkbox);
boolean.appendChild(textValue);
cValue.appendChild(boolean);
}
}
else if (datatype.includes("char") || datatype.includes("string")) {
const textArea = document.createElement("textarea");
textArea.placeholder = "Enter value (char/string)";
textArea.name = "alloc-value";
textArea.autocomplete = "off";
textArea.value = editing.getString(cMod.querySelector("select").value);
const tooLong = document.createElement("div");
tooLong.classList.add("c-warning");
function rescaleTooLong() {
tooLong.style.width = window.getComputedStyle(textArea).width;
requestAnimationFrame(rescaleTooLong);
}
rescaleTooLong();
if (datatype != "char" && datatype != "string") {
tooLong.textContent = editing.getTooLongMsg(textArea.value, cMod.querySelector("select").value);
}
const replacementChars = textArea.value.includes("\uFFFD");
setAutosave(!replacementChars || datatype == "char" || datatype == "string", datatype != "char" || datatype != "string");
textArea.disabled = (replacementChars && (datatype == "char" || datatype == "string"));
textArea.addEventListener("input", () => {
if (editing) {
tooLong.textContent = editing.getTooLongMsg(textArea.value, cMod.querySelector("select").value);
if (cType.value == "char" && autosave) {
saveCharType();
}
}
});
cValue.appendChild(textArea);
cWarnings.appendChild(tooLong);
} else if (datatype.includes("int")) {
const byteSize = parseInt(datatype.match(/\d+/)) / 8;
for (let i = 0; i < Math.floor(editing.getCells().length / byteSize); i++) {
const unsigned = editing.getUnsigned();
const integer = document.createElement("div");
const index = document.createElement("span");
index.textContent = `[${i}]: `;
const input = document.createElement("input");
input.type = "text";
input.name = `alloc-value-${i}`;
const savedValue = editing.getInt(byteSize, i * byteSize, unsigned).toString();
input.value = savedValue;
input.setAttribute("savedvalue", savedValue);
if (datatype == "int64") {
input.addEventListener("input", () => {
if (editing) {
input.value = input.value.replace(".", "");
if (unsigned) {
input.value = input.value.replace("-", "");
} else {
input.value = input.value.replace(/-+/, "-");
}
let value;
if (isNaN(input.value) && input.value != "-") {
input.value = input.getAttribute("savedvalue");
}
if (input.value == "-") {
value = "-";
} else {
value = BigInt(input.value);
if ((unsigned && (value < 0n || value > 2n**BigInt(8 * byteSize) - 1n)) || (!unsigned && (value < -(2n**BigInt(8 * byteSize - 1)) || value > 2n**BigInt(8 * byteSize - 1) - 1n))) {
input.value = input.getAttribute("savedvalue");
value = BigInt(input.getAttribute("savedvalue"));
}
editing.setInt(value, byteSize, i * byteSize, unsigned);
updateColor(editing.getCells()[i * byteSize]);
}
input.setAttribute("savedvalue", value.toString());
}
});
} else {
input.addEventListener("input", () => {
if (editing) {
input.value = input.value.replace(".", "");
if (unsigned) {
input.value = input.value.replace("-", "");
} else {
input.value = input.value.replace(/-+/, "-");
}
let value;
if (isNaN(input.value) && input.value != "-") {
input.value = input.getAttribute("savedvalue");
}
if (input.value == "-") {
value = "-";
} else {
value = parseInt(input.value);
if (isNaN(value)) {
value = 0;
}
if ((unsigned && (value < 0 || value > 2**(8 * byteSize) - 1)) || (!unsigned && (value < -(2**(8 * byteSize - 1)) || value > 2**(8 * byteSize - 1) - 1))) {
input.value = input.getAttribute("savedvalue");
value = parseInt(input.getAttribute("savedvalue"));
}
editing.setInt(value, byteSize, i * byteSize, unsigned);
updateColor(editing.getCells()[i * byteSize]);
}
input.setAttribute("savedvalue", value.toString());
}
});
}
integer.appendChild(index);
integer.appendChild(input);
cValue.appendChild(integer);
}
}
}
cType.addEventListener("input", () => {
updateCMod();
updateSelectedType();
updateCValue();
});
let cells = [];
for (let i = 0; i < pixelSize; i++) {
if (cells[i] === undefined) {
cells[i] = [];
}
for (let j = 0; j < pixelSize; j++) {
const clone = pixel.cloneNode(true);
let untilChange = Math.floor(Math.random() * maxUpdateRate / framerate);
clone.style.top = `calc(50vh - 50vw + ${100 / pixelSize * i}vw)`;
clone.style.left = `${100 / pixelSize * j}vw`;
pixelFuzz.appendChild(clone);
cells[i][j] = clone;
setInterval(() => {
updateColor(clone);
untilChange -= 1;
if (untilChange <= 0) {
if (clone.parentNode.id == "pixelfuzz") {
clone.setAttribute("value", Math.floor(Math.random() * 256));
}
untilChange = Math.floor(Math.random() * maxUpdateRate / framerate);
}
if (!editing) {
window.getSelection().removeAllRanges();
}
}, framerate);
}
}
let initMousePos;
let hold = false;
const selectionBox = document.createElement("div");
selectionBox.style.background = "unset";
selectionBox.style.outline = "1px solid";
selectionBox.style.outlineColor = "transparent";
selectionBox.style.position = "fixed";
document.body.insertBefore(selectionBox, borders);
function mouseDown(event) {
if (event instanceof MouseEvent && event.button != 0) return; // Only left click if mouse
if (event instanceof MouseEvent) {
initMousePos = [event.clientX, event.clientY];
} else if (event instanceof TouchEvent) {
initMousePos = [event.touches[0].clientX, event.touches[0].clientY]
}
hold = true;
selectionBox.style.left = `${initMousePos[0]}px`;
selectionBox.style.top = `${initMousePos[1]}px`;
selectionBox.style.width = 0;
selectionBox.style.height = 0;
selectionBox.style.outlineColor = "#ff0";
}
function mouseUp(event) {
if (event instanceof MouseEvent && event.button == 1) {
event.preventDefault();
movingContext = false;
context.style.transition = "";
} // TODO: For mobile
if (!hold) return; // Proceed only if held
hold = false;
selectionBox.style.outlineColor = "transparent";
let insideBox = [];
const selectionPos = [parseFloat(selectionBox.style.left), parseFloat(selectionBox.style.top)];
const selectionSize = [parseFloat(selectionBox.style.width), parseFloat(selectionBox.style.height)];
let exclusive = true;
for (let i = 0; i < foreground.children.length; i++) {
const child = foreground.children[i];
const positions = [parseFloat(window.getComputedStyle(child).left), parseFloat(window.getComputedStyle(child).top)];
const sizes = [parseFloat(window.getComputedStyle(child).width), parseFloat(window.getComputedStyle(child).height)];
if (
positions[0] <= selectionPos[0] + selectionSize[0] &&
positions[1] <= selectionPos[1] + selectionSize[1] &&
positions[0] + sizes[0] >= selectionPos[0] &&
positions[1] + sizes[1] >= selectionPos[1]
) {
exclusive = false;
break;
}
}
if (exclusive) {
let newAlloc = new Allocation();
allocs.push(newAlloc);
for (let i = 0; i < cells.length; i++) {
for (let j = 0; j < cells[i].length; j++) {
const child = cells[i][j];
if (child.parentNode == pixelFuzz) {
const positions = [parseFloat(window.getComputedStyle(child).left), parseFloat(window.getComputedStyle(child).top)];
const sizes = [parseFloat(window.getComputedStyle(child).width), parseFloat(window.getComputedStyle(child).height)];
if (
positions[0] <= selectionPos[0] + selectionSize[0] &&
positions[1] <= selectionPos[1] + selectionSize[1] &&
positions[0] + sizes[0] >= selectionPos[0] &&
positions[1] + sizes[1] >= selectionPos[1]
) {
insideBox[insideBox.length] = child;
}
}
}
}
insideBox.forEach(child => {
foreground.appendChild(child);
newAlloc.add(child);
});
newAlloc.setupBorder(true);
}
}
document.addEventListener("mousedown", mouseDown);
document.addEventListener("touchstart", mouseDown);
document.addEventListener("mouseup", mouseUp);
document.addEventListener("touchend", mouseUp);
function resizeSelection(event) {
let mousePos;
if (event instanceof MouseEvent) {
mousePos = [event.clientX, event.clientY];
} else if (event instanceof TouchEvent) {
mousePos = [event.touches[0].clientX, event.touches[0].clientY];
}
if (hold) {
selectionBox.style.width = `${Math.max(mousePos[0] - initMousePos[0], initMousePos[0] - mousePos[0])}px`;
selectionBox.style.height = `${Math.max(mousePos[1] - initMousePos[1], initMousePos[1] - mousePos[1])}px`;
selectionBox.style.left = `${Math.min(initMousePos[0], mousePos[0])}px`;
selectionBox.style.top = `${Math.min(initMousePos[1], mousePos[1])}px`;
}
}
document.addEventListener("mousemove", resizeSelection);
document.addEventListener("touchmove", resizeSelection);
window.addEventListener("resize", () => {
allocs.forEach(alloc => {
alloc.setupBorder();
});
});
function frame() {
if (movingContext) {
context.style.left = `${originalPos[0] + mouse[0] - originalMouse[0]}px`;
context.style.top = `${originalPos[1] + mouse[1] - originalMouse[1]}px`;
}
requestAnimationFrame(frame);
}
frame();