2020-12-31 18:47:56 +03:00
|
|
|
/* This scripts contains all the code used to handle the canvas resizing */
|
|
|
|
|
|
|
|
// Resize canvas pop up window
|
2020-07-23 00:29:27 +03:00
|
|
|
let resizeCanvasContainer = document.getElementById("resize-canvas");
|
2020-12-31 18:47:56 +03:00
|
|
|
// Start pivot
|
2020-09-21 11:39:37 +03:00
|
|
|
let rcPivot = "middle";
|
2020-12-31 18:47:56 +03:00
|
|
|
// Selected pivot button
|
2020-09-15 12:56:05 +03:00
|
|
|
let currentPivotObject;
|
2020-12-31 18:47:56 +03:00
|
|
|
// Border offsets
|
|
|
|
let rcBorders = {left: 0, right: 0, top: 0, bottom: 0};
|
2020-07-23 00:29:27 +03:00
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
/** Opens the canvas resize window
|
|
|
|
*
|
|
|
|
*/
|
2020-07-23 00:29:27 +03:00
|
|
|
function openResizeCanvasWindow() {
|
2020-12-31 18:47:56 +03:00
|
|
|
// Initializes the inputs
|
2020-09-22 12:34:36 +03:00
|
|
|
initResizeCanvasInputs();
|
2020-07-23 00:29:27 +03:00
|
|
|
showDialogue('resize-canvas');
|
2020-09-13 12:21:23 +03:00
|
|
|
}
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
/** Initializes the canvas resizing input
|
|
|
|
*
|
|
|
|
*/
|
2020-09-13 12:58:46 +03:00
|
|
|
function initResizeCanvasInputs() {
|
2020-12-31 18:47:56 +03:00
|
|
|
// Getting the pivot buttons
|
2020-09-13 12:21:23 +03:00
|
|
|
let buttons = document.getElementsByClassName("pivot-button");
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
// Adding the event handlers for them
|
2020-09-13 12:21:23 +03:00
|
|
|
for (let i=0; i<buttons.length; i++) {
|
|
|
|
buttons[i].addEventListener("click", changePivot);
|
2020-09-15 12:56:05 +03:00
|
|
|
if (buttons[i].getAttribute("value").includes("middle")) {
|
|
|
|
currentPivotObject = buttons[i];
|
|
|
|
}
|
2020-09-13 12:21:23 +03:00
|
|
|
}
|
2020-09-13 12:58:46 +03:00
|
|
|
|
2020-09-15 12:56:05 +03:00
|
|
|
document.getElementById("rc-width").value = layers[0].canvasSize[0];
|
|
|
|
document.getElementById("rc-height").value = layers[0].canvasSize[1];
|
|
|
|
|
2020-09-21 11:39:37 +03:00
|
|
|
document.getElementById("rc-border-left").addEventListener("change", rcChangedBorder);
|
|
|
|
document.getElementById("rc-border-right").addEventListener("change", rcChangedBorder);
|
|
|
|
document.getElementById("rc-border-top").addEventListener("change", rcChangedBorder);
|
|
|
|
document.getElementById("rc-border-bottom").addEventListener("change", rcChangedBorder);
|
2020-09-15 12:56:05 +03:00
|
|
|
|
2020-09-21 11:39:37 +03:00
|
|
|
document.getElementById("rc-width").addEventListener("change", rcChangedSize);
|
|
|
|
document.getElementById("rc-height").addEventListener("change", rcChangedSize);
|
2020-09-15 12:56:05 +03:00
|
|
|
|
2020-09-13 12:58:46 +03:00
|
|
|
document.getElementById("resize-canvas-confirm").addEventListener("click", resizeCanvas);
|
2020-09-15 12:56:05 +03:00
|
|
|
console.log("Pivot selezionato: " + currentPivotObject);
|
|
|
|
}
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
/** Fired when a border offset is changed: it updates the width and height
|
|
|
|
*
|
|
|
|
* @param {*} event
|
|
|
|
*/
|
2020-09-21 11:39:37 +03:00
|
|
|
function rcChangedBorder(event) {
|
2020-09-15 12:56:05 +03:00
|
|
|
rcUpdateBorders();
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
document.getElementById("rc-width").value = parseInt(layers[0].canvasSize[0]) + rcBorders.left + rcBorders.right;
|
|
|
|
document.getElementById("rc-height").value = parseInt(layers[0].canvasSize[1]) + rcBorders.top + rcBorders.bottom;
|
2020-09-15 12:56:05 +03:00
|
|
|
}
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
/** Fired when width or height are changed: updates the border offsets
|
|
|
|
*
|
|
|
|
* @param {*} event
|
|
|
|
*/
|
2020-09-21 11:39:37 +03:00
|
|
|
function rcChangedSize(event) {
|
2020-09-15 13:12:35 +03:00
|
|
|
let widthOffset = Math.abs(document.getElementById("rc-width").value) - layers[0].canvasSize[0];
|
|
|
|
let heightOffset = Math.abs(document.getElementById("rc-height").value) - layers[0].canvasSize[1];
|
2020-09-15 12:56:05 +03:00
|
|
|
|
|
|
|
let left = Math.round(widthOffset / 2);
|
|
|
|
let right = widthOffset - left;
|
|
|
|
let top = Math.round(heightOffset / 2);
|
|
|
|
let bottom = heightOffset - top;
|
|
|
|
|
|
|
|
document.getElementById("rc-border-left").value = left;
|
|
|
|
document.getElementById("rc-border-right").value = right;
|
|
|
|
document.getElementById("rc-border-top").value = top;
|
|
|
|
document.getElementById("rc-border-bottom").value = bottom;
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
rcBorders.left = left;
|
|
|
|
rcBorders.right = right;
|
|
|
|
rcBorders.top = top;
|
|
|
|
rcBorders.bottom = bottom;
|
2020-09-13 12:58:46 +03:00
|
|
|
}
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
/** Resizes the canvas
|
|
|
|
*
|
|
|
|
* @param {*} event The event that triggered the canvas resizing
|
|
|
|
* @param {*} size The new size of the picture
|
|
|
|
* @param {*} customData Used when ctrl+z ing
|
|
|
|
* @param {*} saveHistory Should I save the history? You shouldn't if you're undoing
|
|
|
|
*/
|
2020-09-29 22:22:02 +03:00
|
|
|
function resizeCanvas(event, size, customData, saveHistory = true) {
|
2020-09-13 13:11:08 +03:00
|
|
|
let imageDatas = [];
|
2020-09-15 12:56:05 +03:00
|
|
|
let leftOffset = 0;
|
|
|
|
let topOffset = 0;
|
|
|
|
let copiedDataIndex = 0;
|
|
|
|
|
2020-09-29 20:10:50 +03:00
|
|
|
// If I'm undoing and I'm not trimming, I manually put the values in the window
|
|
|
|
if (size != null && customData == null) {
|
2020-09-15 14:06:31 +03:00
|
|
|
document.getElementById("rc-width").value = size.x;
|
|
|
|
document.getElementById("rc-height").value = size.y;
|
|
|
|
|
2020-09-21 11:39:37 +03:00
|
|
|
rcChangedSize();
|
2020-09-15 14:06:31 +03:00
|
|
|
}
|
|
|
|
|
2020-09-13 13:11:08 +03:00
|
|
|
rcUpdateBorders();
|
2020-09-29 20:10:50 +03:00
|
|
|
|
2020-09-13 13:11:08 +03:00
|
|
|
// Save all imageDatas
|
|
|
|
for (let i=0; i<layers.length; i++) {
|
|
|
|
if (layers[i].menuEntry != null) {
|
2020-09-27 12:25:09 +03:00
|
|
|
imageDatas.push(layers[i].context.getImageData(0, 0, layers[0].canvasSize[0], layers[0].canvasSize[1]));
|
2020-09-13 13:11:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 14:06:31 +03:00
|
|
|
// Saving the history only if I'm not already undoing or redoing
|
2020-09-29 22:22:02 +03:00
|
|
|
if (saveHistory) {
|
2020-09-15 14:06:31 +03:00
|
|
|
// Saving history
|
|
|
|
new HistoryStateResizeCanvas(
|
2020-12-31 18:47:56 +03:00
|
|
|
{x: parseInt(layers[0].canvasSize[0]) + rcBorders.left + rcBorders.right,
|
|
|
|
y: parseInt(layers[0].canvasSize[1]) + rcBorders.top + rcBorders.bottom},
|
2020-09-15 14:06:31 +03:00
|
|
|
|
|
|
|
{x: layers[0].canvasSize[0],
|
|
|
|
y: layers[0].canvasSize[1]},
|
2020-09-29 22:22:02 +03:00
|
|
|
imageDatas.slice(), customData != null && saveHistory
|
2020-09-15 14:06:31 +03:00
|
|
|
);
|
2020-09-29 22:22:02 +03:00
|
|
|
|
|
|
|
console.log("salvata");
|
2020-09-15 14:06:31 +03:00
|
|
|
}
|
|
|
|
|
2020-09-13 13:11:08 +03:00
|
|
|
// Resize the canvases
|
|
|
|
for (let i=0; i<layers.length; i++) {
|
2020-12-31 18:47:56 +03:00
|
|
|
layers[i].canvasSize[0] = parseInt(layers[i].canvasSize[0]) + rcBorders.left + rcBorders.right;
|
|
|
|
layers[i].canvasSize[1] = parseInt(layers[i].canvasSize[1]) + rcBorders.top + rcBorders.bottom;
|
2020-09-13 13:11:08 +03:00
|
|
|
|
|
|
|
layers[i].canvas.width = layers[i].canvasSize[0];
|
|
|
|
layers[i].canvas.height = layers[i].canvasSize[1];
|
2020-09-15 12:56:05 +03:00
|
|
|
|
|
|
|
layers[i].resize();
|
|
|
|
layers[i].context.fillStyle = currentGlobalColor;
|
2020-09-13 13:11:08 +03:00
|
|
|
}
|
2020-09-15 12:56:05 +03:00
|
|
|
|
|
|
|
// Regenerate the checkerboard
|
|
|
|
fillCheckerboard();
|
2020-09-26 12:51:18 +03:00
|
|
|
fillPixelGrid();
|
2020-09-13 13:11:08 +03:00
|
|
|
// Put the imageDatas in the right position
|
2020-09-21 11:39:37 +03:00
|
|
|
switch (rcPivot)
|
2020-09-15 12:56:05 +03:00
|
|
|
{
|
|
|
|
case 'topleft':
|
|
|
|
leftOffset = 0;
|
|
|
|
topOffset = 0;
|
|
|
|
break;
|
|
|
|
case 'top':
|
2020-12-31 18:47:56 +03:00
|
|
|
leftOffset = (rcBorders.left + rcBorders.right) / 2;
|
2020-09-15 12:56:05 +03:00
|
|
|
topOffset = 0;
|
|
|
|
break;
|
|
|
|
case 'topright':
|
2020-12-31 18:47:56 +03:00
|
|
|
leftOffset = rcBorders.left + rcBorders.right;
|
2020-09-15 12:56:05 +03:00
|
|
|
topOffset = 0;
|
|
|
|
break;
|
|
|
|
case 'left':
|
|
|
|
leftOffset = 0;
|
2020-12-31 18:47:56 +03:00
|
|
|
topOffset = (rcBorders.top + rcBorders.bottom) / 2;
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
case 'middle':
|
2020-12-31 18:47:56 +03:00
|
|
|
leftOffset = (rcBorders.left + rcBorders.right) / 2;
|
|
|
|
topOffset = (rcBorders.top + rcBorders.bottom) / 2;
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
case 'right':
|
2020-12-31 18:47:56 +03:00
|
|
|
leftOffset = rcBorders.left + rcBorders.right;
|
|
|
|
topOffset = (rcBorders.top + rcBorders.bottom) / 2;
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
case 'bottomleft':
|
|
|
|
leftOffset = 0;
|
2020-12-31 18:47:56 +03:00
|
|
|
topOffset = rcBorders.top + rcBorders.bottom;
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
case 'bottom':
|
2020-12-31 18:47:56 +03:00
|
|
|
leftOffset = (rcBorders.left + rcBorders.right) / 2;
|
|
|
|
topOffset = rcBorders.top + rcBorders.bottom;
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
case 'bottomright':
|
2020-12-31 18:47:56 +03:00
|
|
|
leftOffset = rcBorders.left + rcBorders.right;
|
|
|
|
topOffset = rcBorders.top + rcBorders.bottom;
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
default:
|
2020-09-15 14:06:31 +03:00
|
|
|
console.log('Pivot does not exist, please report an issue at https://github.com/lospec/pixel-editor');
|
2020-09-15 12:56:05 +03:00
|
|
|
break;
|
|
|
|
}
|
2020-09-27 14:08:48 +03:00
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
// Putting all the data for each layer with the right offsets (decided by the pivot)
|
2020-09-15 12:56:05 +03:00
|
|
|
for (let i=0; i<layers.length; i++) {
|
|
|
|
if (layers[i].menuEntry != null) {
|
2020-09-27 14:08:48 +03:00
|
|
|
if (customData == undefined) {
|
|
|
|
layers[i].context.putImageData(imageDatas[copiedDataIndex], leftOffset, topOffset);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.log("sgancio " + layers[i].canvasSize + ", [" +
|
|
|
|
customData[copiedDataIndex].width + "," + customData[copiedDataIndex].height
|
|
|
|
+ "]");
|
|
|
|
layers[i].context.putImageData(customData[copiedDataIndex], 0, 0);
|
|
|
|
}
|
2020-09-15 14:06:31 +03:00
|
|
|
layers[i].updateLayerPreview();
|
2020-09-15 12:56:05 +03:00
|
|
|
copiedDataIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
closeDialogue();
|
2020-09-26 14:08:43 +03:00
|
|
|
}
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
/** Trims the canvas so tat the sprite is perfectly contained in it
|
|
|
|
*
|
|
|
|
* @param {*} event
|
|
|
|
* @param {*} saveHistory Should I save the history? You shouldn't if you're undoing
|
|
|
|
*/
|
2020-09-29 20:10:50 +03:00
|
|
|
function trimCanvas(event, saveHistory) {
|
2020-09-27 12:25:09 +03:00
|
|
|
let minY = Infinity;
|
|
|
|
let minX = Infinity;
|
|
|
|
let maxX = -Infinity;
|
|
|
|
let maxY = -Infinity;
|
2020-09-27 14:08:48 +03:00
|
|
|
let tmp;
|
|
|
|
let imageDatas = [];
|
2020-09-29 20:10:50 +03:00
|
|
|
let historySave = saveHistory == null;
|
2020-09-29 22:22:02 +03:00
|
|
|
let prevPivot = rcPivot;
|
2020-09-26 14:08:43 +03:00
|
|
|
|
2020-09-27 14:08:48 +03:00
|
|
|
rcPivot = "topleft";
|
|
|
|
console.log("debug");
|
2020-09-26 14:08:43 +03:00
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
// Computing the min and max coordinates in which there's a non empty pixel
|
2020-09-27 14:08:48 +03:00
|
|
|
for (let i=1; i<layers.length - nAppLayers; i++) {
|
2020-09-26 14:08:43 +03:00
|
|
|
let imageData = layers[i].context.getImageData(0, 0, layers[0].canvasSize[0], layers[0].canvasSize[1]);
|
|
|
|
let pixelPosition;
|
|
|
|
|
2020-09-27 14:08:48 +03:00
|
|
|
for (let i=imageData.data.length - 1; i>= 0; i-=4) {
|
2020-09-27 12:25:09 +03:00
|
|
|
if (!isPixelEmpty(
|
2020-09-27 14:08:48 +03:00
|
|
|
[imageData.data[i - 3], imageData.data[i - 2],
|
|
|
|
-imageData.data[i - 1], imageData.data[i]])) {
|
2020-09-26 14:08:43 +03:00
|
|
|
pixelPosition = getPixelPosition(i);
|
|
|
|
|
2020-09-27 14:08:48 +03:00
|
|
|
// max x
|
2020-09-27 12:25:09 +03:00
|
|
|
if (pixelPosition[0] > maxX) {
|
2020-09-26 14:08:43 +03:00
|
|
|
maxX = pixelPosition[0];
|
|
|
|
}
|
2020-09-27 14:08:48 +03:00
|
|
|
// min x
|
|
|
|
if (pixelPosition[0] < minX) {
|
2020-09-26 14:08:43 +03:00
|
|
|
minX = pixelPosition[0];
|
|
|
|
}
|
2020-09-27 14:08:48 +03:00
|
|
|
// max y
|
2020-09-27 12:25:09 +03:00
|
|
|
if (pixelPosition[1] > maxY) {
|
2020-09-26 14:08:43 +03:00
|
|
|
maxY = pixelPosition[1];
|
|
|
|
}
|
2020-09-27 14:08:48 +03:00
|
|
|
// min y
|
|
|
|
if (pixelPosition[1] < minY) {
|
2020-09-26 14:08:43 +03:00
|
|
|
minY = pixelPosition[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-27 14:08:48 +03:00
|
|
|
tmp = minY;
|
|
|
|
minY = maxY;
|
|
|
|
maxY = tmp;
|
|
|
|
|
|
|
|
minY = layers[0].canvasSize[1] - minY;
|
|
|
|
maxY = layers[0].canvasSize[1] - maxY;
|
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
// Setting the borders coherently with the values I've just computed
|
|
|
|
rcBorders.right = (maxX - layers[0].canvasSize[0]) + 1;
|
|
|
|
rcBorders.left = -minX;
|
|
|
|
rcBorders.top = maxY - layers[0].canvasSize[1] + 1;
|
|
|
|
rcBorders.bottom = -minY;
|
2020-09-27 14:08:48 +03:00
|
|
|
|
|
|
|
// Saving the data
|
|
|
|
for (let i=0; i<layers.length; i++) {
|
|
|
|
if (layers[i].menuEntry != null) {
|
|
|
|
imageDatas.push(layers[i].context.getImageData(minX - 1, layers[i].canvasSize[1] - maxY, maxX-minX + 1, maxY-minY + 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(imageDatas);
|
|
|
|
//console.log("sx: " + borders.left + "dx: " + borders.right + "top: " + borders.top + "btm: " + borders.bottom);
|
2020-09-26 14:08:43 +03:00
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
document.getElementById("rc-border-left").value = rcBorders.left;
|
|
|
|
document.getElementById("rc-border-right").value = rcBorders.right;
|
|
|
|
document.getElementById("rc-border-top").value = rcBorders.top;
|
|
|
|
document.getElementById("rc-border-bottom").value = rcBorders.bottom;
|
2020-09-27 12:25:09 +03:00
|
|
|
|
2020-12-31 18:47:56 +03:00
|
|
|
// Resizing the canvas with the decided border offsets
|
2020-09-29 20:10:50 +03:00
|
|
|
resizeCanvas(null, null, imageDatas.slice(), historySave);
|
2020-09-29 22:22:02 +03:00
|
|
|
// Resetting the previous pivot
|
|
|
|
rcPivot = prevPivot;
|
2020-09-13 12:58:46 +03:00
|
|
|
}
|
|
|
|
|
2020-09-13 13:11:08 +03:00
|
|
|
function rcUpdateBorders() {
|
2020-09-13 12:58:46 +03:00
|
|
|
// Getting input
|
2020-12-31 18:47:56 +03:00
|
|
|
rcBorders.left = document.getElementById("rc-border-left").value;
|
|
|
|
rcBorders.right = document.getElementById("rc-border-right").value;
|
|
|
|
rcBorders.top = document.getElementById("rc-border-top").value;
|
|
|
|
rcBorders.bottom = document.getElementById("rc-border-bottom").value;
|
2020-09-13 12:58:46 +03:00
|
|
|
|
|
|
|
// Validating input
|
2020-12-31 18:47:56 +03:00
|
|
|
rcBorders.left == "" ? rcBorders.left = 0 : rcBorders.left = Math.round(parseInt(rcBorders.left));
|
|
|
|
rcBorders.right == "" ? rcBorders.right = 0 : rcBorders.right = Math.round(parseInt(rcBorders.right));
|
|
|
|
rcBorders.top == "" ? rcBorders.top = 0 : rcBorders.top = Math.round(parseInt(rcBorders.top));
|
|
|
|
rcBorders.bottom == "" ? rcBorders.bottom = 0 : rcBorders.bottom = Math.round(parseInt(rcBorders.bottom));
|
2020-09-13 12:21:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function changePivot(event) {
|
2020-09-21 11:39:37 +03:00
|
|
|
rcPivot = event.target.getAttribute("value");
|
2020-09-15 12:56:05 +03:00
|
|
|
|
|
|
|
// Setting the selected class
|
|
|
|
currentPivotObject.classList.remove("rc-selected-pivot");
|
|
|
|
currentPivotObject = event.target;
|
|
|
|
currentPivotObject.classList.add("rc-selected-pivot");
|
2020-07-23 00:29:27 +03:00
|
|
|
}
|
|
|
|
|