commit
dd52529b6d
13 changed files with 701 additions and 123 deletions
|
@ -132,3 +132,72 @@
|
|||
flex: 1;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
/* Resizing buttons */
|
||||
.expand-button {
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
||||
background-color: transparent;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
transition-duration: 300ms;
|
||||
|
||||
border: 2px solid #293d3d30;
|
||||
}
|
||||
|
||||
.expand-button::after {
|
||||
content: "";
|
||||
|
||||
background-color: #293d3d77;
|
||||
|
||||
mask-image: url("/res/icons/chevron-up.svg");
|
||||
mask-size: contain;
|
||||
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.expand-button:hover::after {
|
||||
background-color: #466;
|
||||
}
|
||||
|
||||
.expand-button.right::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.expand-button.bottom::after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.expand-button.left::after {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.expand-button.left {
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
.expand-button.top {
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.expand-button.right {
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
}
|
||||
.expand-button.bottom {
|
||||
border-bottom-right-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
|
||||
.expand-button:hover {
|
||||
background-color: #293d3d77;
|
||||
}
|
||||
|
|
19
js/index.js
19
js/index.js
|
@ -343,17 +343,14 @@ function newImage(evt) {
|
|||
clearPaintedMask();
|
||||
uil.layers.forEach(({layer}) => {
|
||||
commands.runCommand("eraseImage", "Clear Canvas", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: layer.canvas.width,
|
||||
h: layer.canvas.height,
|
||||
...layer.bb,
|
||||
ctx: layer.ctx,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clearPaintedMask() {
|
||||
maskPaintCtx.clearRect(0, 0, maskPaintCanvas.width, maskPaintCanvas.height);
|
||||
maskPaintLayer.clear();
|
||||
}
|
||||
|
||||
function march(bb, options = {}) {
|
||||
|
@ -558,8 +555,16 @@ function drawBackground() {
|
|||
// Checkerboard
|
||||
let darkTileColor = "#333";
|
||||
let lightTileColor = "#555";
|
||||
for (var x = 0; x < bgLayer.canvas.width; x += 64) {
|
||||
for (var y = 0; y < bgLayer.canvas.height; y += 64) {
|
||||
for (
|
||||
var x = -bgLayer.origin.x - 64;
|
||||
x < bgLayer.canvas.width - bgLayer.origin.x;
|
||||
x += 64
|
||||
) {
|
||||
for (
|
||||
var y = -bgLayer.origin.y - 64;
|
||||
y < bgLayer.canvas.height - bgLayer.origin.y;
|
||||
y += 64
|
||||
) {
|
||||
bgLayer.ctx.fillStyle =
|
||||
(x + y) % 128 === 0 ? lightTileColor : darkTileColor;
|
||||
bgLayer.ctx.fillRect(x, y, 64, 64);
|
||||
|
|
|
@ -17,6 +17,19 @@ mouse.listen.world.onmousemove.on((evn) => {
|
|||
canvasYInfo.textContent = evn.y;
|
||||
snapXInfo.textContent = evn.x + snap(evn.x);
|
||||
snapYInfo.textContent = evn.y + snap(evn.y);
|
||||
|
||||
if (debug) {
|
||||
debugLayer.clear();
|
||||
debugCtx.fillStyle = "#F0F";
|
||||
debugCtx.beginPath();
|
||||
debugCtx.arc(viewport.cx, viewport.cy, 5, 0, Math.PI * 2);
|
||||
debugCtx.fill();
|
||||
|
||||
debugCtx.fillStyle = "#0FF";
|
||||
debugCtx.beginPath();
|
||||
debugCtx.arc(evn.x, evn.y, 5, 0, Math.PI * 2);
|
||||
debugCtx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,44 +53,97 @@ uiCanvas.width = uiCanvas.clientWidth;
|
|||
uiCanvas.height = uiCanvas.clientHeight;
|
||||
const uiCtx = uiCanvas.getContext("2d", {desynchronized: true});
|
||||
|
||||
/**
|
||||
* Here we setup canvas dynamic scaling
|
||||
*/
|
||||
(() => {
|
||||
let expandSize = localStorage.getItem("expand-size") || 1024;
|
||||
expandSize = parseInt(expandSize, 10);
|
||||
|
||||
const askSize = () => {
|
||||
const by = prompt("How much do you want to expand by?", expandSize);
|
||||
|
||||
if (!by) return null;
|
||||
else {
|
||||
const len = parseInt(by, 10);
|
||||
localStorage.setItem("expand-size", len);
|
||||
expandSize = len;
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
const leftButton = makeElement("button", -64, 0);
|
||||
leftButton.classList.add("expand-button", "left");
|
||||
leftButton.style.width = "64px";
|
||||
leftButton.style.height = `${imageCollection.size.h}px`;
|
||||
leftButton.addEventListener("click", () => {
|
||||
let size = null;
|
||||
if ((size = askSize())) {
|
||||
imageCollection.expand(size, 0, 0, 0);
|
||||
drawBackground();
|
||||
const newLeft = -imageCollection.inputOffset.x - imageCollection.origin.x;
|
||||
leftButton.style.left = newLeft - 64 + "px";
|
||||
topButton.style.left = newLeft + "px";
|
||||
bottomButton.style.left = newLeft + "px";
|
||||
topButton.style.width = imageCollection.size.w + "px";
|
||||
bottomButton.style.width = imageCollection.size.w + "px";
|
||||
}
|
||||
});
|
||||
|
||||
const rightButton = makeElement("button", imageCollection.size.w, 0);
|
||||
rightButton.classList.add("expand-button", "right");
|
||||
rightButton.style.width = "64px";
|
||||
rightButton.style.height = `${imageCollection.size.h}px`;
|
||||
rightButton.addEventListener("click", () => {
|
||||
let size = null;
|
||||
if ((size = askSize())) {
|
||||
imageCollection.expand(0, 0, size, 0);
|
||||
drawBackground();
|
||||
rightButton.style.left =
|
||||
parseInt(rightButton.style.left, 10) + size + "px";
|
||||
topButton.style.width = imageCollection.size.w + "px";
|
||||
bottomButton.style.width = imageCollection.size.w + "px";
|
||||
}
|
||||
});
|
||||
|
||||
const topButton = makeElement("button", 0, -64);
|
||||
topButton.classList.add("expand-button", "top");
|
||||
topButton.style.height = "64px";
|
||||
topButton.style.width = `${imageCollection.size.w}px`;
|
||||
topButton.addEventListener("click", () => {
|
||||
let size = null;
|
||||
if ((size = askSize())) {
|
||||
imageCollection.expand(0, size, 0, 0);
|
||||
drawBackground();
|
||||
const newTop = -imageCollection.inputOffset.y - imageCollection.origin.y;
|
||||
topButton.style.top = newTop - 64 + "px";
|
||||
leftButton.style.top = newTop + "px";
|
||||
rightButton.style.top = newTop + "px";
|
||||
leftButton.style.height = imageCollection.size.h + "px";
|
||||
rightButton.style.height = imageCollection.size.h + "px";
|
||||
}
|
||||
});
|
||||
|
||||
const bottomButton = makeElement("button", 0, imageCollection.size.h);
|
||||
bottomButton.classList.add("expand-button", "bottom");
|
||||
bottomButton.style.height = "64px";
|
||||
bottomButton.style.width = `${imageCollection.size.w}px`;
|
||||
bottomButton.addEventListener("click", () => {
|
||||
let size = null;
|
||||
if ((size = askSize())) {
|
||||
imageCollection.expand(0, 0, 0, size);
|
||||
drawBackground();
|
||||
bottomButton.style.top =
|
||||
parseInt(bottomButton.style.top, 10) + size + "px";
|
||||
leftButton.style.height = imageCollection.size.h + "px";
|
||||
rightButton.style.height = imageCollection.size.h + "px";
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
debugLayer.hide(); // Hidden by default
|
||||
|
||||
layers.registerCollection("mask", {name: "Mask Layers", requiresActive: true});
|
||||
|
||||
// Where CSS and javascript magic happens to make the canvas viewport work
|
||||
/**
|
||||
* Ended up using a CSS transforms approach due to more flexibility on transformations
|
||||
* and capability to automagically translate input coordinates to layer space.
|
||||
*/
|
||||
mouse.registerContext(
|
||||
"world",
|
||||
(evn, ctx) => {
|
||||
// Fix because in chrome layerX and layerY simply doesnt work
|
||||
ctx.coords.prev.x = ctx.coords.pos.x;
|
||||
ctx.coords.prev.y = ctx.coords.pos.y;
|
||||
|
||||
// Get element bounding rect
|
||||
const bb = imageCollection.element.getBoundingClientRect();
|
||||
|
||||
// Get element width/height (css, cause I don't trust client sizes in chrome anymore)
|
||||
const w = imageCollection.size.w;
|
||||
const h = imageCollection.size.h;
|
||||
|
||||
// Get cursor position
|
||||
const x = evn.clientX;
|
||||
const y = evn.clientY;
|
||||
|
||||
// Map to layer space
|
||||
const layerX = ((x - bb.left) / bb.width) * w;
|
||||
const layerY = ((y - bb.top) / bb.height) * h;
|
||||
|
||||
//
|
||||
ctx.coords.pos.x = Math.round(layerX);
|
||||
ctx.coords.pos.y = Math.round(layerY);
|
||||
},
|
||||
{target: imageCollection.inputElement}
|
||||
);
|
||||
|
||||
/**
|
||||
* The global viewport object (may be modularized in the future). All
|
||||
* coordinates given are of the center of the viewport
|
||||
|
@ -158,6 +211,31 @@ let worldInit = null;
|
|||
|
||||
viewport.transform(imageCollection.element);
|
||||
|
||||
/**
|
||||
* Ended up using a CSS transforms approach due to more flexibility on transformations
|
||||
* and capability to automagically translate input coordinates to layer space.
|
||||
*/
|
||||
mouse.registerContext(
|
||||
"world",
|
||||
(evn, ctx) => {
|
||||
// Fix because in chrome layerX and layerY simply doesnt work
|
||||
ctx.coords.prev.x = ctx.coords.pos.x;
|
||||
ctx.coords.prev.y = ctx.coords.pos.y;
|
||||
|
||||
// Get cursor position
|
||||
const x = evn.clientX;
|
||||
const y = evn.clientY;
|
||||
|
||||
// Map to layer space
|
||||
const layerCoords = viewport.viewToCanvas(x, y);
|
||||
|
||||
// Set coords
|
||||
ctx.coords.pos.x = Math.round(layerCoords.x);
|
||||
ctx.coords.pos.y = Math.round(layerCoords.y);
|
||||
},
|
||||
{target: imageCollection.inputElement}
|
||||
);
|
||||
|
||||
mouse.listen.window.onwheel.on((evn) => {
|
||||
if (evn.evn.ctrlKey) {
|
||||
evn.evn.preventDefault();
|
||||
|
@ -176,14 +254,6 @@ mouse.listen.window.onwheel.on((evn) => {
|
|||
viewport.transform(imageCollection.element);
|
||||
|
||||
toolbar.currentTool.redraw();
|
||||
|
||||
if (debug) {
|
||||
debugCtx.clearRect(0, 0, debugCanvas.width, debugCanvas.height);
|
||||
debugCtx.fillStyle = "#F0F";
|
||||
debugCtx.beginPath();
|
||||
debugCtx.arc(viewport.cx, viewport.cy, 5, 0, Math.PI * 2);
|
||||
debugCtx.fill();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -197,8 +267,14 @@ mouse.listen.window.btn.middle.onpaint.on((evn) => {
|
|||
viewport.cy = worldInit.y + (evn.iy - evn.y) / viewport.zoom;
|
||||
|
||||
// Limits
|
||||
viewport.cx = Math.max(Math.min(viewport.cx, imageCollection.size.w), 0);
|
||||
viewport.cy = Math.max(Math.min(viewport.cy, imageCollection.size.h), 0);
|
||||
viewport.cx = Math.max(
|
||||
Math.min(viewport.cx, imageCollection.size.w - imageCollection.origin.x),
|
||||
-imageCollection.origin.x
|
||||
);
|
||||
viewport.cy = Math.max(
|
||||
Math.min(viewport.cy, imageCollection.size.h - imageCollection.origin.y),
|
||||
-imageCollection.origin.y
|
||||
);
|
||||
|
||||
// Draw Viewport location
|
||||
}
|
||||
|
|
47
js/lib/layers.d.js
Normal file
47
js/lib/layers.d.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* A layer
|
||||
*
|
||||
* @typedef {object} Layer
|
||||
* @property {string} id The id of the layer
|
||||
* @property {string} key A identifier for the layer
|
||||
* @property {string} name The display name of the layer
|
||||
* @property {BoundingBox} bb The current bounding box of the layer, in layer coordinates
|
||||
* @property {Size} resolution The resolution of the layer (canvas)
|
||||
* @property {boolean} full If the layer is a full layer (occupies the full collection)
|
||||
* @property {number} x The x coordinate of the layer
|
||||
* @property {number} y The y coordinate of the layer
|
||||
* @property {number} width The width of the layer
|
||||
* @property {number} w The width of the layer
|
||||
* @property {number} height The height of the layer
|
||||
* @property {number} h The height of the layer
|
||||
* @property {Point} origin The location of the origin ((0, 0) point) of the layer (If canvas goes from -64, -32 to 128, 512, it's (64, 32))
|
||||
* @property {HTMLCanvasElement} canvas The canvas element of the layers
|
||||
* @property {CanvasRenderingContext2D} ctx The context of the canvas of the layer
|
||||
* @property {function} clear Clears the layer contents
|
||||
* @property {function} moveAfter Moves this layer to another level (after given layer)
|
||||
* @property {function} moveBefore Moves this layer to another level (before given layer)
|
||||
* @property {function} moveTo Moves this layer to another location
|
||||
* @property {function} resize Resizes the layer in place
|
||||
* @property {function} hide Hides the layer
|
||||
* @property {function} unhide Unhides the layer
|
||||
*/
|
||||
|
||||
/**
|
||||
* A layer collection
|
||||
*
|
||||
* @typedef {object} LayerCollection
|
||||
* @property {string} id The id of the collection
|
||||
* @property {string} key A identifier for the collection
|
||||
* @property {string} name The display name of the collection
|
||||
* @property {HTMLDivElement} element The base element of the collection
|
||||
* @property {HTMLDivElement} inputElement The element used for input handling for the collection
|
||||
* @property {Point} inputOffset The offset for calculating layer coordinates from input element input information
|
||||
* @property {Point} origin The location of the origin ((0, 0) point) of the collection (If canvas goes from -64, -32 to 128, 512, it's (64, 32))
|
||||
* @property {BoundingBox} bb The current bounding box of the collection, in layer coordinates
|
||||
* @property {{[key: string]: Layer}} layers An object for quick access to named layers of the collection
|
||||
* @property {Size} size The size of the collection (CSS)
|
||||
* @property {Size} resolution The resolution of the collection (canvas)
|
||||
* @property {function} expand Expands the collection and its full layers by the specified amounts
|
||||
* @property {function} registerLayer Registers a new layer
|
||||
* @property {function} deleteLayer Deletes a layer from the collection
|
||||
*/
|
374
js/lib/layers.js
374
js/lib/layers.js
|
@ -3,6 +3,162 @@
|
|||
*
|
||||
* It manages canvases and their locations and sizes according to current viewport views
|
||||
*/
|
||||
/**
|
||||
* Here is where the old magic is created.
|
||||
*
|
||||
* This is probably not recommended, but it works and
|
||||
* is probably the most reliable way to not break everything.
|
||||
*/
|
||||
(() => {
|
||||
const original = {
|
||||
drawImage: CanvasRenderingContext2D.prototype.drawImage,
|
||||
getImageData: CanvasRenderingContext2D.prototype.getImageData,
|
||||
putImageData: CanvasRenderingContext2D.prototype.putImageData,
|
||||
|
||||
// Drawing methods
|
||||
moveTo: CanvasRenderingContext2D.prototype.moveTo,
|
||||
lineTo: CanvasRenderingContext2D.prototype.lineTo,
|
||||
|
||||
arc: CanvasRenderingContext2D.prototype.arc,
|
||||
fillRect: CanvasRenderingContext2D.prototype.fillRect,
|
||||
clearRect: CanvasRenderingContext2D.prototype.clearRect,
|
||||
};
|
||||
|
||||
// Backing up original functions to <key>Root
|
||||
Object.keys(original).forEach((key) => {
|
||||
CanvasRenderingContext2D.prototype[key + "Root"] = function (...args) {
|
||||
return original[key].call(this, ...args);
|
||||
};
|
||||
});
|
||||
|
||||
// Add basic get bounding box support (canvas coordinates)
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "bb", {
|
||||
get: function () {
|
||||
return new BoundingBox({
|
||||
x: -this.origin.x,
|
||||
y: -this.origin.y,
|
||||
w: this.canvas.width,
|
||||
h: this.canvas.height,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying drawImage
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "drawImage", {
|
||||
value: function (...args) {
|
||||
switch (args.length) {
|
||||
case 3:
|
||||
case 5:
|
||||
if (this.origin !== undefined) {
|
||||
args[1] += this.origin.x;
|
||||
args[2] += this.origin.y;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
// Check for origin on source
|
||||
const sctx = args[0].getContext && args[0].getContext("2d");
|
||||
if (sctx && sctx.origin !== undefined) {
|
||||
args[1] += sctx.origin.x;
|
||||
args[2] += sctx.origin.y;
|
||||
}
|
||||
|
||||
// Check for origin on destination
|
||||
if (this.origin !== undefined) {
|
||||
args[5] += this.origin.x;
|
||||
args[6] += this.origin.y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.drawImage.call(this, ...args);
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying getImageData method
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "getImageData", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.getImageData.call(this, ...args);
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying putImageData method
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "putImageData", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.putImageData.call(this, ...args);
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying moveTo method
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "moveTo", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.moveTo.call(this, ...args);
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying lineTo method
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "lineTo", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.lineTo.call(this, ...args);
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying arc
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "arc", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.arc.call(this, ...args);
|
||||
},
|
||||
});
|
||||
|
||||
// Modifying fillRect
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "fillRect", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.fillRect.call(this, ...args);
|
||||
},
|
||||
});
|
||||
// Modifying clearRect
|
||||
Reflect.defineProperty(CanvasRenderingContext2D.prototype, "clearRect", {
|
||||
value: function (...args) {
|
||||
if (this.origin) {
|
||||
args[0] += this.origin.x;
|
||||
args[1] += this.origin.y;
|
||||
}
|
||||
// Pass arguments through
|
||||
return original.clearRect.call(this, ...args);
|
||||
},
|
||||
});
|
||||
})();
|
||||
// End of black magic
|
||||
|
||||
const layers = {
|
||||
_collections: [],
|
||||
collections: makeWriteOnce({}, "layers.collections"),
|
||||
|
@ -17,6 +173,18 @@ const layers = {
|
|||
|
||||
// Registers a new collection
|
||||
// Layer collections are a group of layers (canvases) that are rendered in tandem. (same width, height, position, transform, etc)
|
||||
/**
|
||||
*
|
||||
* @param {string} key A key used to identify the collection
|
||||
* @param {Size} size The initial size of the collection in pixels (CSS size)
|
||||
* @param {object} options Extra options for the collection
|
||||
* @param {string} [options.name=key] The display name of the collection
|
||||
* @param {{key: string, options: object}} [options.initLayer] The configuration for the initial layer to be created
|
||||
* @param {number} [options.inputSizeMultiplier=9] Size of the input area element, in pixels
|
||||
* @param {HTMLElement} [options.targetElement] Element the collection will be inserted into
|
||||
* @param {Size} [options.resolution=size] The resolution of the collection (canvas size). Not sure it works.
|
||||
* @returns {LayerCollection} The newly created layer collection
|
||||
*/
|
||||
registerCollection: (key, size, options = {}) => {
|
||||
defaultOpt(options, {
|
||||
// Display name for the collection
|
||||
|
@ -29,7 +197,7 @@ const layers = {
|
|||
},
|
||||
|
||||
// Input multiplier (Size of the input element div)
|
||||
inputSizeMultiplier: 3,
|
||||
inputSizeMultiplier: 9,
|
||||
|
||||
// Target
|
||||
targetElement: document.getElementById("layer-render"),
|
||||
|
@ -64,6 +232,7 @@ const layers = {
|
|||
|
||||
options.targetElement.appendChild(element);
|
||||
|
||||
/** @type {LayerCollection} */
|
||||
const collection = makeWriteOnce(
|
||||
{
|
||||
id,
|
||||
|
@ -73,6 +242,7 @@ const layers = {
|
|||
_layers: [],
|
||||
layers: {},
|
||||
|
||||
key,
|
||||
name: options.name,
|
||||
element,
|
||||
inputElement: inputel,
|
||||
|
@ -81,11 +251,30 @@ const layers = {
|
|||
return this._inputOffset;
|
||||
},
|
||||
|
||||
_origin: {x: 0, y: 0},
|
||||
get origin() {
|
||||
return {...this._origin};
|
||||
},
|
||||
|
||||
get bb() {
|
||||
return new BoundingBox({
|
||||
x: -this.origin.x,
|
||||
y: -this.origin.y,
|
||||
w: this.size.w,
|
||||
h: this.size.h,
|
||||
});
|
||||
},
|
||||
|
||||
_resizeInputDiv() {
|
||||
// Set offset
|
||||
const oldOffset = {...this._inputOffset};
|
||||
this._inputOffset = {
|
||||
x: -Math.floor(options.inputSizeMultiplier / 2) * size.w,
|
||||
y: -Math.floor(options.inputSizeMultiplier / 2) * size.h,
|
||||
x:
|
||||
-Math.floor(options.inputSizeMultiplier / 2) * size.w -
|
||||
this._origin.x,
|
||||
y:
|
||||
-Math.floor(options.inputSizeMultiplier / 2) * size.h -
|
||||
this._origin.y,
|
||||
};
|
||||
|
||||
// Resize the input element
|
||||
|
@ -97,6 +286,48 @@ const layers = {
|
|||
this.inputElement.style.height = `${
|
||||
size.h * options.inputSizeMultiplier
|
||||
}px`;
|
||||
|
||||
// Move elements inside to new offset
|
||||
for (const child of this.inputElement.children) {
|
||||
if (child.style.position === "absolute") {
|
||||
child.style.left = `${
|
||||
parseInt(child.style.left, 10) +
|
||||
oldOffset.x -
|
||||
this._inputOffset.x
|
||||
}px`;
|
||||
child.style.top = `${
|
||||
parseInt(child.style.top, 10) +
|
||||
oldOffset.y -
|
||||
this._inputOffset.y
|
||||
}px`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Expands the collection and its full layers by the specified amounts
|
||||
*
|
||||
* @param {number} left Pixels to expand left
|
||||
* @param {number} top Pixels to expand top
|
||||
* @param {number} right Pixels to expand right
|
||||
* @param {number} bottom Pixels to expand bottom
|
||||
*/
|
||||
expand(left, top, right, bottom) {
|
||||
this._layers.forEach((layer) => {
|
||||
if (layer.full) layer._expand(left, top, right, bottom);
|
||||
});
|
||||
|
||||
this._origin.x += left;
|
||||
this._origin.y += top;
|
||||
|
||||
this.size.w += left + right;
|
||||
this.size.h += top + bottom;
|
||||
|
||||
this._resizeInputDiv();
|
||||
|
||||
for (const layer of this._layers) {
|
||||
layer.moveTo(layer.x, layer.y);
|
||||
}
|
||||
},
|
||||
|
||||
size,
|
||||
|
@ -113,9 +344,9 @@ const layers = {
|
|||
* @param {?string} options.group
|
||||
* @param {object} options.after
|
||||
* @param {object} options.ctxOptions
|
||||
* @returns
|
||||
* @returns {Layer} The newly created layer
|
||||
*/
|
||||
registerLayer: (key = null, options = {}) => {
|
||||
registerLayer(key = null, options = {}) {
|
||||
// Make ID
|
||||
const id = guid();
|
||||
|
||||
|
@ -124,7 +355,12 @@ const layers = {
|
|||
name: key || `Temporary ${id}`,
|
||||
|
||||
// Bounding box for layer
|
||||
bb: {x: 0, y: 0, w: collection.size.w, h: collection.size.h},
|
||||
bb: {
|
||||
x: -collection.origin.x,
|
||||
y: -collection.origin.y,
|
||||
w: collection.size.w,
|
||||
h: collection.size.h,
|
||||
},
|
||||
|
||||
// Resolution for layer
|
||||
resolution: null,
|
||||
|
@ -139,11 +375,25 @@ const layers = {
|
|||
ctxOptions: {},
|
||||
});
|
||||
|
||||
// Calculate resolution
|
||||
// Check if the layer is full
|
||||
let full = false;
|
||||
if (
|
||||
options.bb.x === -collection.origin.x &&
|
||||
options.bb.y === -collection.origin.y &&
|
||||
options.bb.w === collection.size.w &&
|
||||
options.bb.h === collection.size.h
|
||||
)
|
||||
full = true;
|
||||
|
||||
if (!options.resolution)
|
||||
// Calculate resolution
|
||||
options.resolution = {
|
||||
w: (collection.resolution.w / collection.size.w) * options.bb.w,
|
||||
h: (collection.resolution.h / collection.size.h) * options.bb.h,
|
||||
w: Math.round(
|
||||
(collection.resolution.w / collection.size.w) * options.bb.w
|
||||
),
|
||||
h: Math.round(
|
||||
(collection.resolution.h / collection.size.h) * options.bb.h
|
||||
),
|
||||
};
|
||||
|
||||
// This layer's canvas
|
||||
|
@ -166,7 +416,21 @@ const layers = {
|
|||
options.after.canvas.after(canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we set the context origin for using the black magic.
|
||||
*/
|
||||
const ctx = canvas.getContext("2d", options.ctxOptions);
|
||||
if (full) {
|
||||
// Modify context to add origin information
|
||||
ctx.origin = {
|
||||
get x() {
|
||||
return collection.origin.x;
|
||||
},
|
||||
get y() {
|
||||
return collection.origin.y;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Path used for logging purposes
|
||||
const _layerlogpath = key
|
||||
|
@ -177,9 +441,16 @@ const layers = {
|
|||
_logpath: _layerlogpath,
|
||||
_collection: collection,
|
||||
|
||||
_bb: new BoundingBox(options.bb),
|
||||
get bb() {
|
||||
return new BoundingBox(this._bb);
|
||||
},
|
||||
|
||||
resolution: new Size(options.resolution),
|
||||
id,
|
||||
key,
|
||||
name: options.name,
|
||||
full,
|
||||
|
||||
state: new Proxy(
|
||||
{visible: true},
|
||||
|
@ -195,10 +466,81 @@ const layers = {
|
|||
}
|
||||
),
|
||||
|
||||
get x() {
|
||||
return this._bb.x;
|
||||
},
|
||||
|
||||
get y() {
|
||||
return this._bb.y;
|
||||
},
|
||||
|
||||
get width() {
|
||||
return this._bb.w;
|
||||
},
|
||||
|
||||
get height() {
|
||||
return this._bb.h;
|
||||
},
|
||||
|
||||
get w() {
|
||||
return this._bb.w;
|
||||
},
|
||||
|
||||
get h() {
|
||||
return this._bb.h;
|
||||
},
|
||||
|
||||
get origin() {
|
||||
return this._collection.origin;
|
||||
},
|
||||
|
||||
/** Our canvas */
|
||||
canvas,
|
||||
ctx,
|
||||
|
||||
/**
|
||||
* This is called by the collection when the layer must be expanded.
|
||||
*
|
||||
* Should NOT be called directly
|
||||
*
|
||||
* @param {number} left Pixels to expand left
|
||||
* @param {number} top Pixels to expand top
|
||||
* @param {number} right Pixels to expand right
|
||||
* @param {number} bottom Pixels to expand bottom
|
||||
*/
|
||||
_expand(left, top, right, bottom) {
|
||||
const tmpCanvas = document.createElement("canvas");
|
||||
tmpCanvas.width = this.w;
|
||||
tmpCanvas.height = this.h;
|
||||
tmpCanvas.getContext("2d").drawImage(this.canvas, 0, 0);
|
||||
|
||||
this.resize(this.w + left + right, this.h + top + bottom);
|
||||
this.clear();
|
||||
this.ctx.drawImageRoot(tmpCanvas, left, top);
|
||||
|
||||
this.moveTo(this.x - left, this.y - top);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the layer contents
|
||||
*/
|
||||
clear() {
|
||||
this.ctx.clearRectRoot(
|
||||
0,
|
||||
0,
|
||||
this.canvas.width,
|
||||
this.canvas.height
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Recalculates DOM positioning
|
||||
*/
|
||||
syncDOM() {
|
||||
this.moveTo(this.x, this.y);
|
||||
this.resize(this.w, this.h);
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves this layer to another level (after given layer)
|
||||
*
|
||||
|
@ -224,8 +566,10 @@ const layers = {
|
|||
* @param {number} y Y coordinate of the top left of the canvas
|
||||
*/
|
||||
moveTo(x, y) {
|
||||
canvas.style.left = `${x}px`;
|
||||
canvas.style.top = `${y}px`;
|
||||
this._bb.x = x;
|
||||
this._bb.y = y;
|
||||
this.canvas.style.left = `${x}px`;
|
||||
this.canvas.style.top = `${y}px`;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -241,6 +585,8 @@ const layers = {
|
|||
canvas.height = Math.round(
|
||||
options.resolution.h * (h / options.bb.h)
|
||||
);
|
||||
this._bb.w = w;
|
||||
this._bb.h = h;
|
||||
canvas.style.width = `${w}px`;
|
||||
canvas.style.height = `${h}px`;
|
||||
},
|
||||
|
@ -282,7 +628,11 @@ const layers = {
|
|||
return layer;
|
||||
},
|
||||
|
||||
// Deletes a layer
|
||||
/**
|
||||
* Deletes a layer from the collection
|
||||
*
|
||||
* @param {Layer} layer Layer to delete
|
||||
*/
|
||||
deleteLayer: (layer) => {
|
||||
const lobj = collection._layers.splice(
|
||||
collection._layers.findIndex(
|
||||
|
|
|
@ -10,6 +10,19 @@
|
|||
* @property {number} y - y coordinate
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a size
|
||||
*/
|
||||
class Size {
|
||||
w = 0;
|
||||
h = 0;
|
||||
|
||||
constructor({w, h} = {w: 0, h: 0}) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a simple bouding box
|
||||
*/
|
||||
|
@ -231,7 +244,12 @@ function makeWriteOnce(obj, name = "write-once object", exceptions = []) {
|
|||
* @returns an offset, in which [i + offset = (a location snapped to the grid)]
|
||||
*/
|
||||
function snap(i, offset = 0, gridSize = 64) {
|
||||
const modulus = (i - offset) % gridSize;
|
||||
let diff = i - offset;
|
||||
if (diff < 0) {
|
||||
diff += gridSize * Math.ceil(Math.abs(diff / gridSize));
|
||||
}
|
||||
|
||||
const modulus = diff % gridSize;
|
||||
var snapOffset = modulus;
|
||||
|
||||
if (modulus > gridSize / 2) snapOffset = modulus - gridSize;
|
||||
|
@ -288,14 +306,19 @@ function cropCanvas(sourceCanvas, options = {}) {
|
|||
|
||||
const w = sourceCanvas.width;
|
||||
const h = sourceCanvas.height;
|
||||
var imageData = sourceCanvas.getContext("2d").getImageData(0, 0, w, h);
|
||||
const srcCtx = sourceCanvas.getContext("2d");
|
||||
const offset = {
|
||||
x: (srcCtx.origin && -srcCtx.origin.x) || 0,
|
||||
y: (srcCtx.origin && -srcCtx.origin.y) || 0,
|
||||
};
|
||||
var imageData = srcCtx.getImageDataRoot(0, 0, w, h);
|
||||
/** @type {BoundingBox} */
|
||||
const bb = new BoundingBox();
|
||||
|
||||
let minx = w;
|
||||
let maxx = -1;
|
||||
let miny = h;
|
||||
let maxy = -1;
|
||||
let minx = Infinity;
|
||||
let maxx = -Infinity;
|
||||
let miny = Infinity;
|
||||
let maxy = -Infinity;
|
||||
|
||||
for (let y = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++) {
|
||||
|
@ -303,10 +326,10 @@ function cropCanvas(sourceCanvas, options = {}) {
|
|||
const index = (y * w + x) * 4; // OHHH OK this is setting the imagedata.data uint8clampeddataarray index for the specified x/y coords
|
||||
//this part i get, this is checking that 4th RGBA byte for opacity
|
||||
if (imageData.data[index + 3] > 0) {
|
||||
minx = Math.min(minx, x);
|
||||
maxx = Math.max(maxx, x);
|
||||
miny = Math.min(miny, y);
|
||||
maxy = Math.max(maxy, y);
|
||||
minx = Math.min(minx, x + offset.x);
|
||||
maxx = Math.max(maxx, x + offset.x);
|
||||
miny = Math.min(miny, y + offset.y);
|
||||
maxy = Math.max(maxy, y + offset.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +339,8 @@ function cropCanvas(sourceCanvas, options = {}) {
|
|||
bb.w = maxx - minx + 1 + 2 * options.border;
|
||||
bb.h = maxy - miny + 1 + 2 * options.border;
|
||||
|
||||
if (maxx < 0) throw new NoContentError("Canvas has no content to crop");
|
||||
if (!Number.isFinite(maxx))
|
||||
throw new NoContentError("Canvas has no content to crop");
|
||||
|
||||
var cutCanvas = document.createElement("canvas");
|
||||
cutCanvas.width = bb.w;
|
||||
|
@ -339,12 +363,7 @@ function cropCanvas(sourceCanvas, options = {}) {
|
|||
function downloadCanvas(options = {}) {
|
||||
defaultOpt(options, {
|
||||
cropToContent: true,
|
||||
canvas: uil.getVisible({
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: imageCollection.size.w,
|
||||
h: imageCollection.size.h,
|
||||
}),
|
||||
canvas: uil.getVisible(imageCollection.bb),
|
||||
filename:
|
||||
new Date()
|
||||
.toISOString()
|
||||
|
@ -360,6 +379,7 @@ function downloadCanvas(options = {}) {
|
|||
var croppedCanvas = options.cropToContent
|
||||
? cropCanvas(options.canvas).canvas
|
||||
: options.canvas;
|
||||
|
||||
if (croppedCanvas != null) {
|
||||
croppedCanvas.toBlob((blob) => {
|
||||
link.href = URL.createObjectURL(blob);
|
||||
|
|
|
@ -41,7 +41,7 @@ const colorBrushTool = () =>
|
|||
"Color Brush",
|
||||
(state, opt) => {
|
||||
// Draw new cursor immediately
|
||||
uiCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
uiCtx.clearRect(0, 0, uiCanvas.width, uiCanvas.height);
|
||||
state.movecb({
|
||||
...mouse.coords.world.pos,
|
||||
evn: {
|
||||
|
@ -64,11 +64,11 @@ const colorBrushTool = () =>
|
|||
after: imgLayer,
|
||||
ctxOptions: {willReadFrequently: true},
|
||||
});
|
||||
state.drawLayer.canvas.style.filter = "opacity(70%)";
|
||||
state.eraseLayer = imageCollection.registerLayer(null, {
|
||||
after: imgLayer,
|
||||
ctxOptions: {willReadFrequently: true},
|
||||
});
|
||||
state.eraseLayer.canvas.style.display = "none";
|
||||
state.eraseLayer.hide();
|
||||
state.eraseBackup = imageCollection.registerLayer(null, {
|
||||
after: imgLayer,
|
||||
|
@ -209,7 +209,7 @@ const colorBrushTool = () =>
|
|||
state.brushSize -
|
||||
Math.floor(state.config.brushScrollSpeed * evn.delta)
|
||||
);
|
||||
uiCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
uiCtx.clearRect(0, 0, uiCanvas.width, uiCanvas.height);
|
||||
state.movecb(evn);
|
||||
}
|
||||
};
|
||||
|
@ -231,12 +231,8 @@ const colorBrushTool = () =>
|
|||
state.keyupcb = (evn) => {
|
||||
switch (evn.code) {
|
||||
case "ShiftLeft":
|
||||
if (!keyboard.isPressed("ShiftRight")) {
|
||||
state.disableDropper();
|
||||
}
|
||||
break;
|
||||
case "ShiftRight":
|
||||
if (!keyboard.isPressed("ShiftLeft")) {
|
||||
if (!keyboard.isPressed(evn.code)) {
|
||||
state.disableDropper();
|
||||
}
|
||||
break;
|
||||
|
@ -288,6 +284,7 @@ const colorBrushTool = () =>
|
|||
|
||||
const cropped = cropCanvas(canvas, {border: 10});
|
||||
const bb = cropped.bb;
|
||||
|
||||
commands.runCommand("drawImage", "Color Brush Draw", {
|
||||
image: cropped.canvas,
|
||||
...bb,
|
||||
|
@ -302,10 +299,9 @@ const colorBrushTool = () =>
|
|||
if (state.affectMask) _mask_brush_erase_callback(evn, state);
|
||||
|
||||
// Make a backup of the current image to apply erase later
|
||||
const bkpcanvas = state.eraseBackup.canvas;
|
||||
const bkpctx = state.eraseBackup.ctx;
|
||||
bkpctx.clearRect(0, 0, bkpcanvas.width, bkpcanvas.height);
|
||||
bkpctx.drawImage(uil.canvas, 0, 0);
|
||||
state.eraseBackup.clear();
|
||||
bkpctx.drawImageRoot(uil.canvas, 0, 0);
|
||||
|
||||
uil.ctx.globalCompositeOperation = "destination-out";
|
||||
_color_brush_erase_callback(evn, state, uil.ctx);
|
||||
|
@ -335,8 +331,8 @@ const colorBrushTool = () =>
|
|||
const bb = cropped.bb;
|
||||
|
||||
uil.ctx.filter = null;
|
||||
uil.ctx.clearRect(0, 0, uil.canvas.width, uil.canvas.height);
|
||||
uil.ctx.drawImage(bkpcanvas, 0, 0);
|
||||
uil.layer.clear();
|
||||
uil.ctx.drawImageRoot(bkpcanvas, 0, 0);
|
||||
|
||||
commands.runCommand("eraseImage", "Color Brush Erase", {
|
||||
mask: cropped.canvas,
|
||||
|
|
|
@ -39,12 +39,13 @@ const _monitorProgress = (bb, oncheck = null) => {
|
|||
|
||||
oncheck && oncheck(data);
|
||||
|
||||
layer.clear();
|
||||
|
||||
// Draw Progress Bar
|
||||
layer.ctx.fillStyle = "#5F5";
|
||||
layer.ctx.fillRect(1, 1, bb.w * data.progress, 10);
|
||||
|
||||
// Draw Progress Text
|
||||
layer.ctx.clearRect(0, 11, expanded.w, 40);
|
||||
layer.ctx.fillStyle = "#FFF";
|
||||
|
||||
layer.ctx.fillRect(0, 15, 60, 25);
|
||||
|
@ -295,8 +296,7 @@ const _generate = async (endpoint, request, bb, options = {}) => {
|
|||
});
|
||||
|
||||
const redraw = (url = images[at]) => {
|
||||
if (url === null)
|
||||
layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
||||
if (url === null) layer.clear();
|
||||
if (!url) return;
|
||||
|
||||
const img = new Image();
|
||||
|
@ -318,7 +318,7 @@ const _generate = async (endpoint, request, bb, options = {}) => {
|
|||
ctx.drawImage(keepUnmaskCanvas, 0, 0);
|
||||
}
|
||||
|
||||
layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
||||
layer.clear();
|
||||
layer.ctx.drawImage(
|
||||
canvas,
|
||||
0,
|
||||
|
@ -770,8 +770,8 @@ const dream_generate_callback = async (bb, resolution, state) => {
|
|||
bbCtx.globalCompositeOperation = "destination-in";
|
||||
bbCtx.drawImage(
|
||||
maskPaintCanvas,
|
||||
bb.x,
|
||||
bb.y,
|
||||
bb.x + maskPaintLayer.origin.x,
|
||||
bb.y + maskPaintLayer.origin.y,
|
||||
bb.w,
|
||||
bb.h,
|
||||
0,
|
||||
|
@ -798,8 +798,8 @@ const dream_generate_callback = async (bb, resolution, state) => {
|
|||
bbCtx.globalCompositeOperation = "destination-out"; // ???
|
||||
bbCtx.drawImage(
|
||||
maskPaintCanvas,
|
||||
bb.x,
|
||||
bb.y,
|
||||
bb.x + maskPaintLayer.origin.x,
|
||||
bb.y + maskPaintLayer.origin.y,
|
||||
bb.w,
|
||||
bb.h,
|
||||
0,
|
||||
|
@ -920,7 +920,17 @@ const dream_img2img_callback = (bb, resolution, state) => {
|
|||
bbCtx.fillStyle = state.invertMask ? "#FFFF" : "#000F";
|
||||
bbCtx.fillRect(0, 0, bb.w, bb.h);
|
||||
bbCtx.globalCompositeOperation = "destination-out";
|
||||
bbCtx.drawImage(maskPaintCanvas, bb.x, bb.y, bb.w, bb.h, 0, 0, bb.w, bb.h);
|
||||
bbCtx.drawImage(
|
||||
maskPaintCanvas,
|
||||
bb.x + maskPaintLayer.origin.x,
|
||||
bb.y + maskPaintLayer.origin.y,
|
||||
bb.w,
|
||||
bb.h,
|
||||
0,
|
||||
0,
|
||||
bb.w,
|
||||
bb.h
|
||||
);
|
||||
|
||||
bbCtx.globalCompositeOperation = "destination-atop";
|
||||
bbCtx.fillStyle = state.invertMask ? "#000F" : "#FFFF";
|
||||
|
|
|
@ -4,10 +4,8 @@ const interrogateTool = () =>
|
|||
"Interrogate",
|
||||
(state, opt) => {
|
||||
// Draw new cursor immediately
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
state.mousemovecb({
|
||||
...mouse.coords.world.pos,
|
||||
});
|
||||
ovLayer.clear();
|
||||
state.redraw();
|
||||
|
||||
// Start Listeners
|
||||
mouse.listen.world.onmousemove.on(state.mousemovecb);
|
||||
|
@ -37,8 +35,7 @@ const interrogateTool = () =>
|
|||
state.invertMask = false;
|
||||
state.overMaskPx = 0;
|
||||
|
||||
state.erasePrevReticle = () =>
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
state.erasePrevReticle = () => ovLayer.clear();
|
||||
|
||||
state.mousemovecb = (evn) => {
|
||||
state.erasePrevReticle();
|
||||
|
|
|
@ -240,12 +240,7 @@ const maskBrushTool = () =>
|
|||
clearMaskButton.textContent = "Clear";
|
||||
clearMaskButton.title = "Clears Painted Mask";
|
||||
clearMaskButton.onclick = () => {
|
||||
maskPaintCtx.clearRect(
|
||||
0,
|
||||
0,
|
||||
maskPaintCanvas.width,
|
||||
maskPaintCanvas.height
|
||||
);
|
||||
maskPaintLayer.clear();
|
||||
};
|
||||
|
||||
const previewMaskButton = document.createElement("button");
|
||||
|
|
|
@ -4,7 +4,7 @@ const selectTransformTool = () =>
|
|||
"Select Image",
|
||||
(state, opt) => {
|
||||
// Draw new cursor immediately
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
state.movecb(mouse.coords.world.pos);
|
||||
|
||||
// Canvas left mouse handlers
|
||||
|
@ -46,7 +46,7 @@ const selectTransformTool = () =>
|
|||
state.reset();
|
||||
|
||||
// Resets cursor
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
|
||||
// Clears overlay
|
||||
imageCollection.inputElement.style.cursor = "auto";
|
||||
|
@ -80,7 +80,7 @@ const selectTransformTool = () =>
|
|||
state.lastMouseMove = null;
|
||||
|
||||
state.redraw = () => {
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
state.movecb(state.lastMouseMove);
|
||||
};
|
||||
|
||||
|
@ -186,7 +186,7 @@ const selectTransformTool = () =>
|
|||
|
||||
// Mouse move handler. As always, also renders cursor
|
||||
state.movecb = (evn) => {
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
uiCtx.clearRect(0, 0, uiCanvas.width, uiCanvas.height);
|
||||
imageCollection.inputElement.style.cursor = "auto";
|
||||
state.lastMouseTarget = evn.target;
|
||||
|
|
|
@ -6,7 +6,7 @@ const stampTool = () =>
|
|||
state.loaded = true;
|
||||
|
||||
// Draw new cursor immediately
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
state.movecb({...mouse.coords.world.pos});
|
||||
|
||||
// Start Listeners
|
||||
|
@ -47,7 +47,7 @@ const stampTool = () =>
|
|||
child.classList.remove("active");
|
||||
});
|
||||
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
},
|
||||
{
|
||||
init: (state) => {
|
||||
|
@ -88,7 +88,7 @@ const stampTool = () =>
|
|||
state.selected = null;
|
||||
}
|
||||
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
if (state.loaded) state.movecb(state.lastMouseMove);
|
||||
};
|
||||
|
||||
|
@ -300,7 +300,7 @@ const stampTool = () =>
|
|||
|
||||
state.lastMouseMove = evn;
|
||||
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
ovLayer.clear();
|
||||
|
||||
// Draw selected image
|
||||
if (state.selected) {
|
||||
|
|
Loading…
Reference in a new issue