Merge pull request #43 from seijihariki/input-rework-2
non-broken version on input-rework Former-commit-id: 44ae64a42f7bb11520e4e29180be4a67f2814b50
This commit is contained in:
commit
da95542c34
8 changed files with 548 additions and 376 deletions
|
@ -2,6 +2,7 @@
|
|||
--c-primary: #2c3333;
|
||||
--c-hover: hsl(180, 7%, 30%);
|
||||
--c-active: hsl(180, 7%, 25%);
|
||||
--c-primary-accent: hsl(180, 7%, 40%);
|
||||
--c-secondary: #395b64;
|
||||
--c-accent: #a5c9ca;
|
||||
--c-text: #e7f6f2;
|
||||
|
|
|
@ -30,3 +30,68 @@
|
|||
.draggable {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
/* Slider Input */
|
||||
div.slider-wrapper {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
div.slider-wrapper {
|
||||
position: relative;
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
div.slider-wrapper * {
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.slider-wrapper > * {
|
||||
position: absolute;
|
||||
padding: inherit;
|
||||
width: 100%;
|
||||
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.slider-wrapper > div.under {
|
||||
display: flex;
|
||||
background-color: var(--c-primary-accent);
|
||||
}
|
||||
div.slider-wrapper > div.under > div:first-child {
|
||||
background-color: var(--c-primary);
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
div.slider-wrapper > div.under > div:last-child {
|
||||
flex: 1;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
div.slider-wrapper > div.under > * {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div.slider-wrapper > div.over {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.slider-wrapper > input.text {
|
||||
color: var(--c-text);
|
||||
|
||||
flex: 1;
|
||||
appearance: textfield;
|
||||
border: 0px;
|
||||
|
||||
padding-top: 5px;
|
||||
height: 15px;
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
|
67
index.html
67
index.html
|
@ -68,66 +68,19 @@ people, person, humans, human, divers, diver, glitch, error, text, watermark, ba
|
|||
value="-1"
|
||||
step="1" />
|
||||
<br />
|
||||
<label for="steps">
|
||||
Steps:
|
||||
<input type="number" id="stepsTxt" />
|
||||
</label>
|
||||
<br />
|
||||
<input type="range" id="steps" name="steps" min="1" max="50" />
|
||||
<br />
|
||||
<label for="cfgScale">
|
||||
CFG scale:
|
||||
<input type="number" id="cfgScaleTxt" />
|
||||
</label>
|
||||
<br />
|
||||
<input
|
||||
type="range"
|
||||
id="cfgScale"
|
||||
name="cfgScale"
|
||||
min="-1"
|
||||
max="25"
|
||||
step="0.5" />
|
||||
<br />
|
||||
<label for="batchSize">
|
||||
Batch size:
|
||||
<input type="number" id="batchSizeText" />
|
||||
</label>
|
||||
<br />
|
||||
<input
|
||||
type="range"
|
||||
id="batchSize"
|
||||
name="batchSize"
|
||||
min="1"
|
||||
max="8"
|
||||
step="1" />
|
||||
<br />
|
||||
<label for="batchCount">
|
||||
Batch count:
|
||||
<input type="number" id="batchCountText" />
|
||||
</label>
|
||||
<br />
|
||||
<input
|
||||
type="range"
|
||||
id="batchCount"
|
||||
name="batchCount"
|
||||
min="1"
|
||||
max="8"
|
||||
step="1" />
|
||||
<br />
|
||||
<hr />
|
||||
<div id="steps"></div>
|
||||
<div id="cfgScale"></div>
|
||||
<div id="batchSize"></div>
|
||||
<div id="batchCount"></div>
|
||||
</div>
|
||||
<!-- Unsectioned -->
|
||||
<label for="scaleFactor">
|
||||
Scale factor:
|
||||
<input type="number" id="scaleFactorTxt" />
|
||||
</label>
|
||||
<br />
|
||||
<div id="scaleFactor"></div>
|
||||
<label for="cbxSnap">Snap to grid?</label>
|
||||
<input
|
||||
type="range"
|
||||
id="scaleFactor"
|
||||
name="scaleFactor"
|
||||
min="1"
|
||||
max="16" />
|
||||
type="checkbox"
|
||||
id="cbxSnap"
|
||||
onchange="changeSnapMode()"
|
||||
checked="checked" />
|
||||
<br />
|
||||
<input type="checkbox" id="cbxHRFix" onchange="changeHiResFix()" />
|
||||
<label for="cbxHRFix">Auto txt2img HRfix</label>
|
||||
|
|
152
js/index.js
152
js/index.js
|
@ -47,62 +47,6 @@ var stableDiffusionData = {
|
|||
// "include_init_images": false // ??????
|
||||
};
|
||||
|
||||
/**
|
||||
* Some Utility Functions
|
||||
*/
|
||||
function sliderChangeHandlerFactory(
|
||||
sliderId,
|
||||
textBoxId,
|
||||
dataKey,
|
||||
defaultV,
|
||||
save = true,
|
||||
setter = (k, v) => (stableDiffusionData[k] = v),
|
||||
getter = (k) => stableDiffusionData[k]
|
||||
) {
|
||||
return sliderChangeHandlerFactoryEl(
|
||||
document.getElementById(sliderId),
|
||||
document.getElementById(textBoxId),
|
||||
dataKey,
|
||||
defaultV,
|
||||
save,
|
||||
setter,
|
||||
getter
|
||||
);
|
||||
}
|
||||
|
||||
function sliderChangeHandlerFactoryEl(
|
||||
sliderEl,
|
||||
textBoxEl,
|
||||
dataKey,
|
||||
defaultV,
|
||||
save = true,
|
||||
setter = (k, v) => (stableDiffusionData[k] = v),
|
||||
getter = (k) => stableDiffusionData[k]
|
||||
) {
|
||||
const savedValue = save && localStorage.getItem(dataKey);
|
||||
|
||||
if (savedValue) setter(dataKey, savedValue || defaultV);
|
||||
|
||||
function changeHandler(evn) {
|
||||
const eventSource = evn && evn.srcElement;
|
||||
const value = eventSource && Number(eventSource.value);
|
||||
|
||||
if (value) setter(dataKey, value);
|
||||
|
||||
if (!eventSource || eventSource === textBoxEl)
|
||||
sliderEl.value = getter(dataKey);
|
||||
setter(dataKey, Number(sliderEl.value));
|
||||
textBoxEl.value = getter(dataKey);
|
||||
|
||||
if (save) localStorage.setItem(dataKey, getter(dataKey));
|
||||
}
|
||||
|
||||
textBoxEl.onchange = changeHandler;
|
||||
sliderEl.oninput = changeHandler;
|
||||
|
||||
return changeHandler;
|
||||
}
|
||||
|
||||
// stuff things use
|
||||
var blockNewImages = false;
|
||||
var returnedImages;
|
||||
|
@ -175,12 +119,8 @@ function startup() {
|
|||
getUpscalers();
|
||||
getModels();
|
||||
drawBackground();
|
||||
changeScaleFactor();
|
||||
changeSampler();
|
||||
changeSteps();
|
||||
changeCfgScale();
|
||||
changeBatchCount();
|
||||
changeBatchSize();
|
||||
changeSnapMode();
|
||||
changeMaskBlur();
|
||||
changeSeed();
|
||||
changeOverMaskPx();
|
||||
|
@ -542,39 +482,77 @@ function changeSampler() {
|
|||
}
|
||||
}
|
||||
|
||||
const changeCfgScale = sliderChangeHandlerFactory(
|
||||
"cfgScale",
|
||||
"cfgScaleTxt",
|
||||
const makeSlider = (
|
||||
label,
|
||||
el,
|
||||
lsKey,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
defaultValue,
|
||||
valuecb = null
|
||||
) => {
|
||||
const local = localStorage.getItem(lsKey);
|
||||
const def = parseFloat(local === null ? defaultValue : local);
|
||||
return createSlider(label, el, {
|
||||
valuecb:
|
||||
valuecb ||
|
||||
((v) => {
|
||||
stableDiffusionData[lsKey] = v;
|
||||
localStorage.setItem(lsKey, v);
|
||||
}),
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
defaultValue: def,
|
||||
});
|
||||
};
|
||||
|
||||
makeSlider(
|
||||
"CFG Scale",
|
||||
document.getElementById("cfgScale"),
|
||||
"cfg_scale",
|
||||
-1,
|
||||
25,
|
||||
0.5,
|
||||
7.0
|
||||
);
|
||||
const changeBatchSize = sliderChangeHandlerFactory(
|
||||
"batchSize",
|
||||
"batchSizeText",
|
||||
makeSlider(
|
||||
"Batch Size",
|
||||
document.getElementById("batchSize"),
|
||||
"batch_size",
|
||||
2
|
||||
);
|
||||
const changeBatchCount = sliderChangeHandlerFactory(
|
||||
"batchCount",
|
||||
"batchCountText",
|
||||
"n_iter",
|
||||
2
|
||||
);
|
||||
const changeScaleFactor = sliderChangeHandlerFactory(
|
||||
"scaleFactor",
|
||||
"scaleFactorTxt",
|
||||
"scaleFactor",
|
||||
1,
|
||||
8,
|
||||
true,
|
||||
(k, v) => (scaleFactor = v),
|
||||
(k) => scaleFactor
|
||||
1,
|
||||
2
|
||||
);
|
||||
const changeSteps = sliderChangeHandlerFactory(
|
||||
"steps",
|
||||
"stepsTxt",
|
||||
"steps",
|
||||
30
|
||||
makeSlider(
|
||||
"Iterations",
|
||||
document.getElementById("batchCount"),
|
||||
"n_iter",
|
||||
1,
|
||||
8,
|
||||
1,
|
||||
2
|
||||
);
|
||||
makeSlider(
|
||||
"Scale Factor",
|
||||
document.getElementById("scaleFactor"),
|
||||
"scale_factor",
|
||||
1,
|
||||
16,
|
||||
1,
|
||||
8,
|
||||
(v) => {
|
||||
scaleFactor = v;
|
||||
}
|
||||
);
|
||||
|
||||
makeSlider("Steps", document.getElementById("steps"), "steps", 1, 70, 1, 30);
|
||||
|
||||
function changeSnapMode() {
|
||||
snapToGrid = document.getElementById("cbxSnap").checked;
|
||||
}
|
||||
|
||||
function changeMaskBlur() {
|
||||
stableDiffusionData.mask_blur = document.getElementById("maskBlur").value;
|
||||
|
|
449
js/input.js
449
js/input.js
|
@ -3,32 +3,13 @@ const inputConfig = {
|
|||
clickTiming: 500, // Timing window to be considered a click (ms). If longer, turns into a drag
|
||||
dClickTiming: 500, // Timing window to be considered a double click (ms).
|
||||
|
||||
keyboardHoldTiming: 100, // Timing window after which to consider holding a key (ms)
|
||||
keyboardHoldTiming: 1000, // Timing window after which to consider holding a key (ms)
|
||||
};
|
||||
|
||||
/**
|
||||
* Mouse input processing
|
||||
*/
|
||||
// Base object generator functions
|
||||
function _context_coords() {
|
||||
return {
|
||||
dragging: {
|
||||
left: null,
|
||||
middle: null,
|
||||
right: null,
|
||||
},
|
||||
|
||||
prev: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
|
||||
pos: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
function _mouse_observers() {
|
||||
return {
|
||||
// Simple click handler
|
||||
|
@ -46,229 +27,286 @@ function _mouse_observers() {
|
|||
};
|
||||
}
|
||||
|
||||
function _context_observers() {
|
||||
return {
|
||||
onwheel: new Observer(),
|
||||
onmousemove: new Observer(),
|
||||
left: _mouse_observers(),
|
||||
middle: _mouse_observers(),
|
||||
right: _mouse_observers(),
|
||||
};
|
||||
}
|
||||
|
||||
const mouse = {
|
||||
buttons: {
|
||||
right: null,
|
||||
left: null,
|
||||
middle: null,
|
||||
},
|
||||
contexts: [],
|
||||
buttons: {},
|
||||
coords: {},
|
||||
|
||||
// Mouse Actions in Window Coordinates
|
||||
window: _context_coords(),
|
||||
listen: {},
|
||||
|
||||
// Mouse Actions in Canvas Coordinates
|
||||
canvas: _context_coords(),
|
||||
// Register Context
|
||||
registerContext: (name, onmove, options = {}) => {
|
||||
// Options
|
||||
defaultOpt(options, {
|
||||
target: null,
|
||||
buttons: {0: "left", 1: "middle", 2: "right"},
|
||||
});
|
||||
|
||||
// Mouse Actions in World Coordinates
|
||||
world: _context_coords(),
|
||||
// Context information
|
||||
const context = {
|
||||
id: guid(),
|
||||
name,
|
||||
onmove,
|
||||
target: options.target,
|
||||
buttons: options.buttons,
|
||||
};
|
||||
|
||||
listen: {
|
||||
window: _context_observers(),
|
||||
canvas: _context_observers(),
|
||||
world: _context_observers(),
|
||||
// Coordinate information
|
||||
mouse.coords[name] = {
|
||||
dragging: {},
|
||||
|
||||
prev: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
|
||||
pos: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
};
|
||||
|
||||
// Listeners
|
||||
mouse.listen[name] = {
|
||||
onwheel: new Observer(),
|
||||
onmousemove: new Observer(),
|
||||
};
|
||||
|
||||
// Button specific items
|
||||
Object.keys(options.buttons).forEach((index) => {
|
||||
const button = options.buttons[index];
|
||||
mouse.coords[name].dragging[button] = null;
|
||||
mouse.listen[name][button] = _mouse_observers();
|
||||
});
|
||||
|
||||
// Add to context
|
||||
context.coords = mouse.coords[name];
|
||||
context.listen = mouse.listen[name];
|
||||
|
||||
// Add to list
|
||||
mouse.contexts.push(context);
|
||||
|
||||
return context;
|
||||
},
|
||||
};
|
||||
|
||||
function _mouse_state_snapshot() {
|
||||
return {
|
||||
buttons: window.structuredClone(mouse.buttons),
|
||||
window: window.structuredClone(mouse.window),
|
||||
canvas: window.structuredClone(mouse.canvas),
|
||||
world: window.structuredClone(mouse.world),
|
||||
};
|
||||
}
|
||||
|
||||
const _double_click_timeout = {};
|
||||
const _drag_start_timeout = {};
|
||||
|
||||
window.onmousedown = (evn) => {
|
||||
const time = new Date();
|
||||
const time = performance.now();
|
||||
|
||||
// Processes for a named button
|
||||
const onhold = (key) => () => {
|
||||
if (_double_click_timeout[key]) {
|
||||
// ondclick event
|
||||
["window", "canvas", "world"].forEach((ctx) =>
|
||||
mouse.listen[ctx][key].ondclick.emit({
|
||||
if (_double_click_timeout[evn.button]) {
|
||||
// ondclick event
|
||||
mouse.contexts.forEach(({target, name, buttons}) => {
|
||||
if ((!target || target === evn.target) && buttons[evn.button])
|
||||
mouse.listen[name][buttons[evn.button]].ondclick.emit({
|
||||
target: evn.target,
|
||||
buttonId: evn.button,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Start timer
|
||||
_double_click_timeout[key] = setTimeout(
|
||||
() => delete _double_click_timeout[key],
|
||||
inputConfig.dClickTiming
|
||||
);
|
||||
}
|
||||
|
||||
// Set drag start timeout
|
||||
_drag_start_timeout[key] = setTimeout(() => {
|
||||
["window", "canvas", "world"].forEach((ctx) => {
|
||||
mouse.listen[ctx][key].ondragstart.emit({
|
||||
target: evn.target,
|
||||
buttonId: evn.button,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: time,
|
||||
});
|
||||
if (mouse[ctx].dragging[key]) mouse[ctx].dragging[key].drag = true;
|
||||
});
|
||||
} else {
|
||||
// Start timer
|
||||
_double_click_timeout[evn.button] = setTimeout(
|
||||
() => delete _double_click_timeout[evn.button],
|
||||
inputConfig.dClickTiming
|
||||
);
|
||||
}
|
||||
|
||||
delete _drag_start_timeout[key];
|
||||
});
|
||||
}, inputConfig.clickTiming);
|
||||
// Set drag start timeout
|
||||
_drag_start_timeout[evn.button] = setTimeout(() => {
|
||||
mouse.contexts.forEach(({target, name, buttons}) => {
|
||||
const key = buttons[evn.button];
|
||||
if (
|
||||
(!target || target === evn.target) &&
|
||||
!mouse.coords[name].dragging[key].drag &&
|
||||
key
|
||||
) {
|
||||
mouse.listen[name][key].ondragstart.emit({
|
||||
target: evn.target,
|
||||
buttonId: evn.button,
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: time,
|
||||
});
|
||||
|
||||
["window", "canvas", "world"].forEach((ctx) => {
|
||||
mouse.buttons[key] = time;
|
||||
mouse[ctx].dragging[key] = {target: evn.target};
|
||||
Object.assign(mouse[ctx].dragging[key], mouse[ctx].pos);
|
||||
mouse.coords[name].dragging[key].drag = true;
|
||||
}
|
||||
});
|
||||
delete _drag_start_timeout[evn.button];
|
||||
}, inputConfig.clickTiming);
|
||||
|
||||
mouse.buttons[evn.button] = time;
|
||||
|
||||
mouse.contexts.forEach(({target, name, buttons}) => {
|
||||
const key = buttons[evn.button];
|
||||
if ((!target || target === evn.target) && key) {
|
||||
mouse.coords[name].dragging[key] = {};
|
||||
mouse.coords[name].dragging[key].target = evn.target;
|
||||
Object.assign(mouse.coords[name].dragging[key], mouse.coords[name].pos);
|
||||
|
||||
// onpaintstart event
|
||||
mouse.listen[ctx][key].onpaintstart.emit({
|
||||
mouse.listen[name][key].onpaintstart.emit({
|
||||
target: evn.target,
|
||||
buttonId: evn.button,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Runs the correct handler
|
||||
const buttons = [onhold("left"), onhold("middle"), onhold("right")];
|
||||
|
||||
buttons[evn.button] && buttons[evn.button]();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.onmouseup = (evn) => {
|
||||
const time = new Date();
|
||||
const time = performance.now();
|
||||
|
||||
// Processes for a named button
|
||||
const onrelease = (key) => () => {
|
||||
["window", "canvas", "world"].forEach((ctx) => {
|
||||
mouse.contexts.forEach(({target, name, buttons}) => {
|
||||
const key = buttons[evn.button];
|
||||
if (
|
||||
(!target || target === evn.target) &&
|
||||
key &&
|
||||
mouse.coords[name].dragging[key]
|
||||
) {
|
||||
const start = {
|
||||
x: mouse[ctx].dragging[key].x,
|
||||
y: mouse[ctx].dragging[key].y,
|
||||
x: mouse.coords[name].dragging[key].x,
|
||||
y: mouse.coords[name].dragging[key].y,
|
||||
};
|
||||
|
||||
// onclick event
|
||||
const dx = mouse[ctx].pos.x - start.x;
|
||||
const dy = mouse[ctx].pos.y - start.y;
|
||||
const dx = mouse.coords[name].pos.x - start.x;
|
||||
const dy = mouse.coords[name].pos.y - start.y;
|
||||
|
||||
if (
|
||||
time.getTime() - mouse.buttons[key].getTime() <
|
||||
inputConfig.clickTiming &&
|
||||
mouse.buttons[evn.button] &&
|
||||
time - mouse.buttons[evn.button] < inputConfig.clickTiming &&
|
||||
dx * dx + dy * dy < inputConfig.clickRadius * inputConfig.clickRadius
|
||||
)
|
||||
mouse.listen[ctx][key].onclick.emit({
|
||||
mouse.listen[name][key].onclick.emit({
|
||||
target: evn.target,
|
||||
buttonId: evn.button,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
|
||||
// onpaintend event
|
||||
mouse.listen[ctx][key].onpaintend.emit({
|
||||
mouse.listen[name][key].onpaintend.emit({
|
||||
target: evn.target,
|
||||
initialTarget: mouse[ctx].dragging[key].target,
|
||||
initialTarget: mouse.coords[name].dragging[key].target,
|
||||
buttonId: evn.button,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
|
||||
// ondragend event
|
||||
if (mouse[ctx].dragging[key].drag)
|
||||
mouse.listen[ctx][key].ondragend.emit({
|
||||
if (mouse.coords[name].dragging[key].drag)
|
||||
mouse.listen[name][key].ondragend.emit({
|
||||
target: evn.target,
|
||||
initialTarget: mouse[ctx].dragging[key].target,
|
||||
initialTarget: mouse.coords[name].dragging[key].target,
|
||||
buttonId: evn.button,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
|
||||
mouse[ctx].dragging[key] = null;
|
||||
});
|
||||
|
||||
if (_drag_start_timeout[key] !== undefined) {
|
||||
clearTimeout(_drag_start_timeout[key]);
|
||||
delete _drag_start_timeout[key];
|
||||
mouse.coords[name].dragging[key] = null;
|
||||
}
|
||||
mouse.buttons[key] = null;
|
||||
};
|
||||
});
|
||||
|
||||
// Runs the correct handler
|
||||
const buttons = [onrelease("left"), onrelease("middle"), onrelease("right")];
|
||||
|
||||
buttons[evn.button] && buttons[evn.button]();
|
||||
if (_drag_start_timeout[evn.button] !== undefined) {
|
||||
clearTimeout(_drag_start_timeout[evn.button]);
|
||||
delete _drag_start_timeout[evn.button];
|
||||
}
|
||||
mouse.buttons[evn.button] = null;
|
||||
};
|
||||
|
||||
window.onmousemove = (evn) => {
|
||||
// Set Window Coordinates
|
||||
Object.assign(mouse.window.prev, mouse.window.pos);
|
||||
mouse.window.pos = {x: evn.clientX, y: evn.clientY};
|
||||
mouse.contexts.forEach((context) => {
|
||||
const target = context.target;
|
||||
const name = context.name;
|
||||
|
||||
// Set Canvas Coordinates (using overlay canvas as reference)
|
||||
if (evn.target.id === "overlayCanvas") {
|
||||
Object.assign(mouse.canvas.prev, mouse.canvas.pos);
|
||||
mouse.canvas.pos = {x: evn.layerX, y: evn.layerY};
|
||||
}
|
||||
if (!target || target === evn.target) {
|
||||
context.onmove(evn, context);
|
||||
|
||||
// Set World Coordinates (For now the same as canvas coords; Will be useful with infinite canvas)
|
||||
if (evn.target.id === "overlayCanvas") {
|
||||
Object.assign(mouse.world.prev, mouse.world.pos);
|
||||
mouse.world.pos = {x: evn.layerX, y: evn.layerY};
|
||||
}
|
||||
mouse.listen[name].onmousemove.emit({
|
||||
target: evn.target,
|
||||
px: mouse.coords[name].prev.x,
|
||||
py: mouse.coords[name].prev.y,
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
|
||||
["window", "canvas", "world"].forEach((ctx) => {
|
||||
mouse.listen[ctx].onmousemove.emit({
|
||||
target: evn.target,
|
||||
px: mouse[ctx].prev.x,
|
||||
py: mouse[ctx].prev.y,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
["left", "middle", "right"].forEach((key) => {
|
||||
// ondrag event
|
||||
if (mouse[ctx].dragging[key] && mouse[ctx].dragging[key].drag)
|
||||
mouse.listen[ctx][key].ondrag.emit({
|
||||
target: evn.target,
|
||||
initialTarget: mouse[ctx].dragging[key].target,
|
||||
px: mouse[ctx].prev.x,
|
||||
py: mouse[ctx].prev.y,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
Object.keys(context.buttons).forEach((index) => {
|
||||
const key = context.buttons[index];
|
||||
// ondragstart event (2)
|
||||
if (mouse.coords[name].dragging[key]) {
|
||||
const dx =
|
||||
mouse.coords[name].pos.x - mouse.coords[name].dragging[key].x;
|
||||
const dy =
|
||||
mouse.coords[name].pos.y - mouse.coords[name].dragging[key].y;
|
||||
if (
|
||||
!mouse.coords[name].dragging[key].drag &&
|
||||
dx * dx + dy * dy >=
|
||||
inputConfig.clickRadius * inputConfig.clickRadius
|
||||
) {
|
||||
mouse.listen[name][key].ondragstart.emit({
|
||||
target: evn.target,
|
||||
buttonId: evn.button,
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
|
||||
// onpaint event
|
||||
if (mouse[ctx].dragging[key])
|
||||
mouse.listen[ctx][key].onpaint.emit({
|
||||
target: evn.target,
|
||||
initialTarget: mouse[ctx].dragging[key].target,
|
||||
px: mouse[ctx].prev.x,
|
||||
py: mouse[ctx].prev.y,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
});
|
||||
mouse.coords[name].dragging[key].drag = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ondrag event
|
||||
if (
|
||||
mouse.coords[name].dragging[key] &&
|
||||
mouse.coords[name].dragging[key].drag
|
||||
)
|
||||
mouse.listen[name][key].ondrag.emit({
|
||||
target: evn.target,
|
||||
initialTarget: mouse.coords[name].dragging[key].target,
|
||||
button: index,
|
||||
px: mouse.coords[name].prev.x,
|
||||
py: mouse.coords[name].prev.y,
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
|
||||
// onpaint event
|
||||
if (mouse.coords[name].dragging[key]) {
|
||||
mouse.listen[name][key].onpaint.emit({
|
||||
target: evn.target,
|
||||
initialTarget: mouse.coords[name].dragging[key].target,
|
||||
button: index,
|
||||
px: mouse.coords[name].prev.x,
|
||||
py: mouse.coords[name].prev.y,
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -276,22 +314,41 @@ window.addEventListener(
|
|||
"wheel",
|
||||
(evn) => {
|
||||
evn.preventDefault();
|
||||
["window", "canvas", "world"].forEach((ctx) => {
|
||||
mouse.listen[ctx].onwheel.emit({
|
||||
mouse.contexts.forEach(({name}) => {
|
||||
mouse.listen[name].onwheel.emit({
|
||||
target: evn.target,
|
||||
delta: evn.deltaY,
|
||||
deltaX: evn.deltaX,
|
||||
deltaY: evn.deltaY,
|
||||
deltaZ: evn.deltaZ,
|
||||
mode: evn.deltaMode,
|
||||
x: mouse[ctx].pos.x,
|
||||
y: mouse[ctx].pos.y,
|
||||
timestamp: new Date(),
|
||||
x: mouse.coords[name].pos.x,
|
||||
y: mouse.coords[name].pos.y,
|
||||
evn,
|
||||
timestamp: performance.now(),
|
||||
});
|
||||
});
|
||||
},
|
||||
{passive: false}
|
||||
);
|
||||
|
||||
mouse.registerContext("window", (evn, ctx) => {
|
||||
ctx.coords.prev.x = ctx.coords.pos.x;
|
||||
ctx.coords.prev.y = ctx.coords.pos.y;
|
||||
ctx.coords.pos.x = evn.clientX;
|
||||
ctx.coords.pos.y = evn.clientY;
|
||||
});
|
||||
|
||||
mouse.registerContext(
|
||||
"canvas",
|
||||
(evn, ctx) => {
|
||||
ctx.coords.prev.x = ctx.coords.pos.x;
|
||||
ctx.coords.prev.y = ctx.coords.pos.y;
|
||||
ctx.coords.pos.x = evn.layerX;
|
||||
ctx.coords.pos.y = evn.layerY;
|
||||
},
|
||||
document.getElementById("overlayCanvas")
|
||||
);
|
||||
/**
|
||||
* Keyboard input processing
|
||||
*/
|
||||
|
@ -342,7 +399,9 @@ const keyboard = {
|
|||
};
|
||||
|
||||
window.onkeydown = (evn) => {
|
||||
// onkeydown event
|
||||
keyboard.listen.onkeydown.emit({
|
||||
target: evn.target,
|
||||
code: evn.code,
|
||||
key: evn.key,
|
||||
evn,
|
||||
|
@ -354,7 +413,9 @@ window.onkeydown = (evn) => {
|
|||
_hold_to: setTimeout(() => {
|
||||
keyboard.keys[evn.code].held = true;
|
||||
delete keyboard.keys[evn.code]._hold_to;
|
||||
// onkeyholdstart event
|
||||
keyboard.listen.onkeyholdstart.emit({
|
||||
target: evn.target,
|
||||
code: evn.code,
|
||||
key: evn.key,
|
||||
evn,
|
||||
|
@ -383,7 +444,9 @@ window.onkeydown = (evn) => {
|
|||
!!callback.alt === evn.altKey &&
|
||||
!!callback.shift === evn.shiftKey
|
||||
) {
|
||||
// onshortcut event
|
||||
keyboard.listen.onshortcut.emit({
|
||||
target: evn.target,
|
||||
code: evn.code,
|
||||
key: evn.key,
|
||||
id: callback.id,
|
||||
|
@ -395,19 +458,25 @@ window.onkeydown = (evn) => {
|
|||
};
|
||||
|
||||
window.onkeyup = (evn) => {
|
||||
// onkeyup event
|
||||
keyboard.listen.onkeyup.emit({
|
||||
target: evn.target,
|
||||
code: evn.code,
|
||||
key: evn.key,
|
||||
evn,
|
||||
});
|
||||
if (keyboard.keys[evn.code] && keyboard.keys[evn.code].held) {
|
||||
// onkeyholdend event
|
||||
keyboard.listen.onkeyholdend.emit({
|
||||
target: evn.target,
|
||||
code: evn.code,
|
||||
key: evn.key,
|
||||
evn,
|
||||
});
|
||||
} else {
|
||||
// onkeyclick event
|
||||
keyboard.listen.onkeyclick.emit({
|
||||
target: evn.target,
|
||||
code: evn.code,
|
||||
key: evn.key,
|
||||
evn,
|
||||
|
|
|
@ -46,3 +46,113 @@ for (var i = 0; i < coll.length; i++) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Slider Inputs
|
||||
*/
|
||||
function createSlider(name, wrapper, options = {}) {
|
||||
defaultOpt(options, {
|
||||
valuecb: null,
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
defaultValue: 0.7,
|
||||
});
|
||||
|
||||
let value = options.defaultValue;
|
||||
|
||||
// Use phantom range element for rounding
|
||||
const phantomRange = document.createElement("input");
|
||||
phantomRange.type = "range";
|
||||
phantomRange.min = options.min;
|
||||
phantomRange.max = options.max;
|
||||
phantomRange.step = options.step;
|
||||
|
||||
// Build slider element
|
||||
const underEl = document.createElement("div");
|
||||
underEl.classList.add("under");
|
||||
const textEl = document.createElement("input");
|
||||
textEl.type = "text";
|
||||
textEl.classList.add("text");
|
||||
|
||||
const overEl = document.createElement("div");
|
||||
overEl.classList.add("over");
|
||||
|
||||
wrapper.classList.add("slider-wrapper");
|
||||
wrapper.appendChild(underEl);
|
||||
wrapper.appendChild(textEl);
|
||||
wrapper.appendChild(overEl);
|
||||
|
||||
const bar = document.createElement("div");
|
||||
bar.classList.add("slider-bar");
|
||||
underEl.appendChild(bar);
|
||||
underEl.appendChild(document.createElement("div"));
|
||||
|
||||
// Set value
|
||||
const setValue = (val) => {
|
||||
phantomRange.value = val;
|
||||
value = parseFloat(phantomRange.value);
|
||||
bar.style.width = `${
|
||||
wrapper.offsetWidth *
|
||||
((value - options.min) / (options.max - options.min))
|
||||
}px`;
|
||||
textEl.value = `${name}: ${value}`;
|
||||
options.valuecb && options.valuecb(value);
|
||||
};
|
||||
|
||||
setValue(options.defaultValue);
|
||||
|
||||
// Events
|
||||
textEl.addEventListener("blur", () => {
|
||||
overEl.style.pointerEvents = "auto";
|
||||
textEl.value = `${name}: ${value}`;
|
||||
});
|
||||
textEl.addEventListener("focus", () => {
|
||||
textEl.value = value;
|
||||
});
|
||||
|
||||
textEl.addEventListener("change", () => {
|
||||
try {
|
||||
if (Number.isNaN(parseFloat(textEl.value))) setValue(value);
|
||||
else setValue(parseFloat(textEl.value));
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
keyboard.listen.onkeyclick.on((evn) => {
|
||||
if (evn.target === textEl && evn.code === "Enter") {
|
||||
textEl.blur();
|
||||
}
|
||||
});
|
||||
|
||||
mouse.listen.window.left.onclick.on((evn) => {
|
||||
if (evn.target === overEl) {
|
||||
overEl.style.pointerEvents = "none";
|
||||
textEl.select();
|
||||
}
|
||||
});
|
||||
|
||||
mouse.listen.window.left.ondrag.on((evn) => {
|
||||
if (evn.target === overEl) {
|
||||
setValue(
|
||||
Math.max(
|
||||
options.min,
|
||||
Math.min(
|
||||
options.max,
|
||||
(evn.evn.layerX / wrapper.offsetWidth) *
|
||||
(options.max - options.min) +
|
||||
options.min
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
set value(val) {
|
||||
setValue(val);
|
||||
},
|
||||
get value() {
|
||||
return value;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -135,42 +135,22 @@ const _toolbar_input = {
|
|||
},
|
||||
|
||||
slider: (state, dataKey, text, min = 0, max = 1, step = 0.1) => {
|
||||
const slider = document.createElement("input");
|
||||
slider.type = "range";
|
||||
slider.max = max;
|
||||
slider.step = step;
|
||||
slider.min = min;
|
||||
slider.value = state[dataKey];
|
||||
const slider = document.createElement("div");
|
||||
|
||||
const textEl = document.createElement("input");
|
||||
textEl.type = "number";
|
||||
textEl.value = state[dataKey];
|
||||
|
||||
console.log(state[dataKey]);
|
||||
|
||||
sliderChangeHandlerFactoryEl(
|
||||
slider,
|
||||
textEl,
|
||||
dataKey,
|
||||
state[dataKey],
|
||||
false,
|
||||
(k, v) => (state[dataKey] = v),
|
||||
(k) => state[dataKey]
|
||||
);
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.appendChild(new Text(text));
|
||||
label.appendChild(textEl);
|
||||
label.appendChild(slider);
|
||||
const value = createSlider(text, slider, {
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
valuecb: (v) => {
|
||||
state[dataKey] = v;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
slider,
|
||||
text: textEl,
|
||||
label,
|
||||
setValue(v) {
|
||||
slider.value = v;
|
||||
textEl.value = slider.value;
|
||||
return parseInt(slider.value);
|
||||
value.value = v;
|
||||
return value.value;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@ -206,7 +186,10 @@ tools.dream = toolbar.registerTool(
|
|||
(state, opt) => {
|
||||
// Draw new cursor immediately
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
state.mousemovecb({...mouse.canvas.pos, target: {id: "overlayCanvas"}});
|
||||
state.mousemovecb({
|
||||
...mouse.coords.canvas.pos,
|
||||
target: {id: "overlayCanvas"},
|
||||
});
|
||||
|
||||
// Start Listeners
|
||||
mouse.listen.canvas.onmousemove.on(state.mousemovecb);
|
||||
|
@ -261,7 +244,10 @@ tools.img2img = toolbar.registerTool(
|
|||
(state, opt) => {
|
||||
// Draw new cursor immediately
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
state.mousemovecb({...mouse.canvas.pos, target: {id: "overlayCanvas"}});
|
||||
state.mousemovecb({
|
||||
...mouse.coords.canvas.pos,
|
||||
target: {id: "overlayCanvas"},
|
||||
});
|
||||
|
||||
// Start Listeners
|
||||
mouse.listen.canvas.onmousemove.on(state.mousemovecb);
|
||||
|
@ -337,17 +323,17 @@ tools.img2img = toolbar.registerTool(
|
|||
).label;
|
||||
|
||||
// Denoising Strength Slider
|
||||
state.ctxmenu.denoisingStrengthLabel = _toolbar_input.slider(
|
||||
state.ctxmenu.denoisingStrengthSlider = _toolbar_input.slider(
|
||||
state,
|
||||
"denoisingStrength",
|
||||
"Denoising Strength",
|
||||
0,
|
||||
1,
|
||||
0.05
|
||||
).label;
|
||||
).slider;
|
||||
|
||||
// Use Border Mask Checkbox
|
||||
state.ctxmenu.useBorderMaskLabel = _toolbar_input.checkbox(
|
||||
state.ctxmenu.useBorderMaskSlider = _toolbar_input.checkbox(
|
||||
state,
|
||||
"useBorderMask",
|
||||
"Use Border Mask"
|
||||
|
@ -360,16 +346,16 @@ tools.img2img = toolbar.registerTool(
|
|||
0,
|
||||
128,
|
||||
1
|
||||
).label;
|
||||
).slider;
|
||||
}
|
||||
|
||||
menu.appendChild(state.ctxmenu.snapToGridLabel);
|
||||
menu.appendChild(document.createElement("br"));
|
||||
menu.appendChild(state.ctxmenu.denoisingStrengthLabel);
|
||||
menu.appendChild(state.ctxmenu.denoisingStrengthSlider);
|
||||
menu.appendChild(document.createElement("br"));
|
||||
menu.appendChild(state.ctxmenu.useBorderMaskLabel);
|
||||
menu.appendChild(document.createElement("br"));
|
||||
menu.appendChild(state.ctxmenu.borderMaskSize);
|
||||
menu.appendChild(state.ctxmenu.borderMaskSlider);
|
||||
},
|
||||
shortcut: "I",
|
||||
}
|
||||
|
@ -389,7 +375,7 @@ tools.maskbrush = toolbar.registerTool(
|
|||
(state, opt) => {
|
||||
// Draw new cursor immediately
|
||||
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
|
||||
state.movecb({...mouse.canvas.pos, target: {id: "overlayCanvas"}});
|
||||
state.movecb({...mouse.coords.canvas.pos, target: {id: "overlayCanvas"}});
|
||||
|
||||
// Start Listeners
|
||||
mouse.listen.canvas.onmousemove.on(state.movecb);
|
||||
|
@ -454,11 +440,11 @@ tools.maskbrush = toolbar.registerTool(
|
|||
state.config.maxBrushSize,
|
||||
1
|
||||
);
|
||||
state.ctxmenu.brushSizeLabel = brushSizeSlider.label;
|
||||
state.ctxmenu.brushSizeSlider = brushSizeSlider.slider;
|
||||
state.setBrushSize = brushSizeSlider.setValue;
|
||||
}
|
||||
|
||||
menu.appendChild(state.ctxmenu.brushSizeLabel);
|
||||
menu.appendChild(state.ctxmenu.brushSizeSlider);
|
||||
},
|
||||
shortcut: "M",
|
||||
}
|
||||
|
|
10
js/util.js
10
js/util.js
|
@ -42,6 +42,16 @@ const guid = (size = 3) => {
|
|||
return id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default option set
|
||||
*/
|
||||
|
||||
function defaultOpt(options, defaults) {
|
||||
Object.keys(defaults).forEach((key) => {
|
||||
if (options[key] === undefined) options[key] = defaults[key];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bounding box Calculation
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue