Mini bug patches

This commit is contained in:
Trung0246
2024-01-09 18:43:30 -08:00
committed by GitHub
parent f4fe65f8c5
commit f9437c5b56
5 changed files with 5340 additions and 3619 deletions
+37 -69
View File
@@ -1553,7 +1553,7 @@ class ScriptPile:
"pipe_in": (lib0246.TautologyStr("*"), ),
"script_rule_loop_mode": (["_", "slice", "cycle"], ),
"script_rule_regex": ("STRING", {
"default": r"(?P<m>^@model$)|(?P<m_>^%MODEL$)|(?P<c>^@clip$)|(?P<c_>^%CLIP$)|(?P<_>^$)",
"default": r"(?P<m>^(@model|%MODEL)$)|(?P<c>^(@clip|%CLIP)$)|(?P<_>^$)",
"multiline": False
}),
"script_rule_pin_mode": ([
@@ -1603,7 +1603,7 @@ class ScriptPile:
if curr_match_pin:
for (i, curr_out), curr_type in zip(enumerate(script_name), script_type):
curr_match_out: re.Match = script_rule_regex.match("%" + curr_out)
if curr_match_out and curr_match_out.lastgroup == curr_match_pin.lastgroup + "_":
if curr_match_out and curr_match_out.lastgroup == curr_match_pin.lastgroup:
pile_data["data"][(curr_out, curr_type)] = (i, curr_pin, count)
count += 1
if curr_type not in pile_data["type"]:
@@ -2014,77 +2014,43 @@ class Hub:
"result": [res_data[i] for i in range(len(res_data))]
}
######################################################################################
class Cloud:
@classmethod
def INPUT_TYPES(s):
return {
"required": lib0246.WildDict(),
"optional": {
"_cloud_in": ("CLOUD_PIPE", ),
},
"hidden": {
"_prompt": "PROMPT",
"_id": "UNIQUE_ID",
"_workflow": "EXTRA_PNGINFO"
}
}
RETURN_TYPES = lib0246.ByPassTypeTuple(("CLOUD_PIPE", ))
RETURN_NAMES = lib0246.ByPassTypeTuple(("_cloud_out", ))
INPUT_IS_LIST = True
OUTPUT_IS_LIST = lib0246.TautologyAll()
FUNCTION = "execute"
CATEGORY = "0246"
def execute(self, _id = None, _prompt = None, _workflow = None, **kwargs):
pass
def text_to_cloud(self):
pass
def cloud_to_text(self):
pass
########################################################################################
######################################## EXPORT ########################################
########################################################################################
# Node only used for showcase stuff
class StrAdd:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"a": ("STRING", {
"default": "a",
"multiline": True
}),
"b": ("STRING", {
"default": "b",
"multiline": True
}),
"c": ("STRING", {
"default": "c",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING", )
RETURN_NAMES = ("res", )
OUTPUT_IS_LIST = (False, )
FUNCTION = "execute"
CATEGORY = "0246"
def execute(self, a = None, b = None, c = None):
return (f"({a};{b};{c})", )
class StrAddBatch:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"a": ("STRING", {
"default": "a",
"multiline": True
}),
"b": ("STRING", {
"default": "b",
"multiline": True
}),
"c": ("STRING", {
"default": "c",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING", )
RETURN_NAMES = ("res", )
INPUT_IS_LIST = True
OUTPUT_IS_LIST = (True, )
FUNCTION = "execute"
CATEGORY = "0246"
def execute(self, a = None, b = None, c = None):
res = []
for i in range(len(a)):
a_val = a[i] if i < len(a) else a[-1]
b_val = b[i] if i < len(b) else b[-1]
c_val = c[i] if i < len(c) else c[-1]
res.append(f"({a_val};{b_val};{c_val})")
return (res, )
# [TODO] "Meta" node to show information about highway or junction
# [TODO] "RandomInt" node can have linger seed if batch len is different
@@ -2107,6 +2073,7 @@ NODE_CLASS_MAPPINGS = {
"0246.ScriptPile": ScriptPile,
"0246.Script": Script,
"0246.Hub": Hub,
# "0246.Cloud": Cloud,
# "0246.Pick": Pick,
# "0246.StrAdd": StrAdd,
# "0246.StrAddBatch": StrAddBatch,
@@ -2131,6 +2098,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"0246.ScriptPile": "Script Pile",
"0246.Script": "Script",
"0246.Hub": "Hub",
# "0246.Cloud": "Cloud",
# "0246.Pick": "Pick",
# "0246.StrAdd": "Str Add",
# "0246.StrAddBatch": "Str Add Batch",
+303 -109
View File
@@ -69,10 +69,10 @@ export function monitor_array(obj, key) {
let flag = false;
lib0246.hijack(window, "structuredClone", (obj) => {
if (obj && obj.___MARK___)
flag = true;
}, function (obj) {
if (flag) {
if (!this.mark) {
if (obj && obj.___MARK___)
flag = true;
} else if (flag) {
monitorArray(obj, key);
obj.___MARK___ = true;
flag = false;
@@ -338,88 +338,90 @@ function patch_script(workflow) {
}
lib0246.hijack(app, "loadGraphData", function (workflow) {
PATCH_SIG.length = 0;
if (workflow) {
if (!workflow?.extra?.["0246.VERSION"]) {
for (let i = 0; i < workflow.nodes.length; ++ i) {
for (let j = 0; j < patch_node_db.length; ++ j) {
if (workflow.nodes[i].type === patch_node_db[j][0]) {
console.warn(`[ComfyUI-0246] Patching node "${workflow.nodes[i].type}" to "${patch_node_db[j][1]}"`);
workflow.nodes[i].type = patch_node_db[j][1];
break;
} else if (workflow.nodes[i].type === patch_node_db[j][1])
break;
}
if ((workflow.nodes[i].type === "0246.Highway" || workflow.nodes[i].type === "0246.HighwayBatch") && !PATCH_SIG.includes(1))
PATCH_SIG.push(1);
else if (workflow.nodes[i].type === "0246.Hub") {
console.warn(`[ComfyUI-0246] Patching node "${workflow.nodes[i].id}" with value __BATCH__ to __BATCH_PRIM__`);
if (workflow.nodes[i].widgets_values?.[0] === "__BATCH__")
workflow.nodes[i].widgets_values[0] = "__BATCH_PRIM__";
const curr_type_list = workflow.extra["0246.HUB_DATA"][workflow.nodes[i].id].sole_type;
if (workflow.nodes[i].outputs)
for (let j = 0; j < workflow.nodes[i].outputs.length; ++ j) {
const curr_name = workflow.nodes[i].outputs[j].name;
if (curr_name?.endsWith?.("__BATCH__")) {
const curr_type = curr_type_list[curr_name];
curr_type[curr_type.length - 1] = "__BATCH_PRIM__";
const new_name = curr_type.join(":");
curr_type_list[new_name] = curr_type;
delete curr_type_list[curr_name];
workflow.nodes[i].outputs[j].name = new_name;
if (!this.mark) {
PATCH_SIG.length = 0;
if (workflow) {
if (!workflow?.extra?.["0246.VERSION"]) {
for (let i = 0; i < workflow.nodes.length; ++ i) {
for (let j = 0; j < patch_node_db.length; ++ j) {
if (workflow.nodes[i].type === patch_node_db[j][0]) {
console.warn(`[ComfyUI-0246] Patching node "${workflow.nodes[i].type}" to "${patch_node_db[j][1]}"`);
workflow.nodes[i].type = patch_node_db[j][1];
break;
} else if (workflow.nodes[i].type === patch_node_db[j][1])
break;
}
if ((workflow.nodes[i].type === "0246.Highway" || workflow.nodes[i].type === "0246.HighwayBatch") && !PATCH_SIG.includes(1))
PATCH_SIG.push(1);
else if (workflow.nodes[i].type === "0246.Hub") {
console.warn(`[ComfyUI-0246] Patching node "${workflow.nodes[i].id}" with value __BATCH__ to __BATCH_PRIM__`);
if (workflow.nodes[i].widgets_values?.[0] === "__BATCH__")
workflow.nodes[i].widgets_values[0] = "__BATCH_PRIM__";
const curr_type_list = workflow.extra["0246.HUB_DATA"][workflow.nodes[i].id].sole_type;
if (workflow.nodes[i].outputs)
for (let j = 0; j < workflow.nodes[i].outputs.length; ++ j) {
const curr_name = workflow.nodes[i].outputs[j].name;
if (curr_name?.endsWith?.("__BATCH__")) {
const curr_type = curr_type_list[curr_name];
curr_type[curr_type.length - 1] = "__BATCH_PRIM__";
const new_name = curr_type.join(":");
curr_type_list[new_name] = curr_type;
delete curr_type_list[curr_name];
workflow.nodes[i].outputs[j].name = new_name;
}
}
}
}
patch_script(workflow);
}
else if (
workflow.extra["0246.VERSION"][0] === 0 &&
workflow.extra["0246.VERSION"][1] === 0 &&
workflow.extra["0246.VERSION"][2] === 3
)
patch_script(workflow);
for (let i = 0; i < workflow.nodes.length; ++ i)
if (workflow.nodes[i].type === "0246.BoxRange") {
if (workflow.nodes[i].widgets_values[0] === "ConditioningSetAreaPercentage")
workflow.nodes[i].widgets_values[0] = "%(x, y, width, height)";
} else if (workflow.nodes[i].type === "0246.ScriptNode") {
if (
workflow.nodes[i].widgets_values[2] === "pin_highway_deep" ||
workflow.nodes[i].widgets_values[2] === "pin_highway_flat"
)
workflow.nodes[i].widgets_values[2] = "pin_highway";
}
}
} else {
if (PATCH_SIG.includes(1))
for (let i = 0; i < app.graph._nodes.length; ++ i)
if (app.graph._nodes[i].type === "0246.Highway" || app.graph._nodes[i].type === "0246.HighwayBatch") {
for (let j = 0; j < app.graph._nodes[i].widgets.length; ++ j)
if (app.graph._nodes[i].widgets[j].name === "Update") {
app.graph._nodes[i].widgets[j].callback();
break;
}
}
}
patch_script(workflow);
}
else if (
workflow.extra["0246.VERSION"][0] === 0 &&
workflow.extra["0246.VERSION"][1] === 0 &&
workflow.extra["0246.VERSION"][2] === 3
)
patch_script(workflow);
window.setTimeout(() => {
if (PATCH_SIG.includes(2)) {
for (let i = 0; i < app.graph._nodes.length; ++ i) {
// if (app.graph._nodes[i].type === "0246.ScriptNode")
// for (let j = 0; j < app.graph._nodes[i].outputs.length; ++ j)
// app.graph._nodes[i].disconnectOutput(j);
for (let j = 0; j < patch_node_db_0_0_3.length; ++ j)
if (app.graph._nodes[i].type === patch_node_db_0_0_3[j][1])
app.graph._nodes[i].setSize([app.graph._nodes[i].size[0], app.graph._nodes[i].computeSize()[1]]);
}
lib0246.error_popup(lib0246.indent_str `
Recent update have 0246.ScriptNode (formerly 0246.ScriptImbue) have it output changed due to bad design.
Please reconnect all output to desired node manually.
for (let i = 0; i < workflow.nodes.length; ++ i)
if (workflow.nodes[i].type === "0246.BoxRange") {
if (workflow.nodes[i].widgets_values[0] === "ConditioningSetAreaPercentage")
workflow.nodes[i].widgets_values[0] = "%(x, y, width, height)";
} else if (workflow.nodes[i].type === "0246.ScriptNode") {
if (
workflow.nodes[i].widgets_values[2] === "pin_highway_deep" ||
workflow.nodes[i].widgets_values[2] === "pin_highway_flat"
)
workflow.nodes[i].widgets_values[2] = "pin_highway";
Also remember to check for all 0246.ScriptRule if they have intended data.
`);
}
}, 0);
}
}, function (workflow) {
if (PATCH_SIG.includes(1))
for (let i = 0; i < app.graph._nodes.length; ++ i)
if (app.graph._nodes[i].type === "0246.Highway" || app.graph._nodes[i].type === "0246.HighwayBatch") {
for (let j = 0; j < app.graph._nodes[i].widgets.length; ++ j)
if (app.graph._nodes[i].widgets[j].name === "Update") {
app.graph._nodes[i].widgets[j].callback();
break;
}
}
window.setTimeout(() => {
if (PATCH_SIG.includes(2)) {
for (let i = 0; i < app.graph._nodes.length; ++ i) {
// if (app.graph._nodes[i].type === "0246.ScriptNode")
// for (let j = 0; j < app.graph._nodes[i].outputs.length; ++ j)
// app.graph._nodes[i].disconnectOutput(j);
for (let j = 0; j < patch_node_db_0_0_3.length; ++ j)
if (app.graph._nodes[i].type === patch_node_db_0_0_3[j][1])
app.graph._nodes[i].setSize([app.graph._nodes[i].size[0], app.graph._nodes[i].computeSize()[1]]);
}
lib0246.error_popup(lib0246.indent_str `
Recent update have 0246.ScriptNode (formerly 0246.ScriptImbue) have it output changed due to bad design.
Please reconnect all output to desired node manually.
Also remember to check for all 0246.ScriptRule if they have intended data.
`);
}
}, 0);
});
/////////////////////////////////////////////////////////////////////////
@@ -428,34 +430,36 @@ lib0246.hijack(app, "loadGraphData", function (workflow) {
let error_flag = false;
lib0246.hijack(app, "showMissingNodesError", function (nodes) {
if (!error_flag)
for (let i = 0; i < nodes.length; ++ i)
for (let j = 0; j < patch_node_db.length; ++ j)
if (nodes[i] === patch_node_db[j][0]) {
lib0246.error_popup(lib0246.indent_str `
[ComfyUI-0246] Unfortunately I have to change node internal ID due to I'm being dumb for using generic name. Sorry for inconvenience.
if (!this.mark) {
if (!error_flag)
for (let i = 0; i < nodes.length; ++ i)
for (let j = 0; j < patch_node_db.length; ++ j)
if (nodes[i] === patch_node_db[j][0]) {
lib0246.error_popup(lib0246.indent_str `
[ComfyUI-0246] Unfortunately I have to change node internal ID due to I'm being dumb for using generic name. Sorry for inconvenience.
If this error message shown then that mean automatic patching failed. Please replace each nodes manually :(
If this error message shown then that mean automatic patching failed. Please replace each nodes manually :(
Affected node:
Affected node:
- Highway -> 0246.Highway
- Junction -> 0246.Junction
- JunctionBatch -> 0246.JunctionBatch
- Loop -> 0246.Loop
- Count -> 0246.Count
- Hold -> 0246.Hold
- Beautify -> 0246.Beautify
- Random -> 0246.RandomInt
- Stringify -> 0246.Stringify
- Highway -> 0246.Highway
- Junction -> 0246.Junction
- JunctionBatch -> 0246.JunctionBatch
- Loop -> 0246.Loop
- Count -> 0246.Count
- Hold -> 0246.Hold
- Beautify -> 0246.Beautify
- Random -> 0246.RandomInt
- Stringify -> 0246.Stringify
- 0246.ScriptPlan -> 0246.ScriptRule
- 0246.ScriptImbue -> 0246.ScriptNode
`);
error_flag = true;
break;
}
}, () => {});
- 0246.ScriptPlan -> 0246.ScriptRule
- 0246.ScriptImbue -> 0246.ScriptNode
`);
error_flag = true;
break;
}
}
});
// Extremely hacky ways to fix issues with Reroute (rgthree). Maybe open issue about this?
app.registerExtension({
@@ -463,8 +467,9 @@ app.registerExtension({
async setup(app) {
if (LiteGraph.Nodes.RerouteNode) {
// Hijack Reroute (rgthree) to do onConnectOutput and onConnectInput
lib0246.hijack(LiteGraph.Nodes.RerouteNode.prototype, "onConnectionsChange", () => {}, function (type, index, connected, link_info) {
reroute_process(this.self);
lib0246.hijack(LiteGraph.Nodes.RerouteNode.prototype, "onConnectionsChange", function (type, index, connected, link_info) {
if (!this.mark)
reroute_process(this.self);
});
// Since native "Reroute" already did graph traversal, we don't need to hijack it
@@ -472,7 +477,196 @@ app.registerExtension({
lib0246.hijack(app.graph, "serialize", function () {
// Only used when breaking changes happen
app.graph.extra["0246.VERSION"] = [0, 0, 4];
}, () => {});
if (!this.mark)
app.graph.extra["0246.VERSION"] = [0, 0, 4];
});
}
});
});
// ctx.beginPath();
// ctx.fillStyle = "#ff00ff";
// ctx.arc(
// this.self.flex.hold_draw[0],
// this.self.flex.hold_draw[1],
// 4, 0, Math.PI * 2
// );
// ctx.fill();
// ctx.closePath();
// ctx.beginPath();
// ctx.fillStyle = "#ff00ff";
// ctx.arc(
// this.self.flex.hold_draw[0] + this.self.flex.hold_draw[2],
// this.self.flex.hold_draw[1] + this.self.flex.hold_draw[3],
// 4, 0, Math.PI * 2
// );
// ctx.fill();
// ctx.closePath();
// function draw_chain(
// ctx,
// fill_c, stroke_c, line_w,
// link_w, link_h, spacing,
// box_x, box_y, box_w, box_h
// ) {
// // Calculate how many links can fit in the box
// let links = Math.floor(box_w / (link_w + spacing));
// // Draw chain links
// for (let i = 0; i < links; ++ i) {
// let center_x = box_x + i * (link_w + spacing) + link_w / 2,
// center_y = box_y + box_h / 2;
// ctx.beginPath();
// ctx.fillStyle = fill_c;
// ctx.strokeStyle = stroke_c;
// ctx.lineWidth = line_w;
// ctx.ellipse(center_x, center_y, link_w / 2, link_h / 2, 0, 0, 2 * Math.PI);
// ctx.stroke();
// ctx.closePath();
// }
// }
// for (let inst_id in widget.cloud.data.hit) {
// ctx.beginPath();
// ctx.strokeStyle = "#f0f";
// ctx.lineWidth = 1;
// ctx.setLineDash([]);
// ctx.rect(
// widget.cloud.data.hit[inst_id][0], widget.cloud.data.hit[inst_id][1],
// widget.cloud.data.hit[inst_id][2], widget.cloud.data.hit[inst_id][3]
// );
// ctx.stroke();
// ctx.closePath();
// }
// {
// function Test() {}
// Test.title = "Test";
// Test.category = "0246";
// Test.comfyClass = "0246.Test";
// Test.collapsable = true;
// Test.title_mode = LiteGraph.NORMAL_TITLE;
// Test.prototype.onNodeCreated = function() {
// const node = this;
// const box_widget = node.addCustomWidget(BOX_RANGE_WIDGET("BOX_RANGE", "box_range", {
// row_count: 10,
// col_count: 10,
// }));
// widget_flex(node, box_widget, {
// ratio: 0,
// share: 1,
// min_h: 50,
// center: true,
// });
// }
// LiteGraph.registerNodeType("0246.Test", Test);
// }
// inst: [
// {
// id: "1",
// kind: "text",
// widgets_values: ["zxc xcv cvb"]
// }, {
// id: "2",
// kind: "text_json",
// widgets_values: ["./test.json", ".[][1]"]
// }, {
// id: "0",
// kind: "text",
// widgets_values: ["asd sdf dfg"]
// }, {
// id: "3",
// kind: "text_list",
// widgets_values: ["asd\nsdf\ndfg"]
// },
// {
// id: "4",
// kind: "weight",
// widgets_values: [1]
// }, {
// id: "5",
// kind: "rand",
// widgets_values: [1, 0, "randomize"]
// }, {
// id: "6",
// kind: "cycle",
// widgets_values: [0, 0]
// }, {
// id: "9",
// kind: "mark",
// widgets_values: ["gligen", 0]
// }, {
// id: "7",
// kind: "flip",
// widgets_values: [false]
// }, {
// id: "8",
// kind: "mark",
// widgets_values: ["cutoff", 0]
// }, {
// id: "10",
// kind: "pin",
// widgets_values: [0]
// },
// ],
// view: {
// ["0"]: "asd sdf dfg",
// ["1"]: "zxc xcv cvb",
// ["2"]: "testing",
// ["3"]: "asd\nsdf\ndfg",
// ["4"]: "1.00",
// ["5"]: "@RAND",
// ["6"]: "@CYCLE",
// ["7"]: "@FLIP",
// ["8"]: "#CUTOFF",
// ["9"]: "#GLIGEN",
// ["10"]: "$0000000000000000000000000000000000",
// },
// group: {
// ["11"]: {
// inst: ["1", "4", "6", "8"],
// color: "#ff0"
// },
// ["22"]: {
// inst: ["2", "5", "7", "9"],
// color: "#0ff"
// },
// ["33"]: {
// group: ["11"],
// color: "#f0f"
// },
// // ["44"]: {
// // group: ["33"]
// // },
// // ["11"]: {
// // inst: ["2"]
// // },
// // ["22"]: {
// // inst: ["2"]
// // },
// },
// if (node.configure && !node.configure[lib0246.HIJACK_MARK]) {
// let temp_compute_size;
// lib0246.hijack(node, "configure", function (data) {
// if (!this.mark) {
// temp_compute_size = node.computeSize;
// node.computeSize = function () {
// return [data.size[0], data.size[1]];
// };
// } else
// window.setTimeout(() => {
// node.size = node.computeSize();
// node.computeSize = temp_compute_size;
// }, 0);
// });
// }
// if (nodeData.category === "group nodes/workflow")
// GROUP_NODE_CATEGORY_LIST.push(nodeData.comfyClass);
+707 -3425
View File
File diff suppressed because it is too large Load Diff
+65 -16
View File
@@ -49,36 +49,62 @@ export function is_async(func) {
return func.constructor.name === "AsyncFunction";
}
export function hijack(obj, key, before_func, after_func) {
export const HIJACK_MARK = Symbol("hijack_mark");
function hijack_evt(evt_obj, pass_obj, mode) {
for (let i = 0; i < evt_obj.evt.length; ++ i)
evt_obj.evt[i].call(pass_obj, mode);
}
export function hijack(obj, key, func, evt) {
// The most convoluted hijacking mechanism ever
const old_func = obj[key] ?? (() => {});
const old_func = obj[key] ?? (() => {}),
evt_obj = old_func[HIJACK_MARK] ?? {
evt: [],
};
obj[key] = function(...args) {
const self = this;
const pass_obj = {
self: self,
stop: false,
pre: before_func,
post: after_func,
func: func,
old: old_func,
args: args,
wait: is_async(old_func) || is_async(before_func) || is_async(after_func),
wait: is_async(old_func) || is_async(func),
};
const exec_after = () => {
const after_result = after_func.apply(pass_obj, args);
hijack_evt(evt_obj, pass_obj, 0b10000);
const after_result = func.apply(pass_obj, args);
hijack_evt(evt_obj, pass_obj, 0b100000);
if (is_promise(after_result))
return after_result.then(() => pass_obj.res);
// return after_result.then(() => pass_obj.res);
return after_result.then(() => {
hijack_evt(evt_obj, pass_obj, 0b100000000);
return pass_obj.res;
});
return pass_obj.res;
};
const exec_old = () => {
if (pass_obj.old !== old_func || pass_obj.stop) {
hijack_evt(evt_obj, pass_obj, 0b1000000);
if (is_promise(pass_obj.res))
return pass_obj.res.then(exec_after);
// return pass_obj.res.then(exec_after);
return pass_obj.res.then(res => {
pass_obj.res = res;
hijack_evt(evt_obj, pass_obj, 0b10000000);
return exec_after();
});
return exec_after();
}
hijack_evt(evt_obj, pass_obj, 0b100);
const result = old_func.apply(self, args);
hijack_evt(evt_obj, pass_obj, 0b1000);
if (is_promise(result))
return result.then(res => {
pass_obj.res = res;
@@ -88,12 +114,21 @@ export function hijack(obj, key, before_func, after_func) {
return exec_after();
};
const before_result = before_func.apply(pass_obj, args);
hijack_evt(evt_obj, pass_obj, 0b1);
const before_result = func.apply(pass_obj, args);
hijack_evt(evt_obj, pass_obj, 0b10);
pass_obj.mark = true;
if (is_promise(before_result))
return before_result.then(exec_old);
return exec_old();
};
obj[key][HIJACK_MARK] = evt_obj;
if (evt)
obj[key][HIJACK_MARK].evt.push(evt);
return old_func;
}
@@ -511,19 +546,15 @@ export function calc_spread(count, total, weight, limit) {
for (let i = 0; i < count; ++ i)
if (limit[i] !== null) {
let weight_ratio = weight[i] / total_weight,
res_val = weight_ratio * total;
res[i] = Math.min(res_val, limit[i]);
res[i] = Math.min(weight[i] / total_weight * total, limit[i]);
total -= res[i];
total_weight -= weight[i];
}
for (let i = 0; i < count; ++ i)
if (limit[i] === null) {
let weight_ratio = weight[i] / total_weight;
res[i] = weight_ratio * total;
}
if (limit[i] === null)
res[i] = weight[i] / (total_weight === 0 ? 1 : total_weight) * total;
return res;
}
@@ -544,6 +575,24 @@ export function snap(num, step) {
return Math.ceil(num / step) * step;
}
export function multi_snap(num, len, fn) {
if (num < fn(0) || num > fn(len - 1))
return null;
let closest = 0,
min_diff = Math.abs(num - fn(0));
for (let i = 1; i < len; ++ i) {
let diff = Math.abs(num - fn(i));
if (diff < min_diff) {
min_diff = diff;
closest = i;
}
}
return closest;
}
export function rem(a, b) {
return (a % b + b) % b;
}
+4228
View File
File diff suppressed because it is too large Load Diff