canvas scaling?
Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
parent
6d9155261e
commit
ea68e25cf0
11 changed files with 578 additions and 98 deletions
|
@ -132,3 +132,72 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 25px;
|
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 {
|
||||||
|
backdrop-filter: brightness(60%);
|
||||||
|
}
|
||||||
|
|
18
js/index.js
18
js/index.js
|
@ -343,8 +343,8 @@ function newImage(evt) {
|
||||||
clearPaintedMask();
|
clearPaintedMask();
|
||||||
uil.layers.forEach(({layer}) => {
|
uil.layers.forEach(({layer}) => {
|
||||||
commands.runCommand("eraseImage", "Clear Canvas", {
|
commands.runCommand("eraseImage", "Clear Canvas", {
|
||||||
x: 0,
|
x: -layer.origin.x,
|
||||||
y: 0,
|
y: -layer.origin.y,
|
||||||
w: layer.canvas.width,
|
w: layer.canvas.width,
|
||||||
h: layer.canvas.height,
|
h: layer.canvas.height,
|
||||||
ctx: layer.ctx,
|
ctx: layer.ctx,
|
||||||
|
@ -353,7 +353,7 @@ function newImage(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPaintedMask() {
|
function clearPaintedMask() {
|
||||||
maskPaintCtx.clearRect(0, 0, maskPaintCanvas.width, maskPaintCanvas.height);
|
maskPaintLayer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
function march(bb, options = {}) {
|
function march(bb, options = {}) {
|
||||||
|
@ -558,8 +558,16 @@ function drawBackground() {
|
||||||
// Checkerboard
|
// Checkerboard
|
||||||
let darkTileColor = "#333";
|
let darkTileColor = "#333";
|
||||||
let lightTileColor = "#555";
|
let lightTileColor = "#555";
|
||||||
for (var x = 0; x < bgLayer.canvas.width; x += 64) {
|
for (
|
||||||
for (var y = 0; y < bgLayer.canvas.height; y += 64) {
|
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 =
|
bgLayer.ctx.fillStyle =
|
||||||
(x + y) % 128 === 0 ? lightTileColor : darkTileColor;
|
(x + y) % 128 === 0 ? lightTileColor : darkTileColor;
|
||||||
bgLayer.ctx.fillRect(x, y, 64, 64);
|
bgLayer.ctx.fillRect(x, y, 64, 64);
|
||||||
|
|
|
@ -17,6 +17,19 @@ mouse.listen.world.onmousemove.on((evn) => {
|
||||||
canvasYInfo.textContent = evn.y;
|
canvasYInfo.textContent = evn.y;
|
||||||
snapXInfo.textContent = evn.x + snap(evn.x);
|
snapXInfo.textContent = evn.x + snap(evn.x);
|
||||||
snapYInfo.textContent = evn.y + snap(evn.y);
|
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,99 @@ uiCanvas.width = uiCanvas.clientWidth;
|
||||||
uiCanvas.height = uiCanvas.clientHeight;
|
uiCanvas.height = uiCanvas.clientHeight;
|
||||||
const uiCtx = uiCanvas.getContext("2d", {desynchronized: true});
|
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
|
debugLayer.hide(); // Hidden by default
|
||||||
|
|
||||||
layers.registerCollection("mask", {name: "Mask Layers", requiresActive: true});
|
layers.registerCollection("mask", {name: "Mask Layers", requiresActive: true});
|
||||||
|
|
||||||
// Where CSS and javascript magic happens to make the canvas viewport work
|
// 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
|
* The global viewport object (may be modularized in the future). All
|
||||||
* coordinates given are of the center of the viewport
|
* coordinates given are of the center of the viewport
|
||||||
|
@ -158,6 +213,31 @@ let worldInit = null;
|
||||||
|
|
||||||
viewport.transform(imageCollection.element);
|
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) => {
|
mouse.listen.window.onwheel.on((evn) => {
|
||||||
if (evn.evn.ctrlKey) {
|
if (evn.evn.ctrlKey) {
|
||||||
evn.evn.preventDefault();
|
evn.evn.preventDefault();
|
||||||
|
@ -176,14 +256,6 @@ mouse.listen.window.onwheel.on((evn) => {
|
||||||
viewport.transform(imageCollection.element);
|
viewport.transform(imageCollection.element);
|
||||||
|
|
||||||
toolbar.currentTool.redraw();
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
309
js/lib/layers.js
309
js/lib/layers.js
|
@ -3,6 +3,150 @@
|
||||||
*
|
*
|
||||||
* It manages canvases and their locations and sizes according to current viewport views
|
* 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);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 = {
|
const layers = {
|
||||||
_collections: [],
|
_collections: [],
|
||||||
collections: makeWriteOnce({}, "layers.collections"),
|
collections: makeWriteOnce({}, "layers.collections"),
|
||||||
|
@ -29,7 +173,7 @@ const layers = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Input multiplier (Size of the input element div)
|
// Input multiplier (Size of the input element div)
|
||||||
inputSizeMultiplier: 3,
|
inputSizeMultiplier: 9,
|
||||||
|
|
||||||
// Target
|
// Target
|
||||||
targetElement: document.getElementById("layer-render"),
|
targetElement: document.getElementById("layer-render"),
|
||||||
|
@ -81,11 +225,21 @@ const layers = {
|
||||||
return this._inputOffset;
|
return this._inputOffset;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_origin: {x: 0, y: 0},
|
||||||
|
get origin() {
|
||||||
|
return {...this._origin};
|
||||||
|
},
|
||||||
|
|
||||||
_resizeInputDiv() {
|
_resizeInputDiv() {
|
||||||
// Set offset
|
// Set offset
|
||||||
|
const oldOffset = {...this._inputOffset};
|
||||||
this._inputOffset = {
|
this._inputOffset = {
|
||||||
x: -Math.floor(options.inputSizeMultiplier / 2) * size.w,
|
x:
|
||||||
y: -Math.floor(options.inputSizeMultiplier / 2) * size.h,
|
-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
|
// Resize the input element
|
||||||
|
@ -97,6 +251,40 @@ const layers = {
|
||||||
this.inputElement.style.height = `${
|
this.inputElement.style.height = `${
|
||||||
size.h * options.inputSizeMultiplier
|
size.h * options.inputSizeMultiplier
|
||||||
}px`;
|
}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`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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,
|
size,
|
||||||
|
@ -115,7 +303,7 @@ const layers = {
|
||||||
* @param {object} options.ctxOptions
|
* @param {object} options.ctxOptions
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
registerLayer: (key = null, options = {}) => {
|
registerLayer(key = null, options = {}) {
|
||||||
// Make ID
|
// Make ID
|
||||||
const id = guid();
|
const id = guid();
|
||||||
|
|
||||||
|
@ -124,7 +312,12 @@ const layers = {
|
||||||
name: key || `Temporary ${id}`,
|
name: key || `Temporary ${id}`,
|
||||||
|
|
||||||
// Bounding box for layer
|
// 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 for layer
|
||||||
resolution: null,
|
resolution: null,
|
||||||
|
@ -139,11 +332,25 @@ const layers = {
|
||||||
ctxOptions: {},
|
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)
|
if (!options.resolution)
|
||||||
|
// Calculate resolution
|
||||||
options.resolution = {
|
options.resolution = {
|
||||||
w: (collection.resolution.w / collection.size.w) * options.bb.w,
|
w: Math.round(
|
||||||
h: (collection.resolution.h / collection.size.h) * options.bb.h,
|
(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
|
// This layer's canvas
|
||||||
|
@ -166,7 +373,21 @@ const layers = {
|
||||||
options.after.canvas.after(canvas);
|
options.after.canvas.after(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here we set the context origin for using the black magic.
|
||||||
|
*/
|
||||||
const ctx = canvas.getContext("2d", options.ctxOptions);
|
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
|
// Path used for logging purposes
|
||||||
const _layerlogpath = key
|
const _layerlogpath = key
|
||||||
|
@ -177,9 +398,12 @@ const layers = {
|
||||||
_logpath: _layerlogpath,
|
_logpath: _layerlogpath,
|
||||||
_collection: collection,
|
_collection: collection,
|
||||||
|
|
||||||
|
bb: new BoundingBox(options.bb),
|
||||||
|
resolution: new Size(options.resolution),
|
||||||
id,
|
id,
|
||||||
key,
|
key,
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
full,
|
||||||
|
|
||||||
state: new Proxy(
|
state: new Proxy(
|
||||||
{visible: true},
|
{visible: true},
|
||||||
|
@ -195,10 +419,71 @@ 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 */
|
/** Our canvas */
|
||||||
canvas,
|
canvas,
|
||||||
ctx,
|
ctx,
|
||||||
|
|
||||||
|
_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)
|
* Moves this layer to another level (after given layer)
|
||||||
*
|
*
|
||||||
|
@ -224,8 +509,10 @@ const layers = {
|
||||||
* @param {number} y Y coordinate of the top left of the canvas
|
* @param {number} y Y coordinate of the top left of the canvas
|
||||||
*/
|
*/
|
||||||
moveTo(x, y) {
|
moveTo(x, y) {
|
||||||
canvas.style.left = `${x}px`;
|
this.bb.x = x;
|
||||||
canvas.style.top = `${y}px`;
|
this.bb.y = y;
|
||||||
|
this.canvas.style.left = `${x}px`;
|
||||||
|
this.canvas.style.top = `${y}px`;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -241,6 +528,8 @@ const layers = {
|
||||||
canvas.height = Math.round(
|
canvas.height = Math.round(
|
||||||
options.resolution.h * (h / options.bb.h)
|
options.resolution.h * (h / options.bb.h)
|
||||||
);
|
);
|
||||||
|
this.bb.w = w;
|
||||||
|
this.bb.h = h;
|
||||||
canvas.style.width = `${w}px`;
|
canvas.style.width = `${w}px`;
|
||||||
canvas.style.height = `${h}px`;
|
canvas.style.height = `${h}px`;
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,19 @@
|
||||||
* @property {number} y - y coordinate
|
* @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
|
* Represents a simple bouding box
|
||||||
*/
|
*/
|
||||||
|
@ -288,14 +301,19 @@ function cropCanvas(sourceCanvas, options = {}) {
|
||||||
|
|
||||||
const w = sourceCanvas.width;
|
const w = sourceCanvas.width;
|
||||||
const h = sourceCanvas.height;
|
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.getImageData(offset.x, offset.y, w, h);
|
||||||
/** @type {BoundingBox} */
|
/** @type {BoundingBox} */
|
||||||
const bb = new BoundingBox();
|
const bb = new BoundingBox();
|
||||||
|
|
||||||
let minx = w;
|
let minx = Infinity;
|
||||||
let maxx = -1;
|
let maxx = -Infinity;
|
||||||
let miny = h;
|
let miny = Infinity;
|
||||||
let maxy = -1;
|
let maxy = -Infinity;
|
||||||
|
|
||||||
for (let y = 0; y < h; y++) {
|
for (let y = 0; y < h; y++) {
|
||||||
for (let x = 0; x < w; x++) {
|
for (let x = 0; x < w; x++) {
|
||||||
|
@ -303,10 +321,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
|
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
|
//this part i get, this is checking that 4th RGBA byte for opacity
|
||||||
if (imageData.data[index + 3] > 0) {
|
if (imageData.data[index + 3] > 0) {
|
||||||
minx = Math.min(minx, x);
|
minx = Math.min(minx, x + offset.x);
|
||||||
maxx = Math.max(maxx, x);
|
maxx = Math.max(maxx, x + offset.x);
|
||||||
miny = Math.min(miny, y);
|
miny = Math.min(miny, y + offset.y);
|
||||||
maxy = Math.max(maxy, y);
|
maxy = Math.max(maxy, y + offset.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,13 +298,23 @@ const uil = {
|
||||||
canvas.width = bb.w;
|
canvas.width = bb.w;
|
||||||
canvas.height = bb.h;
|
canvas.height = bb.h;
|
||||||
if (options.includeBg)
|
if (options.includeBg)
|
||||||
ctx.drawImage(bgLayer.canvas, bb.x, bb.y, bb.w, bb.h, 0, 0, bb.w, bb.h);
|
ctx.drawImage(
|
||||||
|
bgLayer.canvas,
|
||||||
|
bb.x + bgLayer.origin.x,
|
||||||
|
bb.y + bgLayer.origin.y,
|
||||||
|
bb.w,
|
||||||
|
bb.h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
bb.w,
|
||||||
|
bb.h
|
||||||
|
);
|
||||||
this.layers.forEach((layer) => {
|
this.layers.forEach((layer) => {
|
||||||
if (!layer.hidden)
|
if (!layer.hidden)
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
layer.layer.canvas,
|
layer.layer.canvas,
|
||||||
bb.x,
|
bb.x + layer.layer.origin.x,
|
||||||
bb.y,
|
bb.y + layer.layer.origin.y,
|
||||||
bb.w,
|
bb.w,
|
||||||
bb.h,
|
bb.h,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -41,7 +41,7 @@ const colorBrushTool = () =>
|
||||||
"Color Brush",
|
"Color Brush",
|
||||||
(state, opt) => {
|
(state, opt) => {
|
||||||
// Draw new cursor immediately
|
// Draw new cursor immediately
|
||||||
uiCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
uiCtx.clearRect(0, 0, uiCanvas.width, uiCanvas.height);
|
||||||
state.movecb({
|
state.movecb({
|
||||||
...mouse.coords.world.pos,
|
...mouse.coords.world.pos,
|
||||||
evn: {
|
evn: {
|
||||||
|
@ -64,11 +64,11 @@ const colorBrushTool = () =>
|
||||||
after: imgLayer,
|
after: imgLayer,
|
||||||
ctxOptions: {willReadFrequently: true},
|
ctxOptions: {willReadFrequently: true},
|
||||||
});
|
});
|
||||||
|
state.drawLayer.canvas.style.filter = "opacity(70%)";
|
||||||
state.eraseLayer = imageCollection.registerLayer(null, {
|
state.eraseLayer = imageCollection.registerLayer(null, {
|
||||||
after: imgLayer,
|
after: imgLayer,
|
||||||
ctxOptions: {willReadFrequently: true},
|
ctxOptions: {willReadFrequently: true},
|
||||||
});
|
});
|
||||||
state.eraseLayer.canvas.style.display = "none";
|
|
||||||
state.eraseLayer.hide();
|
state.eraseLayer.hide();
|
||||||
state.eraseBackup = imageCollection.registerLayer(null, {
|
state.eraseBackup = imageCollection.registerLayer(null, {
|
||||||
after: imgLayer,
|
after: imgLayer,
|
||||||
|
@ -209,7 +209,7 @@ const colorBrushTool = () =>
|
||||||
state.brushSize -
|
state.brushSize -
|
||||||
Math.floor(state.config.brushScrollSpeed * evn.delta)
|
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);
|
state.movecb(evn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -231,12 +231,8 @@ const colorBrushTool = () =>
|
||||||
state.keyupcb = (evn) => {
|
state.keyupcb = (evn) => {
|
||||||
switch (evn.code) {
|
switch (evn.code) {
|
||||||
case "ShiftLeft":
|
case "ShiftLeft":
|
||||||
if (!keyboard.isPressed("ShiftRight")) {
|
|
||||||
state.disableDropper();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ShiftRight":
|
case "ShiftRight":
|
||||||
if (!keyboard.isPressed("ShiftLeft")) {
|
if (!keyboard.isPressed(evn.code)) {
|
||||||
state.disableDropper();
|
state.disableDropper();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -286,8 +282,9 @@ const colorBrushTool = () =>
|
||||||
const canvas = state.drawLayer.canvas;
|
const canvas = state.drawLayer.canvas;
|
||||||
const ctx = state.drawLayer.ctx;
|
const ctx = state.drawLayer.ctx;
|
||||||
|
|
||||||
const cropped = cropCanvas(canvas, {border: 10});
|
const cropped = cropCanvas(canvas, {border: 10, origin: uil.origin});
|
||||||
const bb = cropped.bb;
|
const bb = cropped.bb;
|
||||||
|
|
||||||
commands.runCommand("drawImage", "Color Brush Draw", {
|
commands.runCommand("drawImage", "Color Brush Draw", {
|
||||||
image: cropped.canvas,
|
image: cropped.canvas,
|
||||||
...bb,
|
...bb,
|
||||||
|
@ -302,10 +299,9 @@ const colorBrushTool = () =>
|
||||||
if (state.affectMask) _mask_brush_erase_callback(evn, state);
|
if (state.affectMask) _mask_brush_erase_callback(evn, state);
|
||||||
|
|
||||||
// Make a backup of the current image to apply erase later
|
// Make a backup of the current image to apply erase later
|
||||||
const bkpcanvas = state.eraseBackup.canvas;
|
|
||||||
const bkpctx = state.eraseBackup.ctx;
|
const bkpctx = state.eraseBackup.ctx;
|
||||||
bkpctx.clearRect(0, 0, bkpcanvas.width, bkpcanvas.height);
|
state.eraseBackup.clear();
|
||||||
bkpctx.drawImage(uil.canvas, 0, 0);
|
bkpctx.drawImageRoot(uil.canvas, 0, 0);
|
||||||
|
|
||||||
uil.ctx.globalCompositeOperation = "destination-out";
|
uil.ctx.globalCompositeOperation = "destination-out";
|
||||||
_color_brush_erase_callback(evn, state, uil.ctx);
|
_color_brush_erase_callback(evn, state, uil.ctx);
|
||||||
|
@ -335,8 +331,8 @@ const colorBrushTool = () =>
|
||||||
const bb = cropped.bb;
|
const bb = cropped.bb;
|
||||||
|
|
||||||
uil.ctx.filter = null;
|
uil.ctx.filter = null;
|
||||||
uil.ctx.clearRect(0, 0, uil.canvas.width, uil.canvas.height);
|
uil.layer.clear();
|
||||||
uil.ctx.drawImage(bkpcanvas, 0, 0);
|
uil.ctx.drawImageRoot(bkpcanvas, 0, 0);
|
||||||
|
|
||||||
commands.runCommand("eraseImage", "Color Brush Erase", {
|
commands.runCommand("eraseImage", "Color Brush Erase", {
|
||||||
mask: cropped.canvas,
|
mask: cropped.canvas,
|
||||||
|
|
|
@ -318,7 +318,7 @@ const _generate = async (endpoint, request, bb, options = {}) => {
|
||||||
ctx.drawImage(keepUnmaskCanvas, 0, 0);
|
ctx.drawImage(keepUnmaskCanvas, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
layer.clear();
|
||||||
layer.ctx.drawImage(
|
layer.ctx.drawImage(
|
||||||
canvas,
|
canvas,
|
||||||
0,
|
0,
|
||||||
|
@ -765,8 +765,8 @@ const dream_generate_callback = async (bb, resolution, state) => {
|
||||||
bbCtx.globalCompositeOperation = "destination-in";
|
bbCtx.globalCompositeOperation = "destination-in";
|
||||||
bbCtx.drawImage(
|
bbCtx.drawImage(
|
||||||
maskPaintCanvas,
|
maskPaintCanvas,
|
||||||
bb.x,
|
bb.x + maskPaintLayer.origin.x,
|
||||||
bb.y,
|
bb.y + maskPaintLayer.origin.y,
|
||||||
bb.w,
|
bb.w,
|
||||||
bb.h,
|
bb.h,
|
||||||
0,
|
0,
|
||||||
|
@ -793,8 +793,8 @@ const dream_generate_callback = async (bb, resolution, state) => {
|
||||||
bbCtx.globalCompositeOperation = "destination-out"; // ???
|
bbCtx.globalCompositeOperation = "destination-out"; // ???
|
||||||
bbCtx.drawImage(
|
bbCtx.drawImage(
|
||||||
maskPaintCanvas,
|
maskPaintCanvas,
|
||||||
bb.x,
|
bb.x + maskPaintLayer.origin.x,
|
||||||
bb.y,
|
bb.y + maskPaintLayer.origin.y,
|
||||||
bb.w,
|
bb.w,
|
||||||
bb.h,
|
bb.h,
|
||||||
0,
|
0,
|
||||||
|
@ -915,7 +915,17 @@ const dream_img2img_callback = (bb, resolution, state) => {
|
||||||
bbCtx.fillStyle = state.invertMask ? "#FFFF" : "#000F";
|
bbCtx.fillStyle = state.invertMask ? "#FFFF" : "#000F";
|
||||||
bbCtx.fillRect(0, 0, bb.w, bb.h);
|
bbCtx.fillRect(0, 0, bb.w, bb.h);
|
||||||
bbCtx.globalCompositeOperation = "destination-out";
|
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.globalCompositeOperation = "destination-atop";
|
||||||
bbCtx.fillStyle = state.invertMask ? "#000F" : "#FFFF";
|
bbCtx.fillStyle = state.invertMask ? "#000F" : "#FFFF";
|
||||||
|
|
|
@ -240,12 +240,7 @@ const maskBrushTool = () =>
|
||||||
clearMaskButton.textContent = "Clear";
|
clearMaskButton.textContent = "Clear";
|
||||||
clearMaskButton.title = "Clears Painted Mask";
|
clearMaskButton.title = "Clears Painted Mask";
|
||||||
clearMaskButton.onclick = () => {
|
clearMaskButton.onclick = () => {
|
||||||
maskPaintCtx.clearRect(
|
maskPaintLayer.clear();
|
||||||
0,
|
|
||||||
0,
|
|
||||||
maskPaintCanvas.width,
|
|
||||||
maskPaintCanvas.height
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const previewMaskButton = document.createElement("button");
|
const previewMaskButton = document.createElement("button");
|
||||||
|
|
|
@ -6,7 +6,7 @@ const stampTool = () =>
|
||||||
state.loaded = true;
|
state.loaded = true;
|
||||||
|
|
||||||
// Draw new cursor immediately
|
// Draw new cursor immediately
|
||||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
ovLayer.clear();
|
||||||
state.movecb({...mouse.coords.world.pos});
|
state.movecb({...mouse.coords.world.pos});
|
||||||
|
|
||||||
// Start Listeners
|
// Start Listeners
|
||||||
|
@ -47,7 +47,7 @@ const stampTool = () =>
|
||||||
child.classList.remove("active");
|
child.classList.remove("active");
|
||||||
});
|
});
|
||||||
|
|
||||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
ovLayer.clear();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
init: (state) => {
|
init: (state) => {
|
||||||
|
@ -88,7 +88,7 @@ const stampTool = () =>
|
||||||
state.selected = null;
|
state.selected = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
ovLayer.clear();
|
||||||
if (state.loaded) state.movecb(state.lastMouseMove);
|
if (state.loaded) state.movecb(state.lastMouseMove);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ const stampTool = () =>
|
||||||
|
|
||||||
state.lastMouseMove = evn;
|
state.lastMouseMove = evn;
|
||||||
|
|
||||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
ovLayer.clear();
|
||||||
|
|
||||||
// Draw selected image
|
// Draw selected image
|
||||||
if (state.selected) {
|
if (state.selected) {
|
||||||
|
|
Loading…
Reference in a new issue