mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Started commenting code
This commit is contained in:
parent
19e6fd1aca
commit
9ef0e6ecea
@ -1,8 +1,11 @@
|
|||||||
let currentPalette = [];
|
let currentPalette = [];
|
||||||
|
|
||||||
//adds the given color to the palette
|
|
||||||
//input hex color string
|
/** Adds the given color to the palette
|
||||||
//returns list item element
|
*
|
||||||
|
* @param {*} newColor the colour to add
|
||||||
|
* @return the list item containing the added colour
|
||||||
|
*/
|
||||||
function addColor (newColor) {
|
function addColor (newColor) {
|
||||||
//add # at beginning if not present
|
//add # at beginning if not present
|
||||||
if (newColor.charAt(0) != '#')
|
if (newColor.charAt(0) != '#')
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//add color button
|
// add-color-button management
|
||||||
on('click', 'add-color-button', function(){
|
on('click', 'add-color-button', function(){
|
||||||
if (!documentCreated) return;
|
if (!documentCreated) return;
|
||||||
|
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
function changeZoom (layer, direction, cursorLocation) {
|
/** Changes the zoom level of the canvas
|
||||||
|
* @param {*} direction 'in' or 'out'
|
||||||
|
* @param {*} cursorLocation The position of the cursor when the user zoomed
|
||||||
|
*/
|
||||||
|
function changeZoom (direction, cursorLocation) {
|
||||||
|
// Computing current width and height
|
||||||
var oldWidth = canvasSize[0] * zoom;
|
var oldWidth = canvasSize[0] * zoom;
|
||||||
var oldHeight = canvasSize[1] * zoom;
|
var oldHeight = canvasSize[1] * zoom;
|
||||||
var newWidth, newHeight;
|
var newWidth, newHeight;
|
||||||
@ -11,7 +16,9 @@ function changeZoom (layer, direction, cursorLocation) {
|
|||||||
newHeight = canvasSize[1] * zoom;
|
newHeight = canvasSize[1] * zoom;
|
||||||
|
|
||||||
//adjust canvas position
|
//adjust canvas position
|
||||||
layer.setCanvasOffset(layer.canvas.offsetLeft + (oldWidth - newWidth) *cursorLocation[0]/oldWidth, layer.canvas.offsetTop + (oldHeight - newHeight) *cursorLocation[1]/oldWidth);
|
layers[0].setCanvasOffset(
|
||||||
|
layers[0].canvas.offsetLeft + (oldWidth - newWidth) * cursorLocation[0]/oldWidth,
|
||||||
|
layers[0].canvas.offsetTop + (oldHeight - newHeight) * cursorLocation[1]/oldWidth);
|
||||||
}
|
}
|
||||||
//if you want to zoom in
|
//if you want to zoom in
|
||||||
else if (direction == 'in' && zoom + Math.ceil(zoom/10) < window.innerHeight/4){
|
else if (direction == 'in' && zoom + Math.ceil(zoom/10) < window.innerHeight/4){
|
||||||
@ -20,11 +27,13 @@ function changeZoom (layer, direction, cursorLocation) {
|
|||||||
newHeight = canvasSize[1] * zoom;
|
newHeight = canvasSize[1] * zoom;
|
||||||
|
|
||||||
//adjust canvas position
|
//adjust canvas position
|
||||||
layer.setCanvasOffset(layer.canvas.offsetLeft - Math.round((newWidth - oldWidth)*cursorLocation[0]/oldWidth), layer.canvas.offsetTop - Math.round((newHeight - oldHeight)*cursorLocation[1]/oldHeight));
|
layers[0].setCanvasOffset(
|
||||||
|
layers[0].canvas.offsetLeft - Math.round((newWidth - oldWidth)*cursorLocation[0]/oldWidth),
|
||||||
|
layers[0].canvas.offsetTop - Math.round((newHeight - oldHeight)*cursorLocation[1]/oldHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
//resize canvas
|
//resize canvas
|
||||||
layer.resize();
|
layers[0].resize();
|
||||||
|
|
||||||
// adjust brush size
|
// adjust brush size
|
||||||
currentTool.updateCursor();
|
currentTool.updateCursor();
|
||||||
|
@ -13,7 +13,9 @@ var currentColor = firstCheckerBoardColor;
|
|||||||
// Saving number of squares filled until now
|
// Saving number of squares filled until now
|
||||||
var nSquaresFilled = 0;
|
var nSquaresFilled = 0;
|
||||||
|
|
||||||
|
/** Fills the checkerboard canvas with squares with alternating colours
|
||||||
|
*
|
||||||
|
*/
|
||||||
function fillCheckerboard() {
|
function fillCheckerboard() {
|
||||||
// Getting checkerboard context
|
// Getting checkerboard context
|
||||||
var context = checkerBoard.context;
|
var context = checkerBoard.context;
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
|
// Data saved when copying or cutting
|
||||||
let clipboardData;
|
let clipboardData;
|
||||||
|
// Tells if the user is pasting something or not
|
||||||
let isPasting = false;
|
let isPasting = false;
|
||||||
|
|
||||||
|
// Coordinates of the copied (or cut) selection
|
||||||
let copiedStartX;
|
let copiedStartX;
|
||||||
let copiedStartY;
|
let copiedStartY;
|
||||||
let copiedEndX;
|
let copiedEndX;
|
||||||
let copiedEndY;
|
let copiedEndY;
|
||||||
|
|
||||||
|
/** Copies the current selection to the clipboard
|
||||||
|
*
|
||||||
|
*/
|
||||||
function copySelection() {
|
function copySelection() {
|
||||||
copiedEndX = endX;
|
copiedEndX = endX;
|
||||||
copiedEndY = endY;
|
copiedEndY = endY;
|
||||||
@ -16,13 +22,19 @@ function copySelection() {
|
|||||||
clipboardData = currentLayer.context.getImageData(startX, startY, endX - startX + 1, endY - startY + 1);
|
clipboardData = currentLayer.context.getImageData(startX, startY, endX - startX + 1, endY - startY + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Pastes the clipboard data onto the current layer
|
||||||
|
*
|
||||||
|
*/
|
||||||
function pasteSelection() {
|
function pasteSelection() {
|
||||||
// Can't paste if the layer is locked
|
// Can't paste if the layer is locked
|
||||||
if (currentLayer.isLocked) {
|
if (currentLayer.isLocked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel the current selection
|
||||||
endSelection();
|
endSelection();
|
||||||
|
|
||||||
|
// I'm pasting
|
||||||
isPasting = true;
|
isPasting = true;
|
||||||
// Putting the image data on the tmp layer
|
// Putting the image data on the tmp layer
|
||||||
TMPLayer.context.putImageData(clipboardData, copiedStartX, copiedStartY);
|
TMPLayer.context.putImageData(clipboardData, copiedStartX, copiedStartY);
|
||||||
@ -43,9 +55,11 @@ function pasteSelection() {
|
|||||||
//drawRect(copiedStartX, copiedEndX, copiedStartY, copiedEndY);
|
//drawRect(copiedStartX, copiedEndX, copiedStartY, copiedEndY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Cuts the current selection and copies it to the clipboard
|
||||||
|
*
|
||||||
|
*/
|
||||||
function cutSelectionTool() {
|
function cutSelectionTool() {
|
||||||
console.log("Taglio");
|
// Saving the coordinates
|
||||||
|
|
||||||
copiedEndX = endX;
|
copiedEndX = endX;
|
||||||
copiedEndY = endY;
|
copiedEndY = endY;
|
||||||
|
|
||||||
@ -53,13 +67,19 @@ function cutSelectionTool() {
|
|||||||
copiedStartY = startY;
|
copiedStartY = startY;
|
||||||
|
|
||||||
// Getting the selected pixels
|
// Getting the selected pixels
|
||||||
|
// If I'm already moving a selection
|
||||||
if (imageDataToMove !== undefined) {
|
if (imageDataToMove !== undefined) {
|
||||||
|
// I just save that selection in the clipboard
|
||||||
clipboardData = imageDataToMove;
|
clipboardData = imageDataToMove;
|
||||||
|
// And clear the underlying space
|
||||||
TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height);
|
TMPLayer.context.clearRect(0, 0, TMPLayer.canvas.width, TMPLayer.canvas.height);
|
||||||
|
// The image has been cleared, so I don't have anything to move anymore
|
||||||
imageDataToMove = undefined;
|
imageDataToMove = undefined;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
clipboardData = currentLayer.context.getImageData(startX, startY, endX - startX + 1, endY - startY + 1);
|
// Otherwise, I copy the current selection into the clipboard
|
||||||
|
copySelection();
|
||||||
|
// And clear the selection
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,13 @@
|
|||||||
|
/** Triggered when the "Create" button in the new pixel dialogue is pressed
|
||||||
|
*
|
||||||
|
*/
|
||||||
on('click', 'create-button', function (){
|
on('click', 'create-button', function (){
|
||||||
|
// Getting the values of the form
|
||||||
var width = getValue('size-width');
|
var width = getValue('size-width');
|
||||||
var height = getValue('size-height');
|
var height = getValue('size-height');
|
||||||
var mode = getValue("editor-mode");
|
var mode = getValue("editor-mode");
|
||||||
|
|
||||||
|
// Creating a new pixel with those properties
|
||||||
newPixel(width, height, mode);
|
newPixel(width, height, mode);
|
||||||
document.getElementById('new-pixel-warning').style.display = 'block';
|
document.getElementById('new-pixel-warning').style.display = 'block';
|
||||||
|
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
|
|
||||||
function createColorPalette(paletteColors, fillBackground, deletePreviousPalette = true) {
|
/** Creates the colour palette
|
||||||
|
*
|
||||||
|
* @param {*} paletteColors The colours of the palette
|
||||||
|
* @param {*} deletePreviousPalette Tells if the app should delete the previous palette or not
|
||||||
|
* (used when opening a file, for example)
|
||||||
|
*/
|
||||||
|
function createColorPalette(paletteColors, deletePreviousPalette = true) {
|
||||||
//remove current palette
|
//remove current palette
|
||||||
if (deletePreviousPalette) {
|
if (deletePreviousPalette) {
|
||||||
colors = document.getElementsByClassName('color-button');
|
colors = document.getElementsByClassName('color-button');
|
||||||
@ -11,6 +17,7 @@ function createColorPalette(paletteColors, fillBackground, deletePreviousPalette
|
|||||||
var lightestColor = '#000000';
|
var lightestColor = '#000000';
|
||||||
var darkestColor = '#ffffff';
|
var darkestColor = '#ffffff';
|
||||||
|
|
||||||
|
// Adding all the colours in the array
|
||||||
for (var i = 0; i < paletteColors.length; i++) {
|
for (var i = 0; i < paletteColors.length; i++) {
|
||||||
var newColor = paletteColors[i];
|
var newColor = paletteColors[i];
|
||||||
var newColorElement = addColor(newColor);
|
var newColorElement = addColor(newColor);
|
||||||
@ -42,6 +49,9 @@ function createColorPalette(paletteColors, fillBackground, deletePreviousPalette
|
|||||||
currentLayer.context.fillStyle = darkestColor;
|
currentLayer.context.fillStyle = darkestColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates the palette with the colours used in all the layers
|
||||||
|
*
|
||||||
|
*/
|
||||||
function createPaletteFromLayers() {
|
function createPaletteFromLayers() {
|
||||||
let colors = {};
|
let colors = {};
|
||||||
|
|
||||||
@ -68,8 +78,6 @@ function createPaletteFromLayers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(colors);
|
|
||||||
|
|
||||||
//create array out of colors object
|
//create array out of colors object
|
||||||
let colorPaletteArray = [];
|
let colorPaletteArray = [];
|
||||||
for (let color in colors) {
|
for (let color in colors) {
|
||||||
@ -77,7 +85,6 @@ function createPaletteFromLayers() {
|
|||||||
colorPaletteArray.push('#'+rgbToHex(colors[color]));
|
colorPaletteArray.push('#'+rgbToHex(colors[color]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('COLOR PALETTE ARRAY', colorPaletteArray);
|
|
||||||
|
|
||||||
//create palette form colors array
|
//create palette form colors array
|
||||||
createColorPalette(colorPaletteArray, false);
|
createColorPalette(colorPaletteArray, false);
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
|
/** Shows the dialogue window called dialogueName, which is a child of pop-up-container in pixel-editor.hbs
|
||||||
|
*
|
||||||
|
* @param {*} dialogueName The name of the window to show
|
||||||
|
* @param {*} trackEvent Should I track the GA event?
|
||||||
|
*/
|
||||||
function showDialogue (dialogueName, trackEvent) {
|
function showDialogue (dialogueName, trackEvent) {
|
||||||
if (typeof trackEvent === 'undefined') trackEvent = true;
|
if (typeof trackEvent === 'undefined') trackEvent = true;
|
||||||
|
|
||||||
|
// The pop up window is open
|
||||||
dialogueOpen = true;
|
dialogueOpen = true;
|
||||||
|
// Showing the pop up container
|
||||||
popUpContainer.style.display = 'block';
|
popUpContainer.style.display = 'block';
|
||||||
|
|
||||||
|
// Showing the window
|
||||||
document.getElementById(dialogueName).style.display = 'block';
|
document.getElementById(dialogueName).style.display = 'block';
|
||||||
|
|
||||||
//track google event
|
//track google event
|
||||||
@ -11,6 +19,9 @@ function showDialogue (dialogueName, trackEvent) {
|
|||||||
ga('send', 'event', 'Palette Editor Dialogue', dialogueName); /*global ga*/
|
ga('send', 'event', 'Palette Editor Dialogue', dialogueName); /*global ga*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Closes the current dialogue by hiding the window and the pop-up-container
|
||||||
|
*
|
||||||
|
*/
|
||||||
function closeDialogue () {
|
function closeDialogue () {
|
||||||
popUpContainer.style.display = 'none';
|
popUpContainer.style.display = 'none';
|
||||||
|
|
||||||
@ -22,6 +33,9 @@ function closeDialogue () {
|
|||||||
dialogueOpen = false;
|
dialogueOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Closes a dialogue window if the user clicks everywhere but in the current window
|
||||||
|
*
|
||||||
|
*/
|
||||||
popUpContainer.addEventListener('click', function (e) {
|
popUpContainer.addEventListener('click', function (e) {
|
||||||
if (e.target == popUpContainer)
|
if (e.target == popUpContainer)
|
||||||
closeDialogue();
|
closeDialogue();
|
||||||
|
@ -456,7 +456,7 @@ function deleteLayer(saveHistory = true) {
|
|||||||
unusedIDs.push(toDelete.id);
|
unusedIDs.push(toDelete.id);
|
||||||
|
|
||||||
// Selecting the next layer
|
// Selecting the next layer
|
||||||
if (layerIndex != (layers.length - 3)) {
|
if (layerIndex != (layers.length - 4)) {
|
||||||
layers[layerIndex + 1].selectLayer();
|
layers[layerIndex + 1].selectLayer();
|
||||||
}
|
}
|
||||||
// or the previous one if the next one doesn't exist
|
// or the previous one if the next one doesn't exist
|
||||||
|
@ -134,7 +134,7 @@ window.addEventListener("mouseup", function (mouseEvent) {
|
|||||||
mode = 'out';
|
mode = 'out';
|
||||||
}
|
}
|
||||||
|
|
||||||
changeZoom(layers[0], mode, getCursorPosition(mouseEvent));
|
changeZoom(mode, getCursorPosition(mouseEvent));
|
||||||
|
|
||||||
for (let i=1; i<layers.length; i++) {
|
for (let i=1; i<layers.length; i++) {
|
||||||
layers[i].copyData(layers[0]);
|
layers[i].copyData(layers[0]);
|
||||||
@ -360,7 +360,7 @@ canvasView.addEventListener("wheel", function(mouseEvent){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Changing zoom and position of the first layer
|
// Changing zoom and position of the first layer
|
||||||
changeZoom(layers[0], mode, getCursorPosition(mouseEvent));
|
changeZoom(mode, getCursorPosition(mouseEvent));
|
||||||
|
|
||||||
for (let i=1; i<layers.length; i++) {
|
for (let i=1; i<layers.length; i++) {
|
||||||
// Copying first layer's data into the other layers
|
// Copying first layer's data into the other layers
|
||||||
|
@ -1,16 +1,32 @@
|
|||||||
let firstPixel = true;
|
let firstPixel = true;
|
||||||
|
|
||||||
|
/** Creates a new, empty file
|
||||||
|
*
|
||||||
|
* @param {*} width Start width of the canvas
|
||||||
|
* @param {*} height Start height of the canvas
|
||||||
|
* @param {*} editorMode The editor mode chosen by the user (advanced or basic)
|
||||||
|
* @param {*} fileContent If fileContent != null, then the newPixel is being called from the open menu
|
||||||
|
*/
|
||||||
function newPixel (width, height, editorMode, fileContent = null) {
|
function newPixel (width, height, editorMode, fileContent = null) {
|
||||||
|
// Saving the editor mode
|
||||||
pixelEditorMode = editorMode;
|
pixelEditorMode = editorMode;
|
||||||
|
|
||||||
|
// The palette is empty, at the beginning
|
||||||
currentPalette = [];
|
currentPalette = [];
|
||||||
|
|
||||||
|
// If this is the first pixel I'm creating since the app has started
|
||||||
if (firstPixel) {
|
if (firstPixel) {
|
||||||
|
// I configure the layers elements
|
||||||
layerListEntry = layerList.firstElementChild;
|
layerListEntry = layerList.firstElementChild;
|
||||||
|
|
||||||
|
// Creating the first layer
|
||||||
currentLayer = new Layer(width, height, canvas, layerListEntry);
|
currentLayer = new Layer(width, height, canvas, layerListEntry);
|
||||||
currentLayer.canvas.style.zIndex = 2;
|
currentLayer.canvas.style.zIndex = 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// If it's not the first Pixel, I have to reset the app
|
||||||
|
|
||||||
|
// Deleting all the extra layers and canvases, leaving only one
|
||||||
let nLayers = layers.length;
|
let nLayers = layers.length;
|
||||||
for (let i=2; i < layers.length - nAppLayers; i++) {
|
for (let i=2; i < layers.length - nAppLayers; i++) {
|
||||||
let currentEntry = layers[i].menuEntry;
|
let currentEntry = layers[i].menuEntry;
|
||||||
@ -38,10 +54,9 @@ function newPixel (width, height, editorMode, fileContent = null) {
|
|||||||
// Setting up the current layer
|
// Setting up the current layer
|
||||||
layers[1] = new Layer(width, height, layers[1].canvas, layers[1].menuEntry);
|
layers[1] = new Layer(width, height, layers[1].canvas, layers[1].menuEntry);
|
||||||
currentLayer = layers[1];
|
currentLayer = layers[1];
|
||||||
|
|
||||||
currentLayer.canvas.style.zIndex = 2;
|
currentLayer.canvas.style.zIndex = 2;
|
||||||
|
|
||||||
// Updating canvas size
|
// Updating canvas size to the new size
|
||||||
for (let i=0; i<nLayers; i++) {
|
for (let i=0; i<nLayers; i++) {
|
||||||
layers[i].canvasSize = [width, height];
|
layers[i].canvasSize = [width, height];
|
||||||
}
|
}
|
||||||
@ -58,7 +73,7 @@ function newPixel (width, height, editorMode, fileContent = null) {
|
|||||||
|
|
||||||
// Pixel grid
|
// Pixel grid
|
||||||
pixelGrid = new Layer(width, height, pixelGridCanvas);
|
pixelGrid = new Layer(width, height, pixelGridCanvas);
|
||||||
|
// Setting the general canvasSize
|
||||||
canvasSize = currentLayer.canvasSize;
|
canvasSize = currentLayer.canvasSize;
|
||||||
|
|
||||||
if (firstPixel) {
|
if (firstPixel) {
|
||||||
@ -81,15 +96,18 @@ function newPixel (width, height, editorMode, fileContent = null) {
|
|||||||
|
|
||||||
//add colors from selected palette
|
//add colors from selected palette
|
||||||
var selectedPalette = getText('palette-button');
|
var selectedPalette = getText('palette-button');
|
||||||
|
|
||||||
|
// If the user selected a palette and isn't opening a file, I load the selected palette
|
||||||
if (selectedPalette != 'Choose a palette...' && fileContent == null) {
|
if (selectedPalette != 'Choose a palette...' && fileContent == null) {
|
||||||
|
|
||||||
//if this palette isnt the one specified in the url, then reset the url
|
//if this palette isnt the one specified in the url, then reset the url
|
||||||
if (!palettes[selectedPalette].specified)
|
if (!palettes[selectedPalette].specified)
|
||||||
history.pushState(null, null, '/pixel-editor/app');
|
history.pushState(null, null, '/pixel-editor/app');
|
||||||
|
|
||||||
//fill the palette with specified palette
|
//fill the palette with specified colours
|
||||||
createColorPalette(palettes[selectedPalette].colors,true);
|
createColorPalette(palettes[selectedPalette].colors,true);
|
||||||
}
|
}
|
||||||
|
// Otherwise, I just generate 2 semirandom colours
|
||||||
else if (fileContent == null) {
|
else if (fileContent == null) {
|
||||||
//this wasn't a specified palette, so reset the url
|
//this wasn't a specified palette, so reset the url
|
||||||
history.pushState(null, null, '/pixel-editor/app');
|
history.pushState(null, null, '/pixel-editor/app');
|
||||||
@ -120,15 +138,21 @@ function newPixel (width, height, editorMode, fileContent = null) {
|
|||||||
undoStates = [];
|
undoStates = [];
|
||||||
redoStates = [];
|
redoStates = [];
|
||||||
|
|
||||||
|
// Closing the "New Pixel dialogue"
|
||||||
closeDialogue();
|
closeDialogue();
|
||||||
|
// Updating the cursor of the current tool
|
||||||
currentTool.updateCursor();
|
currentTool.updateCursor();
|
||||||
|
|
||||||
|
// The user is now able to export the Pixel
|
||||||
document.getElementById('export-button').classList.remove('disabled');
|
document.getElementById('export-button').classList.remove('disabled');
|
||||||
documentCreated = true;
|
documentCreated = true;
|
||||||
|
|
||||||
|
// This is not the first Pixel anymore
|
||||||
firstPixel = false;
|
firstPixel = false;
|
||||||
|
|
||||||
|
// Now, if I opened a file
|
||||||
if (fileContent != null) {
|
if (fileContent != null) {
|
||||||
|
// I add every layer the file had in it
|
||||||
for (let i=0; i<fileContent['nLayers']; i++) {
|
for (let i=0; i<fileContent['nLayers']; i++) {
|
||||||
let layerData = fileContent['layer' + i];
|
let layerData = fileContent['layer' + i];
|
||||||
let layerImage = fileContent['layer' + i + 'ImageData'];
|
let layerImage = fileContent['layer' + i + 'ImageData'];
|
||||||
@ -166,6 +190,7 @@ function newPixel (width, height, editorMode, fileContent = null) {
|
|||||||
deleteLayer(false);
|
deleteLayer(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Applying the correct editor mode
|
||||||
if (pixelEditorMode == 'Basic') {
|
if (pixelEditorMode == 'Basic') {
|
||||||
switchMode('Advanced', false);
|
switchMode('Advanced', false);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
/***********MISCELLANEOUS UTILITY FUNCTIONS**************/
|
||||||
|
|
||||||
|
/** Merges topLayer onto belowLayer
|
||||||
|
*
|
||||||
|
* @param {*} belowLayer The layer on the bottom of the layer stack
|
||||||
|
* @param {*} topLayer The layer on the top of the layer stack
|
||||||
|
*/
|
||||||
function mergeLayers(belowLayer, topLayer) {
|
function mergeLayers(belowLayer, topLayer) {
|
||||||
// Copying the above content on the layerBelow
|
// Copying the above content on the layerBelow
|
||||||
let belowImageData = belowLayer.getImageData(0, 0, canvas.width, canvas.height);
|
let belowImageData = belowLayer.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
@ -24,10 +31,19 @@ function mergeLayers(belowLayer, topLayer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Putting the top data into the belowdata
|
||||||
belowLayer.putImageData(toMergeImageData, 0, 0);
|
belowLayer.putImageData(toMergeImageData, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Used to programmatically create an input event
|
||||||
|
*
|
||||||
|
* @param {*} keyCode KeyCode of the key to press
|
||||||
|
* @param {*} ctrl Is ctrl pressed?
|
||||||
|
* @param {*} alt Is alt pressed?
|
||||||
|
* @param {*} shift Is shift pressed?
|
||||||
|
*/
|
||||||
function simulateInput(keyCode, ctrl, alt, shift) {
|
function simulateInput(keyCode, ctrl, alt, shift) {
|
||||||
|
// I just copy pasted this from stack overflow lol please have mercy
|
||||||
let keyboardEvent = document.createEvent("KeyboardEvent");
|
let keyboardEvent = document.createEvent("KeyboardEvent");
|
||||||
let initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
|
let initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
|
||||||
|
|
||||||
@ -46,38 +62,62 @@ function simulateInput(keyCode, ctrl, alt, shift) {
|
|||||||
document.dispatchEvent(keyboardEvent);
|
document.dispatchEvent(keyboardEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Tells if a pixel is empty (has alpha = 0)
|
||||||
|
*
|
||||||
|
* @param {*} pixel
|
||||||
|
*/
|
||||||
function isPixelEmpty(pixel) {
|
function isPixelEmpty(pixel) {
|
||||||
if (pixel == null || pixel === undefined) {
|
if (pixel == null || pixel === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) || pixel[3] == 0) {
|
// If the alpha channel is 0, the current pixel is empty
|
||||||
|
if (pixel[3] == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Tells if element is a child of an element with class className
|
||||||
|
*
|
||||||
|
* @param {*} element
|
||||||
|
* @param {*} className
|
||||||
|
*/
|
||||||
function isChildOfByClass(element, className) {
|
function isChildOfByClass(element, className) {
|
||||||
|
// Getting the element with class className
|
||||||
while (element != null && element.classList != null && !element.classList.contains(className)) {
|
while (element != null && element.classList != null && !element.classList.contains(className)) {
|
||||||
element = element.parentElement;
|
element = element.parentElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If that element exists and its class is the correct one
|
||||||
if (element != null && element.classList != null && element.classList.contains(className)) {
|
if (element != null && element.classList != null && element.classList.contains(className)) {
|
||||||
|
// Then element is a chld of an element with class className
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the eyedropped colour (the colour of the pixel pointed by the cursor when the user is using the eyedropper).
|
||||||
|
* It takes the colour of the canvas with the biggest z-index, basically the one the user can see, since it doesn't
|
||||||
|
* make much sense to sample a colour which is hidden behind a different layer
|
||||||
|
*
|
||||||
|
* @param {*} cursorLocation The position of the cursor
|
||||||
|
*/
|
||||||
function getEyedropperColor(cursorLocation) {
|
function getEyedropperColor(cursorLocation) {
|
||||||
|
// Making sure max will take some kind of value
|
||||||
let max = -1;
|
let max = -1;
|
||||||
|
// Using tmpColour to sample the sprite
|
||||||
let tmpColour;
|
let tmpColour;
|
||||||
|
// Returned colour
|
||||||
let selectedColor;
|
let selectedColor;
|
||||||
|
|
||||||
for (let i=1; i<layers.length; i++) {
|
for (let i=1; i<layers.length; i++) {
|
||||||
|
// Getting the colour of the pixel in the cursorLocation
|
||||||
tmpColour = layers[i].context.getImageData(Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom),1,1).data;
|
tmpColour = layers[i].context.getImageData(Math.floor(cursorLocation[0]/zoom),Math.floor(cursorLocation[1]/zoom),1,1).data;
|
||||||
|
|
||||||
|
// If it's not empty, I check if it's on the top of the previous colour
|
||||||
if (layers[i].canvas.style.zIndex > max || isPixelEmpty(selectedColor) || selectedColor === undefined) {
|
if (layers[i].canvas.style.zIndex > max || isPixelEmpty(selectedColor) || selectedColor === undefined) {
|
||||||
max = layers[i].canvas.style.zIndex;
|
max = layers[i].canvas.style.zIndex;
|
||||||
|
|
||||||
@ -87,6 +127,7 @@ function getEyedropperColor(cursorLocation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the final colour was empty, I return black
|
||||||
if (isPixelEmpty(tmpColour) && selectedColor === undefined) {
|
if (isPixelEmpty(tmpColour) && selectedColor === undefined) {
|
||||||
selectedColor = [0, 0, 0];
|
selectedColor = [0, 0, 0];
|
||||||
}
|
}
|
||||||
@ -94,7 +135,12 @@ function getEyedropperColor(cursorLocation) {
|
|||||||
return selectedColor;
|
return selectedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the absolute position of the element (position on the screen)
|
||||||
|
*
|
||||||
|
* @param {*} element The element of which we have to get the position
|
||||||
|
*/
|
||||||
function getElementAbsolutePosition(element) {
|
function getElementAbsolutePosition(element) {
|
||||||
|
// Probably copy pasted this from stack overflow too, if not I don't recall how it works
|
||||||
let curleft = curtop = 0;
|
let curleft = curtop = 0;
|
||||||
|
|
||||||
if (element.offsetParent) {
|
if (element.offsetParent) {
|
||||||
@ -107,9 +153,15 @@ function getElementAbsolutePosition(element) {
|
|||||||
return [curleft,curtop];
|
return [curleft,curtop];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Nearest neighbor algorithm to scale a sprite
|
||||||
|
*
|
||||||
|
* @param {*} src The source imageData
|
||||||
|
* @param {*} dst The destination imageData
|
||||||
|
*/
|
||||||
function nearestNeighbor (src, dst) {
|
function nearestNeighbor (src, dst) {
|
||||||
let pos = 0
|
let pos = 0
|
||||||
|
|
||||||
|
// Just applying the nearest neighbor algorithm
|
||||||
for (let y = 0; y < dst.height; y++) {
|
for (let y = 0; y < dst.height; y++) {
|
||||||
for (let x = 0; x < dst.width; x++) {
|
for (let x = 0; x < dst.width; x++) {
|
||||||
const srcX = Math.floor(x * src.width / dst.width)
|
const srcX = Math.floor(x * src.width / dst.width)
|
||||||
@ -125,7 +177,14 @@ function nearestNeighbor (src, dst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Bilinear interpolation used to scale a sprite
|
||||||
|
*
|
||||||
|
* @param {*} src The source imageData
|
||||||
|
* @param {*} dst The destination imageData
|
||||||
|
*/
|
||||||
function bilinearInterpolation (src, dst) {
|
function bilinearInterpolation (src, dst) {
|
||||||
|
// Applying the bilinear interpolation algorithm
|
||||||
|
|
||||||
function interpolate (k, kMin, kMax, vMin, vMax) {
|
function interpolate (k, kMin, kMax, vMin, vMax) {
|
||||||
return Math.round((k - kMin) * vMax + (kMax - k) * vMin)
|
return Math.round((k - kMin) * vMax + (kMax - k) * vMin)
|
||||||
}
|
}
|
||||||
@ -167,14 +226,21 @@ function bilinearInterpolation (src, dst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resizes an imageData depending on the algorithm and on the new width and height
|
||||||
|
*
|
||||||
|
* @param {*} image The imageData to scale
|
||||||
|
* @param {*} width The new width of the imageData
|
||||||
|
* @param {*} height The new height of the imageData
|
||||||
|
* @param {*} algorithm Scaling algorithm chosen by the user in the dialogue
|
||||||
|
*/
|
||||||
function resizeImageData (image, width, height, algorithm) {
|
function resizeImageData (image, width, height, algorithm) {
|
||||||
algorithm = algorithm || 'bilinear-interpolation'
|
algorithm = algorithm || 'bilinear-interpolation'
|
||||||
|
|
||||||
let resize
|
let resize;
|
||||||
switch (algorithm) {
|
switch (algorithm) {
|
||||||
case 'nearest-neighbor': resize = nearestNeighbor; break
|
case 'nearest-neighbor': resize = nearestNeighbor; break
|
||||||
case 'bilinear-interpolation': resize = bilinearInterpolation; break
|
case 'bilinear-interpolation': resize = bilinearInterpolation; break
|
||||||
default: throw new Error(`Unknown algorithm: ${algorithm}`)
|
default: return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = new ImageData(width, height)
|
const result = new ImageData(width, height)
|
||||||
@ -184,6 +250,10 @@ function resizeImageData (image, width, height, algorithm) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the position in (x, y) format of the pixel with index "index"
|
||||||
|
*
|
||||||
|
* @param {*} index The index of the pixel of which we need the (x, y) position
|
||||||
|
*/
|
||||||
function getPixelPosition(index) {
|
function getPixelPosition(index) {
|
||||||
let linearIndex = index / 4;
|
let linearIndex = index / 4;
|
||||||
let x = linearIndex % layers[0].canvasSize[0];
|
let x = linearIndex % layers[0].canvasSize[0];
|
||||||
|
@ -83,7 +83,7 @@ on('click',"zoom-button", function(){
|
|||||||
//zoom in button
|
//zoom in button
|
||||||
on('click','zoom-in-button', function(){
|
on('click','zoom-in-button', function(){
|
||||||
//changeZoom('in',[window.innerWidth/2-canvas.offsetLeft,window.innerHeight/2-canvas.offsetTop]);
|
//changeZoom('in',[window.innerWidth/2-canvas.offsetLeft,window.innerHeight/2-canvas.offsetTop]);
|
||||||
changeZoom(layers[0],'in', [canvasSize[0] * zoom / 2, canvasSize[1] * zoom / 2]);
|
changeZoom('in', [canvasSize[0] * zoom / 2, canvasSize[1] * zoom / 2]);
|
||||||
|
|
||||||
for (let i=1; i<layers.length; i++) {
|
for (let i=1; i<layers.length; i++) {
|
||||||
layers[i].copyData(layers[0]);
|
layers[i].copyData(layers[0]);
|
||||||
@ -92,7 +92,7 @@ on('click','zoom-in-button', function(){
|
|||||||
|
|
||||||
//zoom out button
|
//zoom out button
|
||||||
on('click','zoom-out-button', function(){
|
on('click','zoom-out-button', function(){
|
||||||
changeZoom(layers[0],'out',[canvasSize[0]*zoom/2,canvasSize[1]*zoom/2]);
|
changeZoom('out',[canvasSize[0]*zoom/2,canvasSize[1]*zoom/2]);
|
||||||
|
|
||||||
for (let i=1; i<layers.length; i++) {
|
for (let i=1; i<layers.length; i++) {
|
||||||
layers[i].copyData(layers[0]);
|
layers[i].copyData(layers[0]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user