mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Started project opening
Fixed a bug in the flatten visible undo, created an array to store the colours in the current palette, implemented project saving.
This commit is contained in:
parent
0b5bb3ab1a
commit
2868363bb7
@ -12,11 +12,11 @@ The next version is mostly focused on adding missing essential features and port
|
|||||||
|
|
||||||
Suggestions / Planned features:
|
Suggestions / Planned features:
|
||||||
|
|
||||||
- Save project while keeping layer data
|
|
||||||
- Line tool
|
- Line tool
|
||||||
- Resize canvas
|
- Resize canvas
|
||||||
- Snap brush preview to pixel grid
|
- Snap brush preview to pixel grid
|
||||||
- Move selection with arrows
|
- Move selection with arrows
|
||||||
|
- Load palette from LPE file
|
||||||
|
|
||||||
- Custom color picker
|
- Custom color picker
|
||||||
- custom code without dependencies
|
- custom code without dependencies
|
||||||
@ -36,7 +36,7 @@ Suggestions / Planned features:
|
|||||||
- Another currentLayer.canvas
|
- Another currentLayer.canvas
|
||||||
- Must be rescaled each zoom
|
- Must be rescaled each zoom
|
||||||
|
|
||||||
- Possibly add collaborate function using together.js
|
- Possibly add collaborate function
|
||||||
- Bug fix
|
- Bug fix
|
||||||
- Alt + scroll broken
|
- Alt + scroll broken
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
let currentPalette = [];
|
||||||
|
|
||||||
//adds the given color to the palette
|
//adds the given color to the palette
|
||||||
//input hex color string
|
//input hex color string
|
||||||
//returns list item element
|
//returns list item element
|
||||||
@ -6,7 +8,7 @@ function addColor (newColor) {
|
|||||||
//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);
|
||||||
//create list item
|
//create list item
|
||||||
var listItem = document.createElement('li');
|
var listItem = document.createElement('li');
|
||||||
|
|
||||||
@ -45,5 +47,7 @@ function addColor (newColor) {
|
|||||||
button.parentElement.firstChild.jscolor.show();
|
button.parentElement.firstChild.jscolor.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(currentPalette);
|
||||||
|
|
||||||
return listItem;
|
return listItem;
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,11 @@ function colorChanged(e) {
|
|||||||
var newColor = hexToRgb(e.target.value);
|
var newColor = hexToRgb(e.target.value);
|
||||||
var oldColor = e.target.oldColor;
|
var oldColor = e.target.oldColor;
|
||||||
|
|
||||||
|
currentPalette.splice(currentPalette.indexOf("#" + newColor), 1);
|
||||||
|
|
||||||
newColor.a = 255;
|
newColor.a = 255;
|
||||||
|
|
||||||
//save undo state
|
//save undo state
|
||||||
//saveHistoryState({type: 'colorchange', newColor: e.target.value, oldColor: rgbToHex(oldColor), canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])});
|
|
||||||
new HistoryStateEditColor(e.target.value.toLowerCase(), rgbToHex(oldColor));
|
new HistoryStateEditColor(e.target.value.toLowerCase(), rgbToHex(oldColor));
|
||||||
|
|
||||||
//get the currently selected color
|
//get the currently selected color
|
||||||
@ -82,7 +83,7 @@ function colorChanged(e) {
|
|||||||
|
|
||||||
//set new old color to changed color
|
//set new old color to changed color
|
||||||
e.target.oldColor = newColor;
|
e.target.oldColor = newColor;
|
||||||
|
currentPalette.push('#' + newColorHex);
|
||||||
|
|
||||||
//if this is the current color, update the drawing color
|
//if this is the current color, update the drawing color
|
||||||
if (e.target.colorElement.parentElement.classList.contains('selected')) {
|
if (e.target.colorElement.parentElement.classList.contains('selected')) {
|
||||||
|
@ -34,12 +34,6 @@ function createColorPalette(selectedPalette, fillBackground) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//fill bg with lightest color
|
|
||||||
if (fillBackground) {
|
|
||||||
currentLayer.context.fillStyle = lightestColor;
|
|
||||||
currentLayer.context.fillRect(0, 0, canvasSize[0], canvasSize[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//set as current color
|
//set as current color
|
||||||
currentLayer.context.fillStyle = darkestColor;
|
currentLayer.context.fillStyle = darkestColor;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,29 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
//File Menu
|
//File Menu
|
||||||
case 'New':
|
case 'New':
|
||||||
showDialogue('new-pixel');
|
showDialogue('new-pixel');
|
||||||
|
break;
|
||||||
|
case 'Save project':
|
||||||
|
//create name
|
||||||
|
var selectedPalette = getText('palette-button');
|
||||||
|
if (selectedPalette != 'Choose a palette...'){
|
||||||
|
var paletteAbbreviation = palettes[selectedPalette].abbreviation;
|
||||||
|
var fileName = 'pixel-'+paletteAbbreviation+'-'+canvasSize[0]+'x'+canvasSize[1]+'.lpe';
|
||||||
|
} else {
|
||||||
|
var fileName = 'pixel-'+canvasSize[0]+'x'+canvasSize[1]+'.lpe';
|
||||||
|
selectedPalette = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
//set download link
|
||||||
|
var linkHolder = document.getElementById('save-project-link-holder');
|
||||||
|
// create file content
|
||||||
|
var content = getProjectData();
|
||||||
|
|
||||||
|
linkHolder.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(content);
|
||||||
|
linkHolder.download = fileName;
|
||||||
|
linkHolder.click();
|
||||||
|
|
||||||
|
ga('send', 'event', 'Pixel Editor Save', selectedPalette, canvasSize[0]+'/'+canvasSize[1]); /*global ga*/
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'Open':
|
case 'Open':
|
||||||
//if a document exists
|
//if a document exists
|
||||||
@ -48,9 +71,8 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Save as...':
|
case 'Export':
|
||||||
if (documentCreated) {
|
if (documentCreated) {
|
||||||
|
|
||||||
//create name
|
//create name
|
||||||
var selectedPalette = getText('palette-button');
|
var selectedPalette = getText('palette-button');
|
||||||
if (selectedPalette != 'Choose a palette...'){
|
if (selectedPalette != 'Choose a palette...'){
|
||||||
@ -66,7 +88,7 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
// Creating a tmp canvas to flatten everything
|
// Creating a tmp canvas to flatten everything
|
||||||
var exportCanvas = document.createElement("canvas");
|
var exportCanvas = document.createElement("canvas");
|
||||||
var emptyCanvas = document.createElement("canvas");
|
var emptyCanvas = document.createElement("canvas");
|
||||||
var layersCopy = layers.slice();;
|
var layersCopy = layers.slice();
|
||||||
|
|
||||||
exportCanvas.width = canvasSize[0];
|
exportCanvas.width = canvasSize[0];
|
||||||
exportCanvas.height = canvasSize[1];
|
exportCanvas.height = canvasSize[1];
|
||||||
@ -75,7 +97,7 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
emptyCanvas.height = canvasSize[1];
|
emptyCanvas.height = canvasSize[1];
|
||||||
|
|
||||||
// Sorting the layers by z index
|
// Sorting the layers by z index
|
||||||
layersCopy.sort((a, b) => (a.canvas.zIndex > b.canvas.zIndex) ? 1 : -1);
|
layersCopy.sort((a, b) => (a.canvas.style.zIndex > b.canvas.style.zIndex) ? 1 : -1);
|
||||||
|
|
||||||
// Merging every layer on the export canvas
|
// Merging every layer on the export canvas
|
||||||
for (let i=0; i<layersCopy.length; i++) {
|
for (let i=0; i<layersCopy.length; i++) {
|
||||||
@ -100,7 +122,7 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
exportCanvas.remove();
|
exportCanvas.remove();
|
||||||
|
|
||||||
//track google event
|
//track google event
|
||||||
ga('send', 'event', 'Pixel Editor Save', selectedPalette, canvasSize[0]+'/'+canvasSize[1]); /*global ga*/
|
ga('send', 'event', 'Pixel Editor Export', selectedPalette, canvasSize[0]+'/'+canvasSize[1]); /*global ga*/
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -149,7 +171,6 @@ for (var i = 1; i < mainMenuItems.length; i++) {
|
|||||||
break;
|
break;
|
||||||
//Help Menu
|
//Help Menu
|
||||||
case 'Settings':
|
case 'Settings':
|
||||||
|
|
||||||
//fill form with current settings values
|
//fill form with current settings values
|
||||||
setValue('setting-numberOfHistoryStates', settings.numberOfHistoryStates);
|
setValue('setting-numberOfHistoryStates', settings.numberOfHistoryStates);
|
||||||
|
|
||||||
@ -178,3 +199,27 @@ function closeMenu () {
|
|||||||
deselect(mainMenuItems[i]);
|
deselect(mainMenuItems[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getProjectData() {
|
||||||
|
// use a dictionary
|
||||||
|
let dictionary = [];
|
||||||
|
// store canvas size
|
||||||
|
dictionary.push({key: "canvasWidth", value: currentLayer.canvasSize[0]});
|
||||||
|
dictionary.push({key: "canvasHeight", value: currentLayer.canvasSize[1]});
|
||||||
|
// store palette
|
||||||
|
for (let i=0; i<currentPalette.length; i++) {
|
||||||
|
dictionary.push({key: "color" + i, value: currentPalette[i]});
|
||||||
|
}
|
||||||
|
// store layers
|
||||||
|
for (let i=0; i<layers.length; i++) {
|
||||||
|
// Only saving the layers the user has access to (no vfx, tmp or checkerboard layers)
|
||||||
|
if (layers[i].menuEntry != null) {
|
||||||
|
dictionary.push({key: "layer" + i, value: layers[i]});
|
||||||
|
dictionary.push({key: "layer" + i + "ImageData",
|
||||||
|
value: layers[i].canvas.toDataURL()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(dictionary);
|
||||||
|
}
|
@ -25,20 +25,15 @@ function HistoryStateFlattenVisible(flattened) {
|
|||||||
saveHistoryState(this);
|
saveHistoryState(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
function HistoryStateFlattenTwoVisibles(belowImageData, beforeAbove, layerIndex, aboveLayer, belowLayer) {
|
function HistoryStateFlattenTwoVisibles(belowImageData, afterAbove, layerIndex, aboveLayer, belowLayer) {
|
||||||
this.aboveLayer = aboveLayer;
|
this.aboveLayer = aboveLayer;
|
||||||
this.belowLayer = belowLayer;
|
this.belowLayer = belowLayer;
|
||||||
this.belowImageData = belowImageData;
|
this.belowImageData = belowImageData;
|
||||||
|
|
||||||
this.undo = function() {
|
this.undo = function() {
|
||||||
// SCEMOOOO DEVI METTERCI PURE I PIXELSSSS
|
console.log(afterAbove.menuEntry);
|
||||||
canvasView.append(aboveLayer.canvas);
|
canvasView.append(aboveLayer.canvas);
|
||||||
if (beforeAbove != null) {
|
layerList.insertBefore(aboveLayer.menuEntry, afterAbove);
|
||||||
layerList.insertBefore(aboveLayer.menuEntry, beforeAbove.menuEntry);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
layerList.prepend(aboveLayer.menuEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
belowLayer.context.clearRect(0, 0, belowLayer.canvasSize[0], belowLayer.canvasSize[1]);
|
belowLayer.context.clearRect(0, 0, belowLayer.canvasSize[0], belowLayer.canvasSize[1]);
|
||||||
belowLayer.context.putImageData(this.belowImageData, 0, 0);
|
belowLayer.context.putImageData(this.belowImageData, 0, 0);
|
||||||
|
12
js/_layer.js
12
js/_layer.js
@ -55,6 +55,7 @@ class Layer {
|
|||||||
this.id = "layer" + id;
|
this.id = "layer" + id;
|
||||||
|
|
||||||
if (menuEntry != null) {
|
if (menuEntry != null) {
|
||||||
|
this.name = menuEntry.getElementsByTagName("p")[0].innerHTML;
|
||||||
menuEntry.id = "layer" + id;
|
menuEntry.id = "layer" + id;
|
||||||
menuEntry.onclick = () => this.selectLayer();
|
menuEntry.onclick = () => this.selectLayer();
|
||||||
menuEntry.getElementsByTagName("button")[0].onclick = () => this.toggleLock();
|
menuEntry.getElementsByTagName("button")[0].onclick = () => this.toggleLock();
|
||||||
@ -195,7 +196,10 @@ class Layer {
|
|||||||
isRenamingLayer = false;
|
isRenamingLayer = false;
|
||||||
|
|
||||||
if (oldLayerName != null) {
|
if (oldLayerName != null) {
|
||||||
new HistoryStateRenameLayer(oldLayerName, this.menuEntry.getElementsByTagName("p")[0].innerHTML, currentLayer);
|
let name = this.menuEntry.getElementsByTagName("p")[0].innerHTML;
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
|
new HistoryStateRenameLayer(oldLayerName, name, currentLayer);
|
||||||
oldLayerName = null;
|
oldLayerName = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,16 +337,17 @@ function flatten(onlyVisible) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sorting them by z-index
|
// Sorting them by z-index
|
||||||
visibleLayers.sort((a, b) => (a.canvas.zIndex > b.canvas.zIndex) ? -1 : 1);
|
visibleLayers.sort((a, b) => (a.canvas.style.zIndex > b.canvas.style.zIndex) ? -1 : 1);
|
||||||
// Selecting the last visible layer (the only one that won't get deleted)
|
// Selecting the last visible layer (the only one that won't get deleted)
|
||||||
visibleLayers[visibleLayers.length - 1].selectLayer();
|
visibleLayers[visibleLayers.length - 1].selectLayer();
|
||||||
|
|
||||||
// Merging all the layer but the last one
|
// Merging all the layer but the last one
|
||||||
for (let i=0; i<visibleLayers.length - 1; i++) {
|
for (let i=0; i<visibleLayers.length - 1; i++) {
|
||||||
nToFlatten++;
|
nToFlatten++;
|
||||||
|
console.log(visibleLayers[i].menuEntry.nextElementSibling);
|
||||||
new HistoryStateFlattenTwoVisibles(
|
new HistoryStateFlattenTwoVisibles(
|
||||||
visibleLayers[i + 1].context.getImageData(0, 0, visibleLayers[i].canvasSize[0], visibleLayers[i].canvasSize[1]),
|
visibleLayers[i + 1].context.getImageData(0, 0, visibleLayers[i].canvasSize[0], visibleLayers[i].canvasSize[1]),
|
||||||
visibleLayers[i].menuEntry.previousElementSibling,
|
visibleLayers[i].menuEntry.nextElementSibling,
|
||||||
layers.indexOf(visibleLayers[i]),
|
layers.indexOf(visibleLayers[i]),
|
||||||
visibleLayers[i], visibleLayers[i + 1]
|
visibleLayers[i], visibleLayers[i + 1]
|
||||||
);
|
);
|
||||||
@ -572,7 +577,6 @@ function addLayer(id, saveHistory = true) {
|
|||||||
layerList.insertBefore(toAppend, layerList.childNodes[0]);
|
layerList.insertBefore(toAppend, layerList.childNodes[0]);
|
||||||
|
|
||||||
if (id != null && typeof(id) == "string") {
|
if (id != null && typeof(id) == "string") {
|
||||||
console.log("imposto");
|
|
||||||
newLayer.setID(id);
|
newLayer.setID(id);
|
||||||
}
|
}
|
||||||
// Basically "if I'm not adding a layer because redo() is telling meto do so", then I can save the history
|
// Basically "if I'm not adding a layer because redo() is telling meto do so", then I can save the history
|
||||||
|
@ -3,8 +3,13 @@ document.getElementById('open-image-browse-holder').addEventListener('change', f
|
|||||||
|
|
||||||
//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') {
|
console.log("File: " + fileContentType);
|
||||||
|
|
||||||
|
if (fileContentType == 'image/png' || fileContentType == 'image/gif' || fileContentType == '.lpe') {
|
||||||
|
if (fileContentType == '.lpe') {
|
||||||
|
console.log("OK");
|
||||||
|
}
|
||||||
|
else {
|
||||||
//load file
|
//load file
|
||||||
var fileReader = new FileReader();
|
var fileReader = new FileReader();
|
||||||
fileReader.onload = function(e) {
|
fileReader.onload = function(e) {
|
||||||
@ -56,6 +61,7 @@ document.getElementById('open-image-browse-holder').addEventListener('change', f
|
|||||||
};
|
};
|
||||||
fileReader.readAsDataURL(this.files[0]);
|
fileReader.readAsDataURL(this.files[0]);
|
||||||
}
|
}
|
||||||
else alert('Only PNG and GIF files are allowed at this time.');
|
}
|
||||||
|
else alert('Only .lpe project files, PNG and GIF files are allowed at this time.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
let firstPixel = true;
|
let firstPixel = true;
|
||||||
|
|
||||||
function newPixel (width, height, palette) {
|
function newPixel (width, height, palette) {
|
||||||
|
currentPalette = [];
|
||||||
if (firstPixel) {
|
if (firstPixel) {
|
||||||
layerList = document.getElementById("layers-menu");
|
layerList = document.getElementById("layers-menu");
|
||||||
layerListEntry = layerList.firstElementChild;
|
layerListEntry = layerList.firstElementChild;
|
||||||
@ -115,7 +116,7 @@ function newPixel (width, height, palette) {
|
|||||||
closeDialogue();
|
closeDialogue();
|
||||||
currentTool.updateCursor();
|
currentTool.updateCursor();
|
||||||
|
|
||||||
document.getElementById('save-as-button').classList.remove('disabled');
|
document.getElementById('export-button').classList.remove('disabled');
|
||||||
documentCreated = true;
|
documentCreated = true;
|
||||||
|
|
||||||
firstPixel = false;
|
firstPixel = false;
|
||||||
|
@ -43,8 +43,9 @@
|
|||||||
<button>File</button>
|
<button>File</button>
|
||||||
<ul>
|
<ul>
|
||||||
<li><button>New</button></li>
|
<li><button>New</button></li>
|
||||||
|
<li><button>Save project</button></li>
|
||||||
<li><button>Open</button></li>
|
<li><button>Open</button></li>
|
||||||
<li><button id="save-as-button" class="disabled">Save as...</button></li>
|
<li><button id="export-button" class="disabled">Export</button></li>
|
||||||
<li><a href="/pixel-editor">Exit</a></li>
|
<li><a href="/pixel-editor">Exit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@ -149,8 +150,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Layer 0
|
<p>Layer 0<div class = "gradient"></div></p>
|
||||||
<div class = "gradient"></div></p>
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
@ -158,6 +158,7 @@
|
|||||||
{{svg "plus.svg" width="20" height="20"}} Add layer
|
{{svg "plus.svg" width="20" height="20"}} Add layer
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<ul id = "layer-properties-menu">
|
<ul id = "layer-properties-menu">
|
||||||
<li>
|
<li>
|
||||||
@ -176,7 +177,6 @@
|
|||||||
<button onclick = "flatten(false)">Flatten all</button>
|
<button onclick = "flatten(false)">Flatten all</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div id="eyedropper-preview"></div>
|
<div id="eyedropper-preview"></div>
|
||||||
<div id="brush-preview"></div>
|
<div id="brush-preview"></div>
|
||||||
@ -192,7 +192,8 @@
|
|||||||
|
|
||||||
<div id="data-holders">
|
<div id="data-holders">
|
||||||
<a id="save-image-link-holder" href="#">dl</a>
|
<a id="save-image-link-holder" href="#">dl</a>
|
||||||
<input id="open-image-browse-holder" type="file" accept="image/png, image/gif"/>
|
<a id="save-project-link-holder" href="#">dl</a>
|
||||||
|
<input id="open-image-browse-holder" type="file" accept="image/png, image/gif, .lpe"/>
|
||||||
<input id="load-palette-browse-holder" type="file" accept="image/png, image/gif"/>
|
<input id="load-palette-browse-holder" type="file" accept="image/png, image/gif"/>
|
||||||
<canvas id="load-palette-canvas-holder"></canvas>
|
<canvas id="load-palette-canvas-holder"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user