373 lines
10 KiB
TypeScript
373 lines
10 KiB
TypeScript
var KeyHandler: KeyHandler = {
|
|
elements: {
|
|
keys: {}
|
|
},
|
|
|
|
selected: [],
|
|
imagecache: {},
|
|
ghostImage: null,
|
|
|
|
init() {
|
|
KeyHandler.ghostImage = new Image();
|
|
KeyHandler.ghostImage.src = '/stc/icon/ghost.png';
|
|
KeyHandler.ghostImage.onload = () => {
|
|
for (var y = 0; y < 4; y++) {
|
|
if (KeyHandler.elements.keys[y] == undefined) KeyHandler.elements.keys[y] = {};
|
|
for (var x = 0; x < 8; x++) {
|
|
var keyCheck: HTMLDivElement = document.querySelector(`.key[y="${y}"][x="${x}"]`);
|
|
if (keyCheck) {
|
|
((keyX: number, keyY: number, key: HTMLDivElement) => {
|
|
var canvas = key.querySelector('canvas');
|
|
var context = canvas.getContext('2d');
|
|
KeyHandler.elements.keys[keyY][keyX] = { key, canvas, context };
|
|
|
|
context.textBaseline = 'middle';
|
|
context.textAlign = 'center';
|
|
|
|
key.onclick = () => {
|
|
if (altDown == false) KeyHandler.select(String(keyX), String(keyY));
|
|
else {
|
|
socket.emit('page', 'executekey', PageHandler.currentPageID, keyX, keyY);
|
|
}
|
|
};
|
|
})(x, y, keyCheck);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
},
|
|
|
|
clear() {
|
|
for (var y in KeyHandler.elements.keys) {
|
|
for (var x in KeyHandler.elements.keys[y]) {
|
|
var key = KeyHandler.elements.keys[y][x];
|
|
|
|
key.context.clearRect(0, 0, 100, 100);
|
|
key.key.classList.remove('selected');
|
|
}
|
|
}
|
|
KeyHandler.selected = [];
|
|
Editor.close();
|
|
},
|
|
|
|
render(x: string, y: string, data: Page_Key) {
|
|
if (KeyHandler.elements.keys[String(y)]) {
|
|
if (KeyHandler.elements.keys[String(y)][String(x)]) {
|
|
var context = KeyHandler.elements.keys[String(y)][String(x)].context;
|
|
|
|
context.clearRect(0, 0, renderQuality, renderQuality);
|
|
|
|
if (data.state.type == 'custom') {
|
|
var appearence = data.appearence;
|
|
|
|
render(appearence);
|
|
} else if (data.state.type == 'ghost') {
|
|
var appearence = data.appearence;
|
|
|
|
if (appearence == undefined) appearence = {};
|
|
|
|
appearence.system = { ghost: true };
|
|
|
|
render(appearence);
|
|
} else if (data.state.type == 'pageup') {
|
|
render({
|
|
text: { value: 'Up', color: '#ffffff', size: 18, offsetX: 0, offsetY: 25 },
|
|
background: { color: '#4676b7' },
|
|
image: {
|
|
size: 100,
|
|
rotation: 0,
|
|
offsetX: 0,
|
|
offsetY: -15,
|
|
iconid: 'keyboard_arrow_up',
|
|
iconstyle: 'white'
|
|
},
|
|
system: {
|
|
border: {
|
|
color: '#253e5e',
|
|
thickness: 8
|
|
}
|
|
}
|
|
});
|
|
} else if (data.state.type == 'pagedown') {
|
|
render({
|
|
text: { value: 'Down', color: '#ffffff', size: 18, offsetX: 0, offsetY: -25 },
|
|
background: { color: '#4676b7' },
|
|
image: {
|
|
size: 100,
|
|
rotation: 0,
|
|
offsetX: 0,
|
|
offsetY: 15,
|
|
iconid: 'keyboard_arrow_down',
|
|
iconstyle: 'white'
|
|
},
|
|
system: {
|
|
border: {
|
|
color: '#253e5e',
|
|
thickness: 8
|
|
}
|
|
}
|
|
});
|
|
} else if (data.state.type == 'currentpage') {
|
|
render({
|
|
text: {
|
|
value: `Page\\n\\n${PageHandler.currentIndex + 1}`,
|
|
color: '#ffffff',
|
|
size: 22,
|
|
offsetX: 0,
|
|
offsetY: 0
|
|
},
|
|
background: { color: '#4676b7' },
|
|
system: {
|
|
border: {
|
|
color: '#253e5e',
|
|
thickness: 8
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} else console.error(`Invalid x '${x}'`);
|
|
} else console.error(`Invalid y '${y}'`);
|
|
|
|
function render(appearence: Page_Key_Appearence) {
|
|
if (appearence.background != undefined) {
|
|
context.fillStyle = appearence.background.color;
|
|
context.fillRect(0, 0, renderQuality, renderQuality);
|
|
context.fill();
|
|
}
|
|
|
|
if (appearence.text != undefined) {
|
|
context.fillStyle = appearence.text.color;
|
|
context.font = `800 ${appearence.text.size * fontSizeRatio}px "Montserrat"`;
|
|
|
|
var text = appearence.text.value;
|
|
var lineHeight = appearence.text.size * fontSizeRatio;
|
|
|
|
var centerX = renderQuality / 2 + appearence.text.offsetX / 100 * (renderQuality * 2);
|
|
var centerY = renderQuality / 2 + appearence.text.offsetY / 100 * renderQuality;
|
|
var canvasYCounter = centerY;
|
|
|
|
var words = text.replace(/\\n/g, ' \\n ').split(' ');
|
|
var line = '';
|
|
|
|
var totalLineHeight = 0;
|
|
for (var n = 0; n < words.length; n++) {
|
|
if (words[n].length == 0) continue;
|
|
|
|
var testLine = line + words[n] + ' ';
|
|
var metrics = context.measureText(testLine);
|
|
var testWidth = metrics.width;
|
|
if (words[n] != '\\n')
|
|
if (testWidth > renderQuality && n > 0) {
|
|
line = words[n] + ' ';
|
|
totalLineHeight += lineHeight;
|
|
} else {
|
|
line = testLine;
|
|
}
|
|
else {
|
|
totalLineHeight += lineHeight;
|
|
line = '';
|
|
}
|
|
}
|
|
|
|
line = '';
|
|
canvasYCounter = canvasYCounter - totalLineHeight / 2;
|
|
|
|
var firstSkip = false;
|
|
for (var n = 0; n < words.length; n++) {
|
|
if (words[n].length == 0) continue;
|
|
var testLine = line + words[n] + ' ';
|
|
var metrics = context.measureText(testLine);
|
|
var testWidth = metrics.width;
|
|
if (words[n] != '\\n')
|
|
if (testWidth > renderQuality && n > 0) {
|
|
context.fillText(line, centerX, canvasYCounter);
|
|
line = words[n] + ' ';
|
|
canvasYCounter += lineHeight;
|
|
} else {
|
|
line = testLine;
|
|
}
|
|
else {
|
|
context.fillText(line, centerX, canvasYCounter);
|
|
line = '';
|
|
|
|
canvasYCounter += firstSkip ? lineHeight * 2 : lineHeight;
|
|
if (firstSkip) firstSkip = false;
|
|
}
|
|
}
|
|
context.fillText(line, centerX, canvasYCounter);
|
|
}
|
|
|
|
if (appearence.image != undefined) {
|
|
var imageAddress =
|
|
appearence.image.address != undefined
|
|
? appearence.image.address
|
|
: appearence.image.iconid != undefined
|
|
? `/stc/materialicons/white/${appearence.image.iconid}.png`
|
|
: null;
|
|
|
|
var imageSize =
|
|
appearence.image.size != undefined ? appearence.image.size / 100 * renderQuality : renderQuality;
|
|
if (imageAddress) {
|
|
var centerX = renderQuality / 2 + appearence.image.offsetX / 100 * renderQuality;
|
|
var centerY = renderQuality / 2 + appearence.image.offsetY / 100 * renderQuality;
|
|
|
|
if (KeyHandler.imagecache[imageAddress] != undefined)
|
|
renderImage(KeyHandler.imagecache[imageAddress]);
|
|
else {
|
|
KeyHandler.imagecache[imageAddress] = new Image();
|
|
KeyHandler.imagecache[imageAddress].src = imageAddress;
|
|
KeyHandler.imagecache[imageAddress].onload = () =>
|
|
renderImage(KeyHandler.imagecache[imageAddress]);
|
|
}
|
|
|
|
function renderImage(image) {
|
|
context.save();
|
|
context.translate(centerX, centerY);
|
|
context.rotate(appearence.image.rotation * Math.PI / 180);
|
|
context.drawImage(
|
|
image,
|
|
imageSize / 2 - imageSize,
|
|
imageSize / 2 - imageSize,
|
|
imageSize,
|
|
imageSize
|
|
);
|
|
context.restore();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (appearence.system != undefined) {
|
|
if (appearence.system.border != undefined) {
|
|
var relativeThickness = appearence.system.border.thickness / 100 * renderQuality;
|
|
context.fillStyle = appearence.system.border.color;
|
|
context.fillRect(0, 0, renderQuality, relativeThickness);
|
|
context.rect(0, renderQuality - relativeThickness, renderQuality, relativeThickness);
|
|
context.rect(0, 0, relativeThickness, renderQuality);
|
|
context.rect(renderQuality - relativeThickness, 0, relativeThickness, renderQuality);
|
|
context.fill();
|
|
}
|
|
|
|
if (appearence.system.ghost == true) {
|
|
var size = 50 / 100 * renderQuality;
|
|
context.save();
|
|
context.globalAlpha = 0.7;
|
|
context.translate(renderQuality / 2, renderQuality / 2);
|
|
context.drawImage(KeyHandler.ghostImage, size / 2 - size, size / 2 - size, size, size);
|
|
context.restore();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
select(x: string, y: string, multi: boolean = false) {
|
|
if (PageHandler.currentPage != null) {
|
|
if (PageHandler.currentPage.keys[y] != undefined && PageHandler.currentPage.keys[y][x] != undefined) {
|
|
// var keyConfig = PageHandler.currentPage.keys[y][x];
|
|
|
|
var query = `${x},${y}`;
|
|
if (multi) {
|
|
if (!KeyHandler.selected.includes(query)) KeyHandler.selected.push(query);
|
|
} else
|
|
KeyHandler.selected = [
|
|
query
|
|
];
|
|
|
|
document.querySelectorAll('.key').forEach((key: HTMLDivElement) => {
|
|
var checkX = key.getAttribute('x');
|
|
var checkY = key.getAttribute('y');
|
|
var checkQuery = `${checkX},${checkY}`;
|
|
if (KeyHandler.selected.includes(checkQuery)) key.classList.add('selected');
|
|
else key.classList.remove('selected');
|
|
});
|
|
|
|
if (KeyHandler.selected.length > 1) Editor.close();
|
|
else {
|
|
socket.emit('page', 'getkey', PageHandler.currentPageID, x, y, (key: Page_Key) => {
|
|
Editor.open(x, y, key);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
KeyHandler.init();
|
|
|
|
var altDown = false;
|
|
|
|
window.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
if (e.key == 'alt' || e.altKey == true) altDown = true;
|
|
});
|
|
window.addEventListener('keyup', (e: KeyboardEvent) => {
|
|
if (e.key == 'alt' || e.altKey == false) altDown = false;
|
|
});
|
|
|
|
interface KeyHandler {
|
|
elements: {
|
|
keys: {
|
|
[y: string]: {
|
|
[x: string]: {
|
|
key: HTMLDivElement;
|
|
canvas: HTMLCanvasElement;
|
|
context: CanvasRenderingContext2D;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
selected: string[];
|
|
imagecache: { [iconID: string]: HTMLImageElement };
|
|
ghostImage: any;
|
|
|
|
init: () => void;
|
|
clear: () => void;
|
|
render: (x: string, y: string, data: Page_Key) => void;
|
|
select: (x: string, y: string, multi?: boolean) => void;
|
|
}
|
|
|
|
interface Page_Key {
|
|
id: string;
|
|
state: {
|
|
type: KeyTypes;
|
|
toggle: boolean;
|
|
confirm: boolean;
|
|
};
|
|
actions: Page_Key_ActionTypes;
|
|
appearence: Page_Key_Appearence;
|
|
}
|
|
interface Page_Key_Appearence {
|
|
text?: Page_Key_Text;
|
|
image?: Page_Key_Image;
|
|
background?: Page_Key_Background;
|
|
system?: {
|
|
border?: {
|
|
color: string;
|
|
thickness: number;
|
|
};
|
|
ghost?: boolean;
|
|
};
|
|
}
|
|
|
|
interface Page_Key_Text {
|
|
value: string;
|
|
size: number;
|
|
color: string;
|
|
offsetX: number;
|
|
offsetY: number;
|
|
}
|
|
|
|
interface Page_Key_Image {
|
|
address?: string;
|
|
iconid?: string;
|
|
iconstyle?: 'black' | 'white';
|
|
size: number;
|
|
offsetX: number;
|
|
offsetY: number;
|
|
rotation: number;
|
|
}
|
|
|
|
interface Page_Key_Background {
|
|
color: string;
|
|
}
|
|
|
|
type KeyTypes = 'empty' | 'custom' | 'pageup' | 'pagedown' | 'currentpage' | 'ghost';
|