mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Added basic structure and comments for Tools
Fixed lpe palette loading, added custom events
This commit is contained in:
parent
a930fabcba
commit
0fcb309cc7
@ -4,6 +4,10 @@ This is a browser based software for creating pixel art
|
|||||||
|
|
||||||
The tool can be viewed online here: https://lospec.com/pixel-editor
|
The tool can be viewed online here: https://lospec.com/pixel-editor
|
||||||
|
|
||||||
|
## How to contribute
|
||||||
|
|
||||||
|
Please do not submit pull requests with new features or core changes. Instead, please file an issue first for discussion.
|
||||||
|
|
||||||
## What to Contribute
|
## What to Contribute
|
||||||
|
|
||||||
Any changes that fix bugs or add features are welcome.
|
Any changes that fix bugs or add features are welcome.
|
||||||
@ -15,10 +19,9 @@ Suggestions / Planned features:
|
|||||||
- Documentation
|
- Documentation
|
||||||
|
|
||||||
- Possibility to hide and resize menus (layers, palette)
|
- Possibility to hide and resize menus (layers, palette)
|
||||||
- Line tool
|
|
||||||
- Tiled mode
|
- Tiled mode
|
||||||
- Load palette from LPE file
|
- Load palette from LPE file
|
||||||
- Symmetry options
|
- Symmetry options (currently being worked on)
|
||||||
|
|
||||||
- Mobile
|
- Mobile
|
||||||
- Touch equivalent for mouse clicks
|
- Touch equivalent for mouse clicks
|
||||||
|
@ -69,6 +69,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#brush-preview {
|
#brush-preview {
|
||||||
|
background-color:black;
|
||||||
|
opacity:0.3;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: solid 1px #fff;
|
border: solid 1px #fff;
|
||||||
z-index: 1200;
|
z-index: 1200;
|
||||||
|
@ -98,8 +98,7 @@ const ColorModule = (() => {
|
|||||||
//left clicked color
|
//left clicked color
|
||||||
if (e.which == 1) {
|
if (e.which == 1) {
|
||||||
// remove current color selection
|
// remove current color selection
|
||||||
var selectedColor = document.querySelector('#colors-menu li.selected');
|
document.querySelector('#colors-menu li.selected')?.classList.remove('selected');
|
||||||
if (selectedColor) selectedColor.classList.remove('selected');
|
|
||||||
|
|
||||||
//set current color
|
//set current color
|
||||||
updateCurrentColor(e.target.style.backgroundColor);
|
updateCurrentColor(e.target.style.backgroundColor);
|
||||||
@ -125,7 +124,7 @@ const ColorModule = (() => {
|
|||||||
const newColor = new Color("hsv", Math.floor(Math.random()*360), Math.floor(Math.random()*100), Math.floor(Math.random()*100)).hex;
|
const newColor = new Color("hsv", Math.floor(Math.random()*360), Math.floor(Math.random()*100), Math.floor(Math.random()*100)).hex;
|
||||||
|
|
||||||
//remove current color selection
|
//remove current color selection
|
||||||
document.querySelector('#colors-menu li.selected').classList.remove('selected');
|
document.querySelector('#colors-menu li.selected')?.classList.remove('selected');
|
||||||
|
|
||||||
//add new color and make it selected
|
//add new color and make it selected
|
||||||
let addedColor = addColor(newColor);
|
let addedColor = addColor(newColor);
|
||||||
@ -369,8 +368,7 @@ const ColorModule = (() => {
|
|||||||
if (newColRgb.r + newColRgb.g + newColRgb.b < darkestColorRgb.r + darkestColorRgb.g + darkestColorRgb.b) {
|
if (newColRgb.r + newColRgb.g + newColRgb.b < darkestColorRgb.r + darkestColorRgb.g + darkestColorRgb.b) {
|
||||||
|
|
||||||
//remove current color selection
|
//remove current color selection
|
||||||
var selectedColor = document.querySelector('#colors-menu li.selected');
|
document.querySelector('#colors-menu li.selected')?.classList.remove('selected');
|
||||||
if (selectedColor) selectedColor.classList.remove('selected');
|
|
||||||
|
|
||||||
//set as current color
|
//set as current color
|
||||||
newColorElement.classList.add('selected');
|
newColorElement.classList.add('selected');
|
||||||
|
40
js/Events.js
40
js/Events.js
@ -1,4 +1,6 @@
|
|||||||
class Events {
|
class Events {
|
||||||
|
customCallback = {};
|
||||||
|
|
||||||
/** Used to programmatically create an input event
|
/** Used to programmatically create an input event
|
||||||
*
|
*
|
||||||
* @param {*} keyCode KeyCode of the key to press
|
* @param {*} keyCode KeyCode of the key to press
|
||||||
@ -89,6 +91,13 @@ class Events {
|
|||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Register a callback for a certain window event
|
||||||
|
*
|
||||||
|
* @param {*} event The event to register to
|
||||||
|
* @param {*} elementId The id of the element that will listen to the event
|
||||||
|
* @param {*} functionCallback The function to callback when the event is shoot
|
||||||
|
* @param {...any} args Arguments for the callback
|
||||||
|
*/
|
||||||
static on(event, elementId, functionCallback, ...args) {
|
static on(event, elementId, functionCallback, ...args) {
|
||||||
//if element provided is string, get the actual element
|
//if element provided is string, get the actual element
|
||||||
const element = Util.getElement(elementId);
|
const element = Util.getElement(elementId);
|
||||||
@ -99,6 +108,14 @@ class Events {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Register a callback for a certain window event that is shot by the children of
|
||||||
|
* an element passed as an argument
|
||||||
|
*
|
||||||
|
* @param {*} event The event to register to
|
||||||
|
* @param {*} elementId The id of the element whose children will listen to the event
|
||||||
|
* @param {*} functionCallback The function to callback when the event is shoot
|
||||||
|
* @param {...any} args Arguments for the callback
|
||||||
|
*/
|
||||||
static onChildren(event, parentElement, functionCallback, ...args) {
|
static onChildren(event, parentElement, functionCallback, ...args) {
|
||||||
parentElement = Util.getElement(parentElement);
|
parentElement = Util.getElement(parentElement);
|
||||||
const children = parentElement.children;
|
const children = parentElement.children;
|
||||||
@ -108,4 +125,27 @@ class Events {
|
|||||||
on(event, children[i], functionCallback, ...args);
|
on(event, children[i], functionCallback, ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Registers a callback for a custom (non HTML) event
|
||||||
|
*
|
||||||
|
* @param {*} event The event to register to
|
||||||
|
* @param {*} functionCallback The function to call
|
||||||
|
*/
|
||||||
|
static onCustom(event, functionCallback) {
|
||||||
|
if (customCallback[event] === undefined)
|
||||||
|
customCallback[event] = [];
|
||||||
|
|
||||||
|
customCallback[event].push(functionCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emits a custom (non HTML) event
|
||||||
|
*
|
||||||
|
* @param {*} event The event to emit
|
||||||
|
* @param {...any} args The arguments for that event
|
||||||
|
*/
|
||||||
|
static emit(event, ...args) {
|
||||||
|
if (customCallback[event] != undefined)
|
||||||
|
for (let i=0; i<customCallback[event].length; i++)
|
||||||
|
customCallback[event][i](args);
|
||||||
|
}
|
||||||
}
|
}
|
@ -180,6 +180,9 @@ const FileManager = (() => {
|
|||||||
reader.onload = function (e) {
|
reader.onload = function (e) {
|
||||||
let dictionary = JSON.parse(e.target.result);
|
let dictionary = JSON.parse(e.target.result);
|
||||||
Startup.newPixel(dictionary['canvasWidth'], dictionary['canvasHeight'], dictionary);
|
Startup.newPixel(dictionary['canvasWidth'], dictionary['canvasHeight'], dictionary);
|
||||||
|
for (let i=0; i<dictionary['color' + i] != null; i++) {
|
||||||
|
ColorModule.addColor(dictionary['color'+i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class Layer {
|
|||||||
this.canvasSize = [width, height];
|
this.canvasSize = [width, height];
|
||||||
// REFACTOR: the canvas should actually be a Canvas instance
|
// REFACTOR: the canvas should actually be a Canvas instance
|
||||||
this.canvas = Util.getElement(canvas);
|
this.canvas = Util.getElement(canvas);
|
||||||
// REFACOTR: the context could be an attribute of the canvas class, but it's a bit easier
|
// REFACTOR: the context could be an attribute of the canvas class, but it's a bit easier
|
||||||
// to just type layer.context, we should discuss this
|
// to just type layer.context, we should discuss this
|
||||||
this.context = this.canvas.getContext('2d');
|
this.context = this.canvas.getContext('2d');
|
||||||
this.isSelected = false;
|
this.isSelected = false;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// REFACTOR: convert to IIFE
|
|
||||||
|
|
||||||
const Settings = (() => {
|
const Settings = (() => {
|
||||||
let settings;
|
let settings;
|
||||||
let settingsFromCookie;
|
let settingsFromCookie;
|
||||||
|
14
js/ToolManager.js
Normal file
14
js/ToolManager.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const ToolManager = (() => {
|
||||||
|
/** What it should do
|
||||||
|
*
|
||||||
|
* - Listen to mouse events
|
||||||
|
* - Bind mouse events
|
||||||
|
* - Call tool functions
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
@ -100,8 +100,7 @@ window.addEventListener("mouseup", function (mouseEvent) {
|
|||||||
//if picked color matches this color
|
//if picked color matches this color
|
||||||
if (newColor == colors[i].jscolor.toString()) {
|
if (newColor == colors[i].jscolor.toString()) {
|
||||||
//remove current color selection
|
//remove current color selection
|
||||||
let selectedColor = document.querySelector("#colors-menu li.selected")
|
document.querySelector("#colors-menu li.selected")?.classList.remove("selected");
|
||||||
if (selectedColor) selectedColor.classList.remove("selected");
|
|
||||||
|
|
||||||
//set current color
|
//set current color
|
||||||
|
|
||||||
|
63
js/_tools.js
63
js/_tools.js
@ -4,6 +4,51 @@ var tool = {};
|
|||||||
|
|
||||||
//class for tools
|
//class for tools
|
||||||
class Tool {
|
class Tool {
|
||||||
|
name = "AbstractTool";
|
||||||
|
|
||||||
|
cursorType = {};
|
||||||
|
cursorHTMLElement = undefined;
|
||||||
|
currBrushSize = 1;
|
||||||
|
prevBrushSize = 1;
|
||||||
|
|
||||||
|
startMousePos = {};
|
||||||
|
prevMousePos = {};
|
||||||
|
endMousePos = {};
|
||||||
|
|
||||||
|
onSelect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onHover(cursorPosition) {
|
||||||
|
let toSub = 1;
|
||||||
|
// Prevents the brush to be put in the middle of pixels
|
||||||
|
if (this.currentBrushSize % 2 == 0) {
|
||||||
|
toSub = 0.5;
|
||||||
|
}
|
||||||
|
brushPreview.style.left = (Math.floor(cursorLocation[0] / zoom) * zoom + currentLayer.canvas.offsetLeft - this.currentBrushSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
|
||||||
|
brushPreview.style.top = (Math.floor(cursorLocation[1] / zoom) * zoom + currentLayer.canvas.offsetTop - this.currentBrushSize * zoom / 2 - zoom / 2 + toSub * zoom) + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeselect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrag() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnd() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCursor2() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
constructor (name, options) {
|
constructor (name, options) {
|
||||||
|
|
||||||
//stores the name in object, only needed for legacy functions from when currentTool was just a string
|
//stores the name in object, only needed for legacy functions from when currentTool was just a string
|
||||||
@ -102,4 +147,20 @@ class Tool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*global dragging currentTool, currentToolTemp, selectionCanceled, endSelection*/
|
/*global dragging currentTool, currentToolTemp, selectionCanceled, endSelection*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class selectionTool extends Tool {
|
||||||
|
* imageDataToMove
|
||||||
|
* startDataPos
|
||||||
|
* currDataPos
|
||||||
|
* finalDataPos
|
||||||
|
* canMove
|
||||||
|
*
|
||||||
|
* movePreview()
|
||||||
|
*
|
||||||
|
* // start and end selection just overwrite the onStart and onEnd methods
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user