mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Finished commenting the editor
Also cleaned a few things, removed some unused variables
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
//draw a line between two points on canvas
|
//draws a line between two points on canvas
|
||||||
function line(x0,y0,x1,y1, brushSize) {
|
function line(x0,y0,x1,y1, brushSize) {
|
||||||
var dx = Math.abs(x1-x0);
|
var dx = Math.abs(x1-x0);
|
||||||
var dy = Math.abs(y1-y0);
|
var dy = Math.abs(y1-y0);
|
||||||
|
@ -3,7 +3,7 @@ let modes = {
|
|||||||
description: 'Basic mode is perfect if you want to create simple sprites or try out palettes.'
|
description: 'Basic mode is perfect if you want to create simple sprites or try out palettes.'
|
||||||
},
|
},
|
||||||
'Advanced' : {
|
'Advanced' : {
|
||||||
description: 'Choose advanced mode to gain access to features such as layers.'
|
description: 'Choose advanced mode to gain access to more advanced features such as layers.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
var subMenu = menuItem.children[1];
|
var subMenu = menuItem.children[1];
|
||||||
var subMenuItems = subMenu.children;
|
var subMenuItems = subMenu.children;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//when you click an item within a menu button
|
//when you click an item within a menu button
|
||||||
for (var j = 0; j < subMenuItems.length; j++) {
|
for (var j = 0; j < subMenuItems.length; j++) {
|
||||||
|
|
||||||
|
@ -7,11 +7,6 @@ function fill(cursorLocation) {
|
|||||||
tempImage.data[pixelPos + 1] = fillColor.g;
|
tempImage.data[pixelPos + 1] = fillColor.g;
|
||||||
tempImage.data[pixelPos + 2] = fillColor.b;
|
tempImage.data[pixelPos + 2] = fillColor.b;
|
||||||
tempImage.data[pixelPos + 3] = 255;
|
tempImage.data[pixelPos + 3] = 255;
|
||||||
/*
|
|
||||||
tempImage.data[pixelPos] = fillColor.r;
|
|
||||||
tempImage.data[pixelPos + 1] = fillColor.g;
|
|
||||||
tempImage.data[pixelPos + 2] = fillColor.b;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//change x y to color value passed from the function and use that as the original color
|
//change x y to color value passed from the function and use that as the original color
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//get cursor position relative to canvas
|
//gets cursor position relative to canvas
|
||||||
function getCursorPosition(e) {
|
function getCursorPosition(e) {
|
||||||
var x;
|
var x;
|
||||||
var y;
|
var y;
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
/** How the history works
|
||||||
|
* - undoStates stores the states that can be undone
|
||||||
|
* - redoStates stores the states that can be redone
|
||||||
|
* - undo() undoes an action and adds it to the redoStates
|
||||||
|
* - redo() redoes an action and adds it to the undoStates
|
||||||
|
* - Each HistoryState must implement an undo() and redo() function
|
||||||
|
* Those functions actually implement the undo and redo mechanism for that action,
|
||||||
|
* so you'll need to save the data you need as attributes in the constructor. For example,
|
||||||
|
* for the HistoryStateAddColour, the added colour is saved so that it can be removed in
|
||||||
|
* undo() or added back in redo().
|
||||||
|
* - Each HistoryState must call saveHistoryState(this) so that it gets added to the stack
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
var undoStates = [];
|
var undoStates = [];
|
||||||
var redoStates = [];
|
var redoStates = [];
|
||||||
|
|
||||||
@ -473,8 +487,6 @@ function saveHistoryState (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function undo () {
|
function undo () {
|
||||||
//console.log('%cundo', undoLogStyle);
|
|
||||||
|
|
||||||
//if there are any states saved to undo
|
//if there are any states saved to undo
|
||||||
if (undoStates.length > 0) {
|
if (undoStates.length > 0) {
|
||||||
document.getElementById('redo-button').classList.remove('disabled');
|
document.getElementById('redo-button').classList.remove('disabled');
|
||||||
@ -496,8 +508,6 @@ function undo () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function redo () {
|
function redo () {
|
||||||
//console.log('%credo', undoLogStyle);
|
|
||||||
|
|
||||||
if (redoStates.length > 0) {
|
if (redoStates.length > 0) {
|
||||||
|
|
||||||
//enable undo button
|
//enable undo button
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
var spacePressed = false;
|
var spacePressed = false;
|
||||||
|
|
||||||
|
/** Just listens to hotkeys and calls the linked functions
|
||||||
|
*
|
||||||
|
* @param {*} e
|
||||||
|
*/
|
||||||
function KeyPress(e) {
|
function KeyPress(e) {
|
||||||
var keyboardEvent = window.event? event : e;
|
var keyboardEvent = window.event? event : e;
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
// NEXTPULL: to remove when the new palette system is added
|
||||||
|
|
||||||
//format a color button
|
|
||||||
|
//formats a color button
|
||||||
function initColor (colorElement) {
|
function initColor (colorElement) {
|
||||||
//console.log('initColor()');
|
//console.log('initColor()');
|
||||||
//console.log(document.getElementById('jscolor-hex-input'))
|
//console.log(document.getElementById('jscolor-hex-input'))
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// NEXTPULL: to remove when the new palette system is added
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jscolor - JavaScript Color Picker
|
* jscolor - JavaScript Color Picker
|
||||||
*
|
*
|
||||||
|
55
js/_layer.js
55
js/_layer.js
@ -1,31 +1,27 @@
|
|||||||
/** TODO LIST FOR LAYERS
|
// HTML element that contains the layer entries
|
||||||
|
|
||||||
GENERAL REQUIREMENTS:
|
|
||||||
- Saving the state of an artwork to a .lospec file so that people can work on it later keeping
|
|
||||||
the layers they created? That'd be cool, even for the app users, that could just double click on a lospec
|
|
||||||
file for it to be opened right in the pixel editor
|
|
||||||
|
|
||||||
OPTIONAL:
|
|
||||||
|
|
||||||
1 - Fix issues
|
|
||||||
*/
|
|
||||||
|
|
||||||
let layerList;
|
let layerList;
|
||||||
|
// A single layer entry (used as a prototype to create the new ones)
|
||||||
let layerListEntry;
|
let layerListEntry;
|
||||||
|
// NEXTPULL: remove the drag n drop system and use Sortable.js instead
|
||||||
let layerDragSource = null;
|
let layerDragSource = null;
|
||||||
|
|
||||||
|
// Number of layers at the beginning
|
||||||
let layerCount = 1;
|
let layerCount = 1;
|
||||||
|
// Current max z index (so that I know which z-index to assign to new layers)
|
||||||
let maxZIndex = 3;
|
let maxZIndex = 3;
|
||||||
|
|
||||||
|
// When a layer is deleted, its id is added to this array and can be reused
|
||||||
let unusedIDs = [];
|
let unusedIDs = [];
|
||||||
|
// Id for the next added layer
|
||||||
let currentID = layerCount;
|
let currentID = layerCount;
|
||||||
let idToDelete;
|
// Layer menu
|
||||||
let layerOptions = document.getElementById("layer-properties-menu");
|
let layerOptions = document.getElementById("layer-properties-menu");
|
||||||
|
// Is the user currently renaming a layer?
|
||||||
let isRenamingLayer = false;
|
let isRenamingLayer = false;
|
||||||
|
// I need to save this, trust me
|
||||||
let oldLayerName = null;
|
let oldLayerName = null;
|
||||||
|
|
||||||
|
// Binding the add layer button to the function
|
||||||
on('click',"add-layer-button", addLayer, false);
|
on('click',"add-layer-button", addLayer, false);
|
||||||
|
|
||||||
/** Handler class for a single canvas (a single layer)
|
/** Handler class for a single canvas (a single layer)
|
||||||
@ -54,6 +50,7 @@ class Layer {
|
|||||||
|
|
||||||
this.id = "layer" + id;
|
this.id = "layer" + id;
|
||||||
|
|
||||||
|
// Binding the events
|
||||||
if (menuEntry != null) {
|
if (menuEntry != null) {
|
||||||
this.name = menuEntry.getElementsByTagName("p")[0].innerHTML;
|
this.name = menuEntry.getElementsByTagName("p")[0].innerHTML;
|
||||||
menuEntry.id = "layer" + id;
|
menuEntry.id = "layer" + id;
|
||||||
@ -78,20 +75,13 @@ class Layer {
|
|||||||
|
|
||||||
// Initializes the canvas
|
// Initializes the canvas
|
||||||
initialize() {
|
initialize() {
|
||||||
/*
|
|
||||||
var maxHorizontalZoom = Math.floor(window.innerWidth/this.canvasSize[0]*0.75);
|
|
||||||
var maxVerticalZoom = Math.floor(window.innerHeight/this.canvasSize[1]*0.75);
|
|
||||||
|
|
||||||
zoom = Math.min(maxHorizontalZoom,maxVerticalZoom);
|
|
||||||
if (zoom < 1) zoom = 1;
|
|
||||||
*/
|
|
||||||
//resize canvas
|
//resize canvas
|
||||||
this.canvas.width = this.canvasSize[0];
|
this.canvas.width = this.canvasSize[0];
|
||||||
this.canvas.height = this.canvasSize[1];
|
this.canvas.height = this.canvasSize[1];
|
||||||
this.canvas.style.width = (this.canvas.width*zoom)+'px';
|
this.canvas.style.width = (this.canvas.width*zoom)+'px';
|
||||||
this.canvas.style.height = (this.canvas.height*zoom)+'px';
|
this.canvas.style.height = (this.canvas.height*zoom)+'px';
|
||||||
|
|
||||||
//unhide canvas
|
//show canvas
|
||||||
this.canvas.style.display = 'block';
|
this.canvas.style.display = 'block';
|
||||||
|
|
||||||
//center canvas in window
|
//center canvas in window
|
||||||
@ -103,7 +93,7 @@ class Layer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hover() {
|
hover() {
|
||||||
// Hide all the layers but the current one
|
// Hides all the layers but the current one
|
||||||
for (let i=1; i<layers.length - nAppLayers; i++) {
|
for (let i=1; i<layers.length - nAppLayers; i++) {
|
||||||
if (layers[i] !== this) {
|
if (layers[i] !== this) {
|
||||||
layers[i].canvas.style.opacity = 0.3;
|
layers[i].canvas.style.opacity = 0.3;
|
||||||
@ -112,7 +102,7 @@ class Layer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unhover() {
|
unhover() {
|
||||||
// Show all the layers again
|
// Shows all the layers again
|
||||||
for (let i=1; i<layers.length - nAppLayers; i++) {
|
for (let i=1; i<layers.length - nAppLayers; i++) {
|
||||||
if (layers[i] !== this) {
|
if (layers[i] !== this) {
|
||||||
layers[i].canvas.style.opacity = 1;
|
layers[i].canvas.style.opacity = 1;
|
||||||
@ -127,6 +117,7 @@ class Layer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEXTPULL: remove this
|
||||||
layerDragStart(element) {
|
layerDragStart(element) {
|
||||||
layerDragSource = this;
|
layerDragSource = this;
|
||||||
element.dataTransfer.effectAllowed = 'move';
|
element.dataTransfer.effectAllowed = 'move';
|
||||||
@ -135,6 +126,7 @@ class Layer {
|
|||||||
this.classList.add('dragElem');
|
this.classList.add('dragElem');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEXTPULL: remove this
|
||||||
layerDragOver(element) {
|
layerDragOver(element) {
|
||||||
if (element.preventDefault) {
|
if (element.preventDefault) {
|
||||||
element.preventDefault(); // Necessary. Allows us to drop.
|
element.preventDefault(); // Necessary. Allows us to drop.
|
||||||
@ -146,10 +138,12 @@ class Layer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEXTPULL: remove this
|
||||||
layerDragLeave(element) {
|
layerDragLeave(element) {
|
||||||
this.classList.remove('layerdragover');
|
this.classList.remove('layerdragover');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEXTPULL: remove this
|
||||||
layerDragDrop(element) {
|
layerDragDrop(element) {
|
||||||
if (element.stopPropagation) {
|
if (element.stopPropagation) {
|
||||||
element.stopPropagation(); // Stops some browsers from redirecting.
|
element.stopPropagation(); // Stops some browsers from redirecting.
|
||||||
@ -169,6 +163,7 @@ class Layer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEXTPULL: remove this
|
||||||
layerDragEnd(element) {
|
layerDragEnd(element) {
|
||||||
this.classList.remove('layerdragover');
|
this.classList.remove('layerdragover');
|
||||||
}
|
}
|
||||||
@ -217,20 +212,20 @@ class Layer {
|
|||||||
|
|
||||||
openOptionsMenu(event) {
|
openOptionsMenu(event) {
|
||||||
if (event.which == 3) {
|
if (event.which == 3) {
|
||||||
|
let selectedId;
|
||||||
let target = event.target;
|
let target = event.target;
|
||||||
let offsets = getElementAbsolutePosition(this);
|
|
||||||
|
|
||||||
while (target != null && target.classList != null && !target.classList.contains("layers-menu-entry")) {
|
while (target != null && target.classList != null && !target.classList.contains("layers-menu-entry")) {
|
||||||
target = target.parentElement;
|
target = target.parentElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
idToDelete = target.id;
|
selectedId = target.id;
|
||||||
|
|
||||||
layerOptions.style.visibility = "visible";
|
layerOptions.style.visibility = "visible";
|
||||||
layerOptions.style.top = "0";
|
layerOptions.style.top = "0";
|
||||||
layerOptions.style.marginTop = "" + (event.clientY - 25) + "px";
|
layerOptions.style.marginTop = "" + (event.clientY - 25) + "px";
|
||||||
|
|
||||||
getLayerByID(idToDelete).selectLayer();
|
getLayerByID(selectedId).selectLayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,10 +260,6 @@ class Layer {
|
|||||||
layer.menuEntry.classList.add("selected-layer");
|
layer.menuEntry.classList.add("selected-layer");
|
||||||
currentLayer = layer;
|
currentLayer = layer;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
canvas = currentLayer.canvas;
|
|
||||||
context = currentLayer.context;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLock() {
|
toggleLock() {
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
|
/** Loads a file (.png or .lpe)
|
||||||
|
*
|
||||||
|
*/
|
||||||
document.getElementById('open-image-browse-holder').addEventListener('change', function () {
|
document.getElementById('open-image-browse-holder').addEventListener('change', function () {
|
||||||
let fileName = document.getElementById("open-image-browse-holder").value;
|
let fileName = document.getElementById("open-image-browse-holder").value;
|
||||||
|
// Getting the extension
|
||||||
let extension = fileName.substring(fileName.lastIndexOf('.')+1, fileName.length) || fileName;
|
let extension = fileName.substring(fileName.lastIndexOf('.')+1, fileName.length) || fileName;
|
||||||
|
|
||||||
|
// I didn't write this check and I have no idea what it does
|
||||||
if (this.files && this.files[0]) {
|
if (this.files && this.files[0]) {
|
||||||
|
// Btw, checking if the extension is supported
|
||||||
if (extension == 'png' || extension == 'gif' || extension == 'lpe') {
|
if (extension == 'png' || extension == 'gif' || extension == 'lpe') {
|
||||||
|
// If it's a Lospec Pixel Editor tm file, I load the project
|
||||||
if (extension == 'lpe') {
|
if (extension == 'lpe') {
|
||||||
let file = this.files[0];
|
let file = this.files[0];
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
|
|
||||||
|
// Getting all the data
|
||||||
reader.readAsText(file, "UTF-8");
|
reader.readAsText(file, "UTF-8");
|
||||||
|
// Converting the data to a json object and creating a new pixel (see _newPixel.js for more)
|
||||||
reader.onload = function (e) {
|
reader.onload = function (e) {
|
||||||
let dictionary = JSON.parse(e.target.result);
|
let dictionary = JSON.parse(e.target.result);
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//this is called when a user picks a file after selecting "load palette" from the new pixel dialogue
|
//this is called when a user picks a file after selecting "load palette" from the new pixel dialogue
|
||||||
|
|
||||||
|
// TODO: load palette from .lpe file
|
||||||
document.getElementById('load-palette-browse-holder').addEventListener('change', function () {
|
document.getElementById('load-palette-browse-holder').addEventListener('change', function () {
|
||||||
if (this.files && this.files[0]) {
|
if (this.files && this.files[0]) {
|
||||||
|
|
||||||
//make sure file is allowed filetype
|
//make sure file is allowed filetype
|
||||||
var fileContentType = this.files[0].type;
|
var fileContentType = this.files[0].type;
|
||||||
if (fileContentType == 'image/png' || fileContentType == 'image/gif') {
|
if (fileContentType == 'image/png' || fileContentType == 'image/gif') {
|
||||||
|
24
js/_move.js
24
js/_move.js
@ -6,9 +6,15 @@ var selectionCanceled = true;
|
|||||||
var firstTimeMove = true;
|
var firstTimeMove = true;
|
||||||
|
|
||||||
// TODO: move with arrows
|
// TODO: move with arrows
|
||||||
|
/** Updates the move preview so that is placed in the right position
|
||||||
|
*
|
||||||
|
* @param {*} mousePosition The position of the cursor
|
||||||
|
*/
|
||||||
function updateMovePreview(mousePosition) {
|
function updateMovePreview(mousePosition) {
|
||||||
|
// I haven't canceled the selection
|
||||||
selectionCanceled = false;
|
selectionCanceled = false;
|
||||||
|
|
||||||
|
// If it's the first time that I move the selection, I cut it from its original position
|
||||||
if (firstTimeMove) {
|
if (firstTimeMove) {
|
||||||
cutSelection(mousePosition);
|
cutSelection(mousePosition);
|
||||||
}
|
}
|
||||||
@ -18,26 +24,34 @@ function updateMovePreview(mousePosition) {
|
|||||||
lastMousePos = mousePosition;
|
lastMousePos = mousePosition;
|
||||||
// clear the entire tmp layer
|
// clear the entire tmp layer
|
||||||
TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height);
|
TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height);
|
||||||
// put the image data with offset
|
// put the image data on the tmp layer with offset
|
||||||
TMPLayer.context.putImageData(
|
TMPLayer.context.putImageData(
|
||||||
imageDataToMove,
|
imageDataToMove,
|
||||||
Math.round(lastMousePos[0] / zoom) - imageDataToMove.width / 2,
|
Math.round(lastMousePos[0] / zoom) - imageDataToMove.width / 2,
|
||||||
Math.round(lastMousePos[1] / zoom) - imageDataToMove.height / 2);
|
Math.round(lastMousePos[1] / zoom) - imageDataToMove.height / 2);
|
||||||
|
|
||||||
lastMovePos = lastMousePos;
|
lastMovePos = lastMousePos;
|
||||||
|
// Moving the the rectangular ants
|
||||||
moveSelection(lastMousePos[0] / zoom, lastMousePos[1] / zoom, imageDataToMove.width, imageDataToMove.height);
|
moveSelection(lastMousePos[0] / zoom, lastMousePos[1] / zoom, imageDataToMove.width, imageDataToMove.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Ends a selection, meaning that it makes the changes definitive and creates the history states
|
||||||
|
*
|
||||||
|
*/
|
||||||
function endSelection() {
|
function endSelection() {
|
||||||
|
// Clearing the tmp (move preview) and vfx (ants) layers
|
||||||
TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height);
|
TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height);
|
||||||
VFXLayer.context.clearRect(0, 0, VFXLayer.canvas.width, VFXLayer.canvas.height);
|
VFXLayer.context.clearRect(0, 0, VFXLayer.canvas.width, VFXLayer.canvas.height);
|
||||||
|
// Preparing an empty imageData with the size of the canvas
|
||||||
let cleanImageData = new ImageData(endX - startX, endY - startY);
|
let cleanImageData = new ImageData(endX - startX, endY - startY);
|
||||||
|
|
||||||
|
// If I was moving something
|
||||||
if (imageDataToMove !== undefined) {
|
if (imageDataToMove !== undefined) {
|
||||||
console.log("definito");
|
|
||||||
// Saving the current clipboard before editing it in order to merge it with the current layer
|
// Saving the current clipboard before editing it in order to merge it with the current layer
|
||||||
cleanImageData.data.set(imageDataToMove.data);
|
cleanImageData.data.set(imageDataToMove.data);
|
||||||
|
|
||||||
|
// I have to save the underlying data, so that the transparent pixels in the clipboard
|
||||||
|
// don't override the coloured pixels in the canvas
|
||||||
let underlyingImageData = currentLayer.context.getImageData(startX, startY, endX - startX, endY - startY);
|
let underlyingImageData = currentLayer.context.getImageData(startX, startY, endX - startX, endY - startY);
|
||||||
|
|
||||||
for (let i=0; i<underlyingImageData.data.length; i+=4) {
|
for (let i=0; i<underlyingImageData.data.length; i+=4) {
|
||||||
@ -51,6 +65,7 @@ function endSelection() {
|
|||||||
underlyingImageData.data[i+2], underlyingImageData.data[i+3]
|
underlyingImageData.data[i+2], underlyingImageData.data[i+3]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// If the pixel of the clipboard is empty, but the one below it isn't, I use the pixel below
|
||||||
if (isPixelEmpty(currentMovePixel)) {
|
if (isPixelEmpty(currentMovePixel)) {
|
||||||
if (!isPixelEmpty(underlyingImageData)) {
|
if (!isPixelEmpty(underlyingImageData)) {
|
||||||
imageDataToMove.data[i] = currentUnderlyingPixel[0];
|
imageDataToMove.data[i] = currentUnderlyingPixel[0];
|
||||||
@ -61,13 +76,16 @@ function endSelection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If I moved the selection before confirming it
|
||||||
if (lastMovePos !== undefined) {
|
if (lastMovePos !== undefined) {
|
||||||
|
// I put it in the new position
|
||||||
currentLayer.context.putImageData(
|
currentLayer.context.putImageData(
|
||||||
imageDataToMove,
|
imageDataToMove,
|
||||||
Math.round(lastMovePos[0] / zoom) - imageDataToMove.width / 2,
|
Math.round(lastMovePos[0] / zoom) - imageDataToMove.width / 2,
|
||||||
Math.round(lastMovePos[1] / zoom) - imageDataToMove.height / 2);
|
Math.round(lastMovePos[1] / zoom) - imageDataToMove.height / 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// I put it in the same position
|
||||||
currentLayer.context.putImageData(
|
currentLayer.context.putImageData(
|
||||||
imageDataToMove,
|
imageDataToMove,
|
||||||
copiedStartX,
|
copiedStartX,
|
||||||
@ -77,6 +95,7 @@ function endSelection() {
|
|||||||
imageDataToMove.data.set(cleanImageData.data);
|
imageDataToMove.data.set(cleanImageData.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resetting all the flags
|
||||||
selectionCanceled = true;
|
selectionCanceled = true;
|
||||||
isRectSelecting = false;
|
isRectSelecting = false;
|
||||||
firstTimeMove = true;
|
firstTimeMove = true;
|
||||||
@ -86,5 +105,6 @@ function endSelection() {
|
|||||||
lastMovePos = undefined;
|
lastMovePos = undefined;
|
||||||
currentLayer.updateLayerPreview();
|
currentLayer.updateLayerPreview();
|
||||||
|
|
||||||
|
// Saving the history
|
||||||
new HistoryStateEditCanvas();
|
new HistoryStateEditCanvas();
|
||||||
}
|
}
|
@ -1,27 +1,44 @@
|
|||||||
|
// Start colour of the pixel grid (can be changed in the preferences)
|
||||||
let pixelGridColor = "#0000FF";
|
let pixelGridColor = "#0000FF";
|
||||||
|
// Distance between one line and another in HTML pixels
|
||||||
let lineDistance = 12;
|
let lineDistance = 12;
|
||||||
|
// The grid is not visible at the beginning
|
||||||
let pixelGridVisible = false;
|
let pixelGridVisible = false;
|
||||||
|
// Saving the canvas containing the pixel grid
|
||||||
pixelGridCanvas = document.getElementById("pixel-grid");
|
pixelGridCanvas = document.getElementById("pixel-grid");
|
||||||
|
|
||||||
|
/** Shows or hides the pixel grid depening on its current visibility
|
||||||
|
* (triggered by the show pixel grid button in the top menu)
|
||||||
|
*
|
||||||
|
*/
|
||||||
function togglePixelGrid(event) {
|
function togglePixelGrid(event) {
|
||||||
|
// Getting the button because I have to change its text
|
||||||
let button = document.getElementById("toggle-pixelgrid-button");
|
let button = document.getElementById("toggle-pixelgrid-button");
|
||||||
|
|
||||||
|
// Toggling the state
|
||||||
pixelGridVisible = !pixelGridVisible;
|
pixelGridVisible = !pixelGridVisible;
|
||||||
|
|
||||||
|
// If it was visible, I hide it
|
||||||
if (pixelGridVisible) {
|
if (pixelGridVisible) {
|
||||||
button.innerHTML = "Hide pixel grid";
|
button.innerHTML = "Hide pixel grid";
|
||||||
pixelGridCanvas.style.display = "inline-block";
|
pixelGridCanvas.style.display = "inline-block";
|
||||||
}
|
}
|
||||||
|
// Otherwise, I show it
|
||||||
else {
|
else {
|
||||||
button.innerHTML = "Show pixel grid";
|
button.innerHTML = "Show pixel grid";
|
||||||
pixelGridCanvas.style.display = "none";
|
pixelGridCanvas.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Fills the pixelGridCanvas with the pixelgrid
|
||||||
|
*
|
||||||
|
*/
|
||||||
function fillPixelGrid() {
|
function fillPixelGrid() {
|
||||||
let context = pixelGridCanvas.getContext("2d");
|
let context = pixelGridCanvas.getContext("2d");
|
||||||
let originalSize = layers[0].canvasSize;
|
let originalSize = layers[0].canvasSize;
|
||||||
|
|
||||||
|
// The pixelGridCanvas is lineDistance times bigger so that the lines don't take 1 canvas pixel
|
||||||
|
// (which would cover the whole canvas with the pixelGridColour), but they take 1/lineDistance canvas pixels
|
||||||
pixelGridCanvas.width = originalSize[0] * lineDistance;
|
pixelGridCanvas.width = originalSize[0] * lineDistance;
|
||||||
pixelGridCanvas.height = originalSize[1] * lineDistance;
|
pixelGridCanvas.height = originalSize[1] * lineDistance;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//prests
|
//presets
|
||||||
var presets = {
|
var presets = {
|
||||||
'Gameboy Color': {
|
'Gameboy Color': {
|
||||||
width: 240,
|
width: 240,
|
||||||
|
@ -4,6 +4,10 @@ let startY;
|
|||||||
let endX;
|
let endX;
|
||||||
let endY;
|
let endY;
|
||||||
|
|
||||||
|
/** Starts the selection: saves the canvas, sets the start coordinates
|
||||||
|
*
|
||||||
|
* @param {*} mouseEvent
|
||||||
|
*/
|
||||||
function startRectSelection(mouseEvent) {
|
function startRectSelection(mouseEvent) {
|
||||||
// Saving the canvas
|
// Saving the canvas
|
||||||
new HistoryStateEditCanvas();
|
new HistoryStateEditCanvas();
|
||||||
@ -35,6 +39,10 @@ function startRectSelection(mouseEvent) {
|
|||||||
selectionCanceled = false;
|
selectionCanceled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Updates the selection
|
||||||
|
*
|
||||||
|
* @param {*} mouseEvent
|
||||||
|
*/
|
||||||
function updateRectSelection(mouseEvent) {
|
function updateRectSelection(mouseEvent) {
|
||||||
let pos = getCursorPosition(mouseEvent);
|
let pos = getCursorPosition(mouseEvent);
|
||||||
|
|
||||||
@ -42,6 +50,10 @@ function updateRectSelection(mouseEvent) {
|
|||||||
drawRect(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5);
|
drawRect(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Ends the selection: sets the end coordiantes
|
||||||
|
*
|
||||||
|
* @param {*} mouseEvent
|
||||||
|
*/
|
||||||
function endRectSelection(mouseEvent) {
|
function endRectSelection(mouseEvent) {
|
||||||
// Getting the end position
|
// Getting the end position
|
||||||
let currentPos = getCursorPosition(mouseEvent);
|
let currentPos = getCursorPosition(mouseEvent);
|
||||||
@ -72,6 +84,10 @@ function endRectSelection(mouseEvent) {
|
|||||||
currentTool.updateCursor();
|
currentTool.updateCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Cuts the selection from its canvas and puts it in the tmp layer so it can be moved
|
||||||
|
*
|
||||||
|
* @param {*} mousePosition
|
||||||
|
*/
|
||||||
function cutSelection(mousePosition) {
|
function cutSelection(mousePosition) {
|
||||||
// Getting the selected pixels
|
// Getting the selected pixels
|
||||||
imageDataToMove = currentLayer.context.getImageData(startX, startY, endX - startX + 1, endY - startY + 1);
|
imageDataToMove = currentLayer.context.getImageData(startX, startY, endX - startX + 1, endY - startY + 1);
|
||||||
@ -79,10 +95,13 @@ function cutSelection(mousePosition) {
|
|||||||
currentLayer.context.clearRect(startX - 0.5, startY - 0.5, endX - startX + 1, endY - startY + 1);
|
currentLayer.context.clearRect(startX - 0.5, startY - 0.5, endX - startX + 1, endY - startY + 1);
|
||||||
// Moving those pixels from the current layer to the tmp layer
|
// Moving those pixels from the current layer to the tmp layer
|
||||||
TMPLayer.context.putImageData(imageDataToMove, startX + 1, startY);
|
TMPLayer.context.putImageData(imageDataToMove, startX + 1, startY);
|
||||||
|
|
||||||
//originalDataPosition = [currentPos[0], currentPos[1]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Draws a dashed rectangle representing the selection
|
||||||
|
*
|
||||||
|
* @param {*} x Current end x coordinate of the selection
|
||||||
|
* @param {*} y Current end y coordinate of the selection
|
||||||
|
*/
|
||||||
function drawRect(x, y) {
|
function drawRect(x, y) {
|
||||||
// Getting the vfx context
|
// Getting the vfx context
|
||||||
let vfxContext = VFXCanvas.getContext('2d');
|
let vfxContext = VFXCanvas.getContext('2d');
|
||||||
@ -106,10 +125,13 @@ function applyChanges() {
|
|||||||
|
|
||||||
// Checks whether the pointer is inside the selected area or not
|
// Checks whether the pointer is inside the selected area or not
|
||||||
function cursorInSelectedArea() {
|
function cursorInSelectedArea() {
|
||||||
|
// Getting the cursor position
|
||||||
let cursorPos = getCursorPosition(currentMouseEvent);
|
let cursorPos = getCursorPosition(currentMouseEvent);
|
||||||
|
// Getting the coordinates relatively to the canvas
|
||||||
let x = cursorPos[0] / zoom;
|
let x = cursorPos[0] / zoom;
|
||||||
let y = cursorPos[1] / zoom;
|
let y = cursorPos[1] / zoom;
|
||||||
|
|
||||||
|
// This is to avoid rightX or topY being less than leftX or bottomY
|
||||||
let leftX = Math.min(startX, endX);
|
let leftX = Math.min(startX, endX);
|
||||||
let rightX = Math.max(startX, endX);
|
let rightX = Math.max(startX, endX);
|
||||||
let topY = Math.max(startY, endY);
|
let topY = Math.max(startY, endY);
|
||||||
@ -126,6 +148,13 @@ function cursorInSelectedArea() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Moves the rect ants to the specified position
|
||||||
|
*
|
||||||
|
* @param {*} x X coordinate of the rect ants
|
||||||
|
* @param {*} y Y coordinat of the rect ants
|
||||||
|
* @param {*} width Width of the selection
|
||||||
|
* @param {*} height Height of the selectin
|
||||||
|
*/
|
||||||
function moveSelection(x, y, width, height) {
|
function moveSelection(x, y, width, height) {
|
||||||
// Getting the vfx context
|
// Getting the vfx context
|
||||||
let vfxContext = VFXCanvas.getContext('2d');
|
let vfxContext = VFXCanvas.getContext('2d');
|
||||||
@ -135,6 +164,7 @@ function moveSelection(x, y, width, height) {
|
|||||||
vfxContext.lineWidth = 1;
|
vfxContext.lineWidth = 1;
|
||||||
vfxContext.setLineDash([4]);
|
vfxContext.setLineDash([4]);
|
||||||
|
|
||||||
|
// Fixing the coordinates
|
||||||
startX = Math.round(Math.round(x) - 0.5 - Math.round(width / 2)) + 0.5;
|
startX = Math.round(Math.round(x) - 0.5 - Math.round(width / 2)) + 0.5;
|
||||||
startY = Math.round(Math.round(y) - 0.5 - Math.round(height / 2)) + 0.5;
|
startY = Math.round(Math.round(y) - 0.5 - Math.round(height / 2)) + 0.5;
|
||||||
endX = startX + Math.round(width);
|
endX = startX + Math.round(width);
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
|
// Saving the empty rect svg
|
||||||
var emptySVG = document.getElementById("empty-button-svg");
|
var emptySVG = document.getElementById("empty-button-svg");
|
||||||
|
// and the full rect svg so that I can change them when the user changes rect modes
|
||||||
var fullSVG = document.getElementById("full-button-svg");
|
var fullSVG = document.getElementById("full-button-svg");
|
||||||
|
|
||||||
|
// The start mode is empty rectangle
|
||||||
var drawMode = 'empty';
|
var drawMode = 'empty';
|
||||||
|
// I'm not drawing a rectangle at the beginning
|
||||||
var isDrawingRect = false;
|
var isDrawingRect = false;
|
||||||
|
|
||||||
|
// Rect coordinates
|
||||||
let startRectX;
|
let startRectX;
|
||||||
let startRectY;
|
let startRectY;
|
||||||
let endRectX;
|
let endRectX;
|
||||||
let endRectY;
|
let endRectY;
|
||||||
|
|
||||||
|
/** Starts drawing the rect, saves the start coordinates
|
||||||
|
*
|
||||||
|
* @param {*} mouseEvent
|
||||||
|
*/
|
||||||
function startRectDrawing(mouseEvent) {
|
function startRectDrawing(mouseEvent) {
|
||||||
// Putting the vfx layer on top of everything
|
// Putting the vfx layer on top of everything
|
||||||
VFXCanvas.style.zIndex = MAX_Z_INDEX;
|
VFXCanvas.style.zIndex = MAX_Z_INDEX;
|
||||||
@ -25,13 +32,22 @@ function startRectDrawing(mouseEvent) {
|
|||||||
drawRectangle(startRectX, startRectY);
|
drawRectangle(startRectX, startRectY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Updates the rectangle preview depending on the position of the mouse
|
||||||
|
*
|
||||||
|
* @param {*} mouseEvent The mouseEvent from which we'll get the mouse position
|
||||||
|
*/
|
||||||
function updateRectDrawing(mouseEvent) {
|
function updateRectDrawing(mouseEvent) {
|
||||||
let pos = getCursorPosition(mouseEvent);
|
let pos = getCursorPosition(mouseEvent);
|
||||||
|
|
||||||
// Drawing the rect
|
// Drawing the rect at the right position
|
||||||
drawRectangle(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5);
|
drawRectangle(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Finishes drawing the rect, decides the end coordinates and moves the preview rectangle to the
|
||||||
|
* current layer
|
||||||
|
*
|
||||||
|
* @param {*} mouseEvent event from which we'll get the mouse position
|
||||||
|
*/
|
||||||
function endRectDrawing(mouseEvent) {
|
function endRectDrawing(mouseEvent) {
|
||||||
// Getting the end position
|
// Getting the end position
|
||||||
let currentPos = getCursorPosition(mouseEvent);
|
let currentPos = getCursorPosition(mouseEvent);
|
||||||
@ -61,14 +77,17 @@ function endRectDrawing(mouseEvent) {
|
|||||||
endRectX -= 0.5;
|
endRectX -= 0.5;
|
||||||
startRectX -= 0.5;
|
startRectX -= 0.5;
|
||||||
|
|
||||||
|
// Setting the correct linewidth and colour
|
||||||
currentLayer.context.lineWidth = tool.rectangle.brushSize;
|
currentLayer.context.lineWidth = tool.rectangle.brushSize;
|
||||||
currentLayer.context.fillStyle = currentGlobalColor;
|
currentLayer.context.fillStyle = currentGlobalColor;
|
||||||
|
|
||||||
|
// Drawing the rect using 4 lines
|
||||||
line(startRectX, startRectY, endRectX, startRectY, tool.rectangle.brushSize);
|
line(startRectX, startRectY, endRectX, startRectY, tool.rectangle.brushSize);
|
||||||
line(endRectX, startRectY, endRectX, endRectY, tool.rectangle.brushSize);
|
line(endRectX, startRectY, endRectX, endRectY, tool.rectangle.brushSize);
|
||||||
line(endRectX, endRectY, startRectX, endRectY, tool.rectangle.brushSize);
|
line(endRectX, endRectY, startRectX, endRectY, tool.rectangle.brushSize);
|
||||||
line(startRectX, endRectY, startRectX, startRectY, tool.rectangle.brushSize);
|
line(startRectX, endRectY, startRectX, startRectY, tool.rectangle.brushSize);
|
||||||
|
|
||||||
|
// If I have to fill it, I do so
|
||||||
if (drawMode == 'fill') {
|
if (drawMode == 'fill') {
|
||||||
currentLayer.context.fillRect(startRectX, startRectY, endRectX - startRectX, endRectY - startRectY);
|
currentLayer.context.fillRect(startRectX, startRectY, endRectX - startRectX, endRectY - startRectY);
|
||||||
}
|
}
|
||||||
@ -77,6 +96,12 @@ function endRectDrawing(mouseEvent) {
|
|||||||
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
|
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Draws a rectangle with end coordinates given by x and y on the VFX layer (draws
|
||||||
|
* the preview for the rectangle tool)
|
||||||
|
*
|
||||||
|
* @param {*} x The current end x of the rectangle
|
||||||
|
* @param {*} y The current end y of the rectangle
|
||||||
|
*/
|
||||||
function drawRectangle(x, y) {
|
function drawRectangle(x, y) {
|
||||||
// Getting the vfx context
|
// Getting the vfx context
|
||||||
let vfxContext = VFXCanvas.getContext("2d");
|
let vfxContext = VFXCanvas.getContext("2d");
|
||||||
@ -98,10 +123,12 @@ function drawRectangle(x, y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vfxContext.setLineDash([]);
|
vfxContext.setLineDash([]);
|
||||||
|
|
||||||
vfxContext.stroke();
|
vfxContext.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets the correct tool icon depending on its mode
|
||||||
|
*
|
||||||
|
*/
|
||||||
function setRectToolSvg() {
|
function setRectToolSvg() {
|
||||||
if (drawMode == 'empty') {
|
if (drawMode == 'empty') {
|
||||||
emptySVG.setAttribute('display', 'visible');
|
emptySVG.setAttribute('display', 'visible');
|
||||||
|
@ -1,16 +1,31 @@
|
|||||||
let resizeCanvasContainer = document.getElementById("resize-canvas");
|
/* This scripts contains all the code used to handle the canvas resizing */
|
||||||
let rcPivot = "middle";
|
|
||||||
let currentPivotObject;
|
|
||||||
let borders = {left: 0, right: 0, top: 0, bottom: 0};
|
|
||||||
|
|
||||||
|
// Resize canvas pop up window
|
||||||
|
let resizeCanvasContainer = document.getElementById("resize-canvas");
|
||||||
|
// Start pivot
|
||||||
|
let rcPivot = "middle";
|
||||||
|
// Selected pivot button
|
||||||
|
let currentPivotObject;
|
||||||
|
// Border offsets
|
||||||
|
let rcBorders = {left: 0, right: 0, top: 0, bottom: 0};
|
||||||
|
|
||||||
|
/** Opens the canvas resize window
|
||||||
|
*
|
||||||
|
*/
|
||||||
function openResizeCanvasWindow() {
|
function openResizeCanvasWindow() {
|
||||||
|
// Initializes the inputs
|
||||||
initResizeCanvasInputs();
|
initResizeCanvasInputs();
|
||||||
showDialogue('resize-canvas');
|
showDialogue('resize-canvas');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initializes the canvas resizing input
|
||||||
|
*
|
||||||
|
*/
|
||||||
function initResizeCanvasInputs() {
|
function initResizeCanvasInputs() {
|
||||||
|
// Getting the pivot buttons
|
||||||
let buttons = document.getElementsByClassName("pivot-button");
|
let buttons = document.getElementsByClassName("pivot-button");
|
||||||
|
|
||||||
|
// Adding the event handlers for them
|
||||||
for (let i=0; i<buttons.length; i++) {
|
for (let i=0; i<buttons.length; i++) {
|
||||||
buttons[i].addEventListener("click", changePivot);
|
buttons[i].addEventListener("click", changePivot);
|
||||||
if (buttons[i].getAttribute("value").includes("middle")) {
|
if (buttons[i].getAttribute("value").includes("middle")) {
|
||||||
@ -33,13 +48,21 @@ function initResizeCanvasInputs() {
|
|||||||
console.log("Pivot selezionato: " + currentPivotObject);
|
console.log("Pivot selezionato: " + currentPivotObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Fired when a border offset is changed: it updates the width and height
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function rcChangedBorder(event) {
|
function rcChangedBorder(event) {
|
||||||
rcUpdateBorders();
|
rcUpdateBorders();
|
||||||
|
|
||||||
document.getElementById("rc-width").value = parseInt(layers[0].canvasSize[0]) + borders.left + borders.right;
|
document.getElementById("rc-width").value = parseInt(layers[0].canvasSize[0]) + rcBorders.left + rcBorders.right;
|
||||||
document.getElementById("rc-height").value = parseInt(layers[0].canvasSize[1]) + borders.top + borders.bottom;
|
document.getElementById("rc-height").value = parseInt(layers[0].canvasSize[1]) + rcBorders.top + rcBorders.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Fired when width or height are changed: updates the border offsets
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function rcChangedSize(event) {
|
function rcChangedSize(event) {
|
||||||
let widthOffset = Math.abs(document.getElementById("rc-width").value) - layers[0].canvasSize[0];
|
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];
|
let heightOffset = Math.abs(document.getElementById("rc-height").value) - layers[0].canvasSize[1];
|
||||||
@ -54,12 +77,19 @@ function rcChangedSize(event) {
|
|||||||
document.getElementById("rc-border-top").value = top;
|
document.getElementById("rc-border-top").value = top;
|
||||||
document.getElementById("rc-border-bottom").value = bottom;
|
document.getElementById("rc-border-bottom").value = bottom;
|
||||||
|
|
||||||
borders.left = left;
|
rcBorders.left = left;
|
||||||
borders.right = right;
|
rcBorders.right = right;
|
||||||
borders.top = top;
|
rcBorders.top = top;
|
||||||
borders.bottom = bottom;
|
rcBorders.bottom = bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
*/
|
||||||
function resizeCanvas(event, size, customData, saveHistory = true) {
|
function resizeCanvas(event, size, customData, saveHistory = true) {
|
||||||
let imageDatas = [];
|
let imageDatas = [];
|
||||||
let leftOffset = 0;
|
let leftOffset = 0;
|
||||||
@ -87,8 +117,8 @@ function resizeCanvas(event, size, customData, saveHistory = true) {
|
|||||||
if (saveHistory) {
|
if (saveHistory) {
|
||||||
// Saving history
|
// Saving history
|
||||||
new HistoryStateResizeCanvas(
|
new HistoryStateResizeCanvas(
|
||||||
{x: parseInt(layers[0].canvasSize[0]) + borders.left + borders.right,
|
{x: parseInt(layers[0].canvasSize[0]) + rcBorders.left + rcBorders.right,
|
||||||
y: parseInt(layers[0].canvasSize[1]) + borders.top + borders.bottom},
|
y: parseInt(layers[0].canvasSize[1]) + rcBorders.top + rcBorders.bottom},
|
||||||
|
|
||||||
{x: layers[0].canvasSize[0],
|
{x: layers[0].canvasSize[0],
|
||||||
y: layers[0].canvasSize[1]},
|
y: layers[0].canvasSize[1]},
|
||||||
@ -100,8 +130,8 @@ function resizeCanvas(event, size, customData, saveHistory = true) {
|
|||||||
|
|
||||||
// Resize the canvases
|
// Resize the canvases
|
||||||
for (let i=0; i<layers.length; i++) {
|
for (let i=0; i<layers.length; i++) {
|
||||||
layers[i].canvasSize[0] = parseInt(layers[i].canvasSize[0]) + borders.left + borders.right;
|
layers[i].canvasSize[0] = parseInt(layers[i].canvasSize[0]) + rcBorders.left + rcBorders.right;
|
||||||
layers[i].canvasSize[1] = parseInt(layers[i].canvasSize[1]) + borders.top + borders.bottom;
|
layers[i].canvasSize[1] = parseInt(layers[i].canvasSize[1]) + rcBorders.top + rcBorders.bottom;
|
||||||
|
|
||||||
layers[i].canvas.width = layers[i].canvasSize[0];
|
layers[i].canvas.width = layers[i].canvasSize[0];
|
||||||
layers[i].canvas.height = layers[i].canvasSize[1];
|
layers[i].canvas.height = layers[i].canvasSize[1];
|
||||||
@ -121,42 +151,43 @@ function resizeCanvas(event, size, customData, saveHistory = true) {
|
|||||||
topOffset = 0;
|
topOffset = 0;
|
||||||
break;
|
break;
|
||||||
case 'top':
|
case 'top':
|
||||||
leftOffset = (borders.left + borders.right) / 2;
|
leftOffset = (rcBorders.left + rcBorders.right) / 2;
|
||||||
topOffset = 0;
|
topOffset = 0;
|
||||||
break;
|
break;
|
||||||
case 'topright':
|
case 'topright':
|
||||||
leftOffset = borders.left + borders.right;
|
leftOffset = rcBorders.left + rcBorders.right;
|
||||||
topOffset = 0;
|
topOffset = 0;
|
||||||
break;
|
break;
|
||||||
case 'left':
|
case 'left':
|
||||||
leftOffset = 0;
|
leftOffset = 0;
|
||||||
topOffset = (borders.top + borders.bottom) / 2;
|
topOffset = (rcBorders.top + rcBorders.bottom) / 2;
|
||||||
break;
|
break;
|
||||||
case 'middle':
|
case 'middle':
|
||||||
leftOffset = (borders.left + borders.right) / 2;
|
leftOffset = (rcBorders.left + rcBorders.right) / 2;
|
||||||
topOffset = (borders.top + borders.bottom) / 2;
|
topOffset = (rcBorders.top + rcBorders.bottom) / 2;
|
||||||
break;
|
break;
|
||||||
case 'right':
|
case 'right':
|
||||||
leftOffset = borders.left + borders.right;
|
leftOffset = rcBorders.left + rcBorders.right;
|
||||||
topOffset = (borders.top + borders.bottom) / 2;
|
topOffset = (rcBorders.top + rcBorders.bottom) / 2;
|
||||||
break;
|
break;
|
||||||
case 'bottomleft':
|
case 'bottomleft':
|
||||||
leftOffset = 0;
|
leftOffset = 0;
|
||||||
topOffset = borders.top + borders.bottom;
|
topOffset = rcBorders.top + rcBorders.bottom;
|
||||||
break;
|
break;
|
||||||
case 'bottom':
|
case 'bottom':
|
||||||
leftOffset = (borders.left + borders.right) / 2;
|
leftOffset = (rcBorders.left + rcBorders.right) / 2;
|
||||||
topOffset = borders.top + borders.bottom;
|
topOffset = rcBorders.top + rcBorders.bottom;
|
||||||
break;
|
break;
|
||||||
case 'bottomright':
|
case 'bottomright':
|
||||||
leftOffset = borders.left + borders.right;
|
leftOffset = rcBorders.left + rcBorders.right;
|
||||||
topOffset = borders.top + borders.bottom;
|
topOffset = rcBorders.top + rcBorders.bottom;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('Pivot does not exist, please report an issue at https://github.com/lospec/pixel-editor');
|
console.log('Pivot does not exist, please report an issue at https://github.com/lospec/pixel-editor');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Putting all the data for each layer with the right offsets (decided by the pivot)
|
||||||
for (let i=0; i<layers.length; i++) {
|
for (let i=0; i<layers.length; i++) {
|
||||||
if (layers[i].menuEntry != null) {
|
if (layers[i].menuEntry != null) {
|
||||||
if (customData == undefined) {
|
if (customData == undefined) {
|
||||||
@ -176,6 +207,11 @@ function resizeCanvas(event, size, customData, saveHistory = true) {
|
|||||||
closeDialogue();
|
closeDialogue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
*/
|
||||||
function trimCanvas(event, saveHistory) {
|
function trimCanvas(event, saveHistory) {
|
||||||
let minY = Infinity;
|
let minY = Infinity;
|
||||||
let minX = Infinity;
|
let minX = Infinity;
|
||||||
@ -189,6 +225,7 @@ function trimCanvas(event, saveHistory) {
|
|||||||
rcPivot = "topleft";
|
rcPivot = "topleft";
|
||||||
console.log("debug");
|
console.log("debug");
|
||||||
|
|
||||||
|
// Computing the min and max coordinates in which there's a non empty pixel
|
||||||
for (let i=1; i<layers.length - nAppLayers; i++) {
|
for (let i=1; i<layers.length - nAppLayers; i++) {
|
||||||
let imageData = layers[i].context.getImageData(0, 0, layers[0].canvasSize[0], layers[0].canvasSize[1]);
|
let imageData = layers[i].context.getImageData(0, 0, layers[0].canvasSize[0], layers[0].canvasSize[1]);
|
||||||
let pixelPosition;
|
let pixelPosition;
|
||||||
@ -226,10 +263,11 @@ function trimCanvas(event, saveHistory) {
|
|||||||
minY = layers[0].canvasSize[1] - minY;
|
minY = layers[0].canvasSize[1] - minY;
|
||||||
maxY = layers[0].canvasSize[1] - maxY;
|
maxY = layers[0].canvasSize[1] - maxY;
|
||||||
|
|
||||||
borders.right = (maxX - layers[0].canvasSize[0]) + 1;
|
// Setting the borders coherently with the values I've just computed
|
||||||
borders.left = -minX;
|
rcBorders.right = (maxX - layers[0].canvasSize[0]) + 1;
|
||||||
borders.top = maxY - layers[0].canvasSize[1] + 1;
|
rcBorders.left = -minX;
|
||||||
borders.bottom = -minY;
|
rcBorders.top = maxY - layers[0].canvasSize[1] + 1;
|
||||||
|
rcBorders.bottom = -minY;
|
||||||
|
|
||||||
// Saving the data
|
// Saving the data
|
||||||
for (let i=0; i<layers.length; i++) {
|
for (let i=0; i<layers.length; i++) {
|
||||||
@ -241,11 +279,12 @@ function trimCanvas(event, saveHistory) {
|
|||||||
console.log(imageDatas);
|
console.log(imageDatas);
|
||||||
//console.log("sx: " + borders.left + "dx: " + borders.right + "top: " + borders.top + "btm: " + borders.bottom);
|
//console.log("sx: " + borders.left + "dx: " + borders.right + "top: " + borders.top + "btm: " + borders.bottom);
|
||||||
|
|
||||||
document.getElementById("rc-border-left").value = borders.left;
|
document.getElementById("rc-border-left").value = rcBorders.left;
|
||||||
document.getElementById("rc-border-right").value = borders.right;
|
document.getElementById("rc-border-right").value = rcBorders.right;
|
||||||
document.getElementById("rc-border-top").value = borders.top;
|
document.getElementById("rc-border-top").value = rcBorders.top;
|
||||||
document.getElementById("rc-border-bottom").value = borders.bottom;
|
document.getElementById("rc-border-bottom").value = rcBorders.bottom;
|
||||||
|
|
||||||
|
// Resizing the canvas with the decided border offsets
|
||||||
resizeCanvas(null, null, imageDatas.slice(), historySave);
|
resizeCanvas(null, null, imageDatas.slice(), historySave);
|
||||||
// Resetting the previous pivot
|
// Resetting the previous pivot
|
||||||
rcPivot = prevPivot;
|
rcPivot = prevPivot;
|
||||||
@ -253,16 +292,16 @@ function trimCanvas(event, saveHistory) {
|
|||||||
|
|
||||||
function rcUpdateBorders() {
|
function rcUpdateBorders() {
|
||||||
// Getting input
|
// Getting input
|
||||||
borders.left = document.getElementById("rc-border-left").value;
|
rcBorders.left = document.getElementById("rc-border-left").value;
|
||||||
borders.right = document.getElementById("rc-border-right").value;
|
rcBorders.right = document.getElementById("rc-border-right").value;
|
||||||
borders.top = document.getElementById("rc-border-top").value;
|
rcBorders.top = document.getElementById("rc-border-top").value;
|
||||||
borders.bottom = document.getElementById("rc-border-bottom").value;
|
rcBorders.bottom = document.getElementById("rc-border-bottom").value;
|
||||||
|
|
||||||
// Validating input
|
// Validating input
|
||||||
borders.left == "" ? borders.left = 0 : borders.left = Math.round(parseInt(borders.left));
|
rcBorders.left == "" ? rcBorders.left = 0 : rcBorders.left = Math.round(parseInt(rcBorders.left));
|
||||||
borders.right == "" ? borders.right = 0 : borders.right = Math.round(parseInt(borders.right));
|
rcBorders.right == "" ? rcBorders.right = 0 : rcBorders.right = Math.round(parseInt(rcBorders.right));
|
||||||
borders.top == "" ? borders.top = 0 : borders.top = Math.round(parseInt(borders.top));
|
rcBorders.top == "" ? rcBorders.top = 0 : rcBorders.top = Math.round(parseInt(rcBorders.top));
|
||||||
borders.bottom == "" ? borders.bottom = 0 : borders.bottom = Math.round(parseInt(borders.bottom));
|
rcBorders.bottom == "" ? rcBorders.bottom = 0 : rcBorders.bottom = Math.round(parseInt(rcBorders.bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
function changePivot(event) {
|
function changePivot(event) {
|
||||||
|
@ -1,15 +1,26 @@
|
|||||||
|
/* This scripts contains all the code used to handle the sprite scaling */
|
||||||
|
// Should I keep the sprite ratio?
|
||||||
let keepRatio = true;
|
let keepRatio = true;
|
||||||
|
// Used to store the current ratio
|
||||||
let currentRatio;
|
let currentRatio;
|
||||||
|
// The currenty selected resizing algorithm (nearest-neighbor or bilinear-interpolation)
|
||||||
let currentAlgo = 'nearest-neighbor';
|
let currentAlgo = 'nearest-neighbor';
|
||||||
|
// Current resize data
|
||||||
let data = {width: 0, height: 0, widthPercentage: 100, heightPercentage: 100};
|
let data = {width: 0, height: 0, widthPercentage: 100, heightPercentage: 100};
|
||||||
|
// Start resize data
|
||||||
let startData = {width: 0, height:0, widthPercentage: 100, heightPercentage: 100};
|
let startData = {width: 0, height:0, widthPercentage: 100, heightPercentage: 100};
|
||||||
|
|
||||||
|
/** Opens the sprite resizing window
|
||||||
|
*
|
||||||
|
*/
|
||||||
function openResizeSpriteWindow() {
|
function openResizeSpriteWindow() {
|
||||||
|
// Inits the sprie resize inputs
|
||||||
initResizeSpriteInputs();
|
initResizeSpriteInputs();
|
||||||
|
|
||||||
|
// Computing the current ratio
|
||||||
currentRatio = layers[0].canvasSize[0] / layers[0].canvasSize[1];
|
currentRatio = layers[0].canvasSize[0] / layers[0].canvasSize[1];
|
||||||
|
|
||||||
|
// Initializing the input fields
|
||||||
data.width = layers[0].canvasSize[0];
|
data.width = layers[0].canvasSize[0];
|
||||||
data.height = layers[1].canvasSize[1];
|
data.height = layers[1].canvasSize[1];
|
||||||
|
|
||||||
@ -18,9 +29,13 @@ function openResizeSpriteWindow() {
|
|||||||
startData.heightPercentage = 100;
|
startData.heightPercentage = 100;
|
||||||
startData.widthPercentage = 100;
|
startData.widthPercentage = 100;
|
||||||
|
|
||||||
|
// Opening the pop up now that it's ready
|
||||||
showDialogue('resize-sprite');
|
showDialogue('resize-sprite');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initalizes the input values and binds the elements to their events
|
||||||
|
*
|
||||||
|
*/
|
||||||
function initResizeSpriteInputs() {
|
function initResizeSpriteInputs() {
|
||||||
document.getElementById("rs-width").value = layers[0].canvasSize[0];
|
document.getElementById("rs-width").value = layers[0].canvasSize[0];
|
||||||
document.getElementById("rs-height").value = layers[0].canvasSize[1];
|
document.getElementById("rs-height").value = layers[0].canvasSize[1];
|
||||||
@ -40,11 +55,21 @@ function initResizeSpriteInputs() {
|
|||||||
document.getElementById("resize-algorithm-combobox").addEventListener("change", changedAlgorithm);
|
document.getElementById("resize-algorithm-combobox").addEventListener("change", changedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resizes (scales) the sprite
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
* @param {*} ratio Keeps infos about the x ratio and y ratio
|
||||||
|
*/
|
||||||
function resizeSprite(event, ratio) {
|
function resizeSprite(event, ratio) {
|
||||||
|
// Old data
|
||||||
let oldWidth, oldHeight;
|
let oldWidth, oldHeight;
|
||||||
|
// New data
|
||||||
let newWidth, newHeight;
|
let newWidth, newHeight;
|
||||||
|
// Current imageDatas
|
||||||
let rsImageDatas = [];
|
let rsImageDatas = [];
|
||||||
|
// Index that will be used a few lines below
|
||||||
let layerIndex = 0;
|
let layerIndex = 0;
|
||||||
|
// Copy of the imageDatas that will be stored in the history
|
||||||
let imageDatasCopy = [];
|
let imageDatasCopy = [];
|
||||||
|
|
||||||
oldWidth = layers[0].canvasSize[0];
|
oldWidth = layers[0].canvasSize[0];
|
||||||
@ -70,6 +95,7 @@ function resizeSprite(event, ratio) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Computing newWidth and newHeight
|
||||||
if (ratio == null) {
|
if (ratio == null) {
|
||||||
newWidth = data.width;
|
newWidth = data.width;
|
||||||
newHeight = data.height;
|
newHeight = data.height;
|
||||||
@ -88,8 +114,11 @@ function resizeSprite(event, ratio) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ratio is null when the user is undoing
|
||||||
if (ratio == null) {
|
if (ratio == null) {
|
||||||
|
// Copying the image data
|
||||||
imageDatasCopy = rsImageDatas.slice();
|
imageDatasCopy = rsImageDatas.slice();
|
||||||
|
// Saving the history
|
||||||
new HistoryStateResizeSprite(newWidth / oldWidth, newHeight / oldHeight, currentAlgo, imageDatasCopy);
|
new HistoryStateResizeSprite(newWidth / oldWidth, newHeight / oldHeight, currentAlgo, imageDatasCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +153,12 @@ function resizeSprite(event, ratio) {
|
|||||||
closeDialogue();
|
closeDialogue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Trust me, the math for the functions below works. If you want to optimize them feel free to have a look, though */
|
||||||
|
|
||||||
|
/** Fired when the input field for width is changed. Updates th othe input fields consequently
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function changedWidth(event) {
|
function changedWidth(event) {
|
||||||
let oldValue = data.width;
|
let oldValue = data.width;
|
||||||
let ratio;
|
let ratio;
|
||||||
@ -150,6 +185,10 @@ function changedWidth(event) {
|
|||||||
document.getElementById("rs-width-percentage").value = newWidthPerc;
|
document.getElementById("rs-width-percentage").value = newWidthPerc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Fired when the input field for width is changed. Updates the other input fields consequently
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function changedHeight(event) {
|
function changedHeight(event) {
|
||||||
let oldValue = 100;
|
let oldValue = 100;
|
||||||
let ratio;
|
let ratio;
|
||||||
@ -176,6 +215,10 @@ function changedHeight(event) {
|
|||||||
data.heightPercentage = newHeightPerc;
|
data.heightPercentage = newHeightPerc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Fired when the input field for width percentage is changed. Updates the other input fields consequently
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function changedWidthPercentage(event) {
|
function changedWidthPercentage(event) {
|
||||||
let oldValue = 100;
|
let oldValue = 100;
|
||||||
let ratio;
|
let ratio;
|
||||||
@ -204,6 +247,10 @@ function changedWidthPercentage(event) {
|
|||||||
data.width = newWidth;
|
data.width = newWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Fired when the input field for height percentage is changed. Updates the other input fields consequently
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function changedHeightPercentage(event) {
|
function changedHeightPercentage(event) {
|
||||||
let oldValue = data.heightPercentage;
|
let oldValue = data.heightPercentage;
|
||||||
let ratio;
|
let ratio;
|
||||||
@ -230,10 +277,18 @@ function changedHeightPercentage(event) {
|
|||||||
data.height = newHeight;
|
data.height = newHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Toggles the keepRatio value (fired by the checkbox in the pop up window)
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function toggleRatio(event) {
|
function toggleRatio(event) {
|
||||||
keepRatio = !keepRatio;
|
keepRatio = !keepRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Changes the scaling algorithm (fired by the combobox in the pop up window)
|
||||||
|
*
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
function changedAlgorithm(event) {
|
function changedAlgorithm(event) {
|
||||||
currentAlgo = event.target.value;
|
currentAlgo = event.target.value;
|
||||||
}
|
}
|
Reference in New Issue
Block a user