Added ability to select import position

This commit is contained in:
NSSure 2022-10-22 05:46:48 -04:00
parent eb139ef8e7
commit b8d1f11f93
5 changed files with 204 additions and 16 deletions

View File

@ -1,12 +1,17 @@
#import-image { #import-image {
ul {
list-style-type: none;
margin: 15px 0;
padding: 0;
}
.import-image-file { .import-image-file {
button { button {
margin: 0; margin: 0;
} }
} }
.import-image-checkbox { .import-image-location-pivot {
height: 50px;
display: flex; display: flex;
align-items: center; align-items: center;
} }

View File

@ -197,6 +197,7 @@ const ColorModule = (() => {
//add # at beginning if not present //add # at beginning if not present
if (newColor.charAt(0) != '#') if (newColor.charAt(0) != '#')
newColor = '#' + newColor; newColor = '#' + newColor;
currentPalette.push(newColor); currentPalette.push(newColor);
//create list item //create list item
const listItem = document.createElement('li'); const listItem = document.createElement('li');
@ -388,18 +389,69 @@ const ColorModule = (() => {
* *
*/ */
function createPaletteFromLayers() { function createPaletteFromLayers() {
//create array out of colors object
let colorPaletteArray = getLayerColors();
//create palette from colors array
createColorPalette(colorPaletteArray);
}
/**
* Scan the layers for any colors that are not currently in the palette. If any colors
* are found they should be added as new colors for the palette.
*/
function updatePaletteFromLayers() {
let layersPaletteArray = getLayerColors();
for (let i = 0; i < layersPaletteArray.length; i++) {
if (currentPalette.indexOf(layersPaletteArray[i]) !== -1) {
continue;
}
addColor(layersPaletteArray[i]);
}
return;
// Compare the current layer colors to the current palette and add any layer colors that aren't in the palette.
let mergedPalette = [...currentPalette];
for (let i = 0; i < layersPaletteArray.length; i++) {
let isNewPaletteColor = true;
for (let j = 0; j < currentPalette.length; j++) {
// If the layer color matches an existing palette color skip it so it isn't added again.
if (layersPaletteArray[i] === mergedPalette[j]) {
isNewPaletteColor = false;
break;
}
}
if (isNewPaletteColor) {
mergedPalette.push(layersPaletteArray[i]);
}
}
// Recreate the palette using the merged colors array.
createColorPalette(mergedPalette);
}
/**
* Iterates each layer and grab each unique color.
* @returns Array of colors used within the current layers.
*/
function getLayerColors() {
let colors = {}; let colors = {};
let nColors = 0; let nColors = 0;
//create array out of colors object //create array out of colors object
let colorPaletteArray = []; let colorPaletteArray = [];
for (let i=0; i<currFile.layers.length; i++) { for (let i = 0; i < currFile.layers.length; i++) {
if (currFile.layers[i].hasCanvas()) { if (currFile.layers[i].hasCanvas()) {
let imageData = currFile.layers[i].context.getImageData( let imageData = currFile.layers[i].context.getImageData(0, 0, currFile.canvasSize[0], currFile.canvasSize[1]).data;
0, 0, currFile.canvasSize[0], currFile.canvasSize[1]).data;
let dataLength = imageData.length; let dataLength = imageData.length;
for (let j=0; j<dataLength; j += 4) { for (let j=0; j < dataLength; j += 4) {
if (!Util.isPixelEmpty(imageData[j])) { if (!Util.isPixelEmpty(imageData[j])) {
let color = imageData[j]+','+imageData[j + 1]+','+imageData[j + 2]; let color = imageData[j]+','+imageData[j + 1]+','+imageData[j + 2];
@ -407,6 +459,7 @@ const ColorModule = (() => {
colorPaletteArray.push('#' + new Color("rgb", imageData[j], imageData[j + 1], imageData[j + 2]).hex); colorPaletteArray.push('#' + new Color("rgb", imageData[j], imageData[j + 1], imageData[j + 2]).hex);
colors[color] = new Color("rgb", imageData[j], imageData[j + 1], imageData[j + 2]).rgb; colors[color] = new Color("rgb", imageData[j], imageData[j + 1], imageData[j + 2]).rgb;
nColors++; nColors++;
//don't allow more than 256 colors to be added //don't allow more than 256 colors to be added
if (nColors >= Settings.getCurrSettings().maxColorsOnImportedImage) { if (nColors >= Settings.getCurrSettings().maxColorsOnImportedImage) {
alert('The image loaded seems to have more than '+Settings.getCurrSettings().maxColorsOnImportedImage+' colors.'); alert('The image loaded seems to have more than '+Settings.getCurrSettings().maxColorsOnImportedImage+' colors.');
@ -418,10 +471,7 @@ const ColorModule = (() => {
} }
} }
//create palette from colors array return colorPaletteArray;
createColorPalette(colorPaletteArray);
console.log("Done 2");
} }
function updateCurrentColor(color, refLayer) { function updateCurrentColor(color, refLayer) {
@ -446,6 +496,7 @@ const ColorModule = (() => {
resetPalette, resetPalette,
createColorPalette, createColorPalette,
createPaletteFromLayers, createPaletteFromLayers,
updatePaletteFromLayers,
updateCurrentColor, updateCurrentColor,
} }
})(); })();

View File

@ -272,6 +272,10 @@ const FileManager = (() => {
browsePaletteHolder.value = null; browsePaletteHolder.value = null;
} }
currentImportPivotElement = undefined;
currentImportPivotPosition = 'middle';
isImportWindowInitialized = false;
/** /**
* Displays the import image window to allow for configurations * Displays the import image window to allow for configurations
* to be made be the image is imported. * to be made be the image is imported.
@ -279,11 +283,25 @@ const FileManager = (() => {
function openImportImageWindow() { function openImportImageWindow() {
// Reset window values. // Reset window values.
importImageHolder.value = null; importImageHolder.value = null;
document.getElementById('import-image-match-size').checked = false; document.getElementById('import-image-match-size').checked = false;
document.getElementById('import-image-update-palette').checked = false;
document.getElementById('import-image-name').innerText = ""; document.getElementById('import-image-name').innerText = "";
// Workaround to prevent events from firing twice for the import window.
if (!this.isImportWindowInitialized) {
// Getting the pivot buttons and setting the default pivot selection.
let pivotButtons = document.getElementsByClassName("pivot-button");
this.currentImportPivotElement = document.querySelector('.import-image-location-pivot .rc-selected-pivot');
// Add event handlers for each pivot.
for (let i=0; i < pivotButtons.length; i++) {
Events.on("click", pivotButtons[i], onImportPivotChanged.bind(this));
}
Events.on("click", "select-image", () => document.getElementById('import-image-browse-holder')?.click()); Events.on("click", "select-image", () => document.getElementById('import-image-browse-holder')?.click());
Events.on("click", "import-image-confirm", importImage); Events.on("click", "import-image-confirm", importImage);
}
Dialogue.showDialogue('import-image', false); Dialogue.showDialogue('import-image', false);
} }
@ -301,17 +319,25 @@ const FileManager = (() => {
var fileReader = new FileReader(); var fileReader = new FileReader();
// Once the image has been loaded draw the image to the current layer at the top right. // Once the image has been loaded draw the image to the current layer at the top right.
fileReader.onload = function(e) { fileReader.onload = (e) => {
var img = new Image(); var img = new Image();
img.onload = () => { img.onload = () => {
let shouldResizeCanvas = document.getElementById('import-image-match-size').checked; let shouldResizeCanvas = document.getElementById('import-image-match-size').checked;
let shouldImportColors = document.getElementById('import-image-update-palette').checked;
// Resize the canvas to the image size if the flag was set to true. // Resize the canvas to the image size if the flag was set to true.
if (shouldResizeCanvas) { if (shouldResizeCanvas) {
currFile.resizeCanvas(null, { x: img.width, y: img.height }, null, false); currFile.resizeCanvas(null, { x: img.width, y: img.height }, null, false);
} }
currFile.currentLayer.context.drawImage(img, 0, 0) // Calculate pivot offset and draw the imported image. Ensure the pivot position accounts for the imported images dimensions.
let offset = Util.getPivotPosition(this.currentImportPivotPosition, currFile.canvasSize[0], currFile.canvasSize[1], img.width, img.height);
currFile.currentLayer.context.drawImage(img, offset.x, offset.y);
if (shouldImportColors) {
ColorModule.updatePaletteFromLayers();
}
Dialogue.closeDialogue(); Dialogue.closeDialogue();
}; };
@ -340,6 +366,19 @@ const FileManager = (() => {
} }
} }
/**
* Called when the selected pivot for the import image is changed.
* @param {*} event The event for the selected pivot.
*/
function onImportPivotChanged(event) {
this.currentImportPivotPosition = event.target.getAttribute("value");
// Setting the selected class
this.currentImportPivotElement.classList.remove("rc-selected-pivot");
this.currentImportPivotElement = event.target;
this.currentImportPivotElement.classList.add("rc-selected-pivot");
}
return { return {
saveProject, saveProject,
exportProject, exportProject,

View File

@ -134,4 +134,73 @@ class Util {
static getFileExtension(fileName) { static getFileExtension(fileName) {
return (fileName.substring(fileName.lastIndexOf('.')+1, fileName.length) || fileName).toLowerCase(); return (fileName.substring(fileName.lastIndexOf('.')+1, fileName.length) || fileName).toLowerCase();
} }
static getCanvasBorders() {
}
/**
* Determines the x and y offset for drawing images at a specific point 'topleft', 'middle', etc.
*
* @param {*} pivot A string representing the position of the pivot 'topleft', 'middle', etc.
* @param {*} width Width of the bounds often represents the canvas width.
* @param {*} height Height of the bounds often represents the canvas height.
* @param {*} imageWidth Substracts the offset from calculated x position of the pivot. Defaults to 0.
* @param {*} imageHeight Subtracts the offset from the calculated y position of the pivot. Defaults to 0.
*
* @returns Object containing the x and y offset for the pivot.
*/
static getPivotPosition(pivot, width, height, imageWidth = 0, imageHeight = 0) {
let position = {
x: 0,
y: 0
};
let centerX = width / 2;
let centerY = height / 2;
switch (pivot)
{
case 'topleft':
position.x = 0;
position.y = 0;
break;
case 'top':
position.x = centerX - (imageWidth / 2);
position.y = 0;
break;
case 'topright':
position.x = width - imageWidth;
position.y = 0;
break;
case 'left':
position.x = 0;
position.y = centerY - (imageHeight / 2);
break;
case 'middle':
position.x = centerX - (imageWidth / 2);
position.y = centerY - (imageHeight / 2);
break;
case 'right':
position.x = width - imageWidth;
position.y = centerY - (imageHeight / 2);
break;
case 'bottomleft':
position.x = 0;
position.y = height - imageHeight;
break;
case 'bottom':
position.x = centerX - (imageWidth / 2);
position.y = height - imageHeight;
break;
case 'bottomright':
position.x = width - imageWidth
position.y = height - imageHeight;
break;
default:
break;
}
return position;
}
} }

View File

@ -10,8 +10,32 @@
<span id="import-image-name"></span> <span id="import-image-name"></span>
</div> </div>
<div class="import-image-checkbox"> <ul role="group">
<span>Match canvas to image size <input type="checkbox" id="import-image-match-size"/></span> <li>
<span><input type="checkbox" id="import-image-match-size"/> Match canvas to image size</span>
</li>
<li>
<span><input type="checkbox" id="import-image-update-palette"/> Append palette with image colors</span>
</li>
</ul>
<h2>Canvas Location</h2>
<p>If matching to image size canvas location is ignored.</p>
<!--PIVOTS-->
<div class="import-image-location-pivot">
<span id = "pivot-menu">
<button class="pivot-button" value="topleft">{{svg "arrows/topleft.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="top">{{svg "arrows/top.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="topright">{{svg "arrows/topright.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="left">{{svg "arrows/left.svg" width="20" height="20"}}</button>
<button class="pivot-button rc-selected-pivot" value="middle">{{svg "arrows/middle.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="right">{{svg "arrows/right.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="bottomleft">{{svg "arrows/bottomleft.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="bottom">{{svg "arrows/bottom.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="bottomright">{{svg "arrows/bottomright.svg" width="20" height="20"}}</button>
</span>
</div> </div>
<div class="popup-actions"> <div class="popup-actions">