mirror of
https://git.datalinker.icu/kijai/ComfyUI-KJNodes.git
synced 2025-12-16 08:14:32 +08:00
Spline editor custom size option
This commit is contained in:
parent
f259e062c7
commit
4e2ff11e3f
@ -34,6 +34,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"CreateVoronoiMask": CreateVoronoiMask,
|
"CreateVoronoiMask": CreateVoronoiMask,
|
||||||
"CreateMagicMask": CreateMagicMask,
|
"CreateMagicMask": CreateMagicMask,
|
||||||
"RemapMaskRange": RemapMaskRange,
|
"RemapMaskRange": RemapMaskRange,
|
||||||
|
"GetMaskSize": GetMaskSize,
|
||||||
#images
|
#images
|
||||||
"ImageBatchMulti": ImageBatchMulti,
|
"ImageBatchMulti": ImageBatchMulti,
|
||||||
"ColorMatch": ColorMatch,
|
"ColorMatch": ColorMatch,
|
||||||
|
|||||||
@ -106,7 +106,7 @@ output types:
|
|||||||
coord['y'] = int(round(coord['y']))
|
coord['y'] = int(round(coord['y']))
|
||||||
|
|
||||||
normalized_y_values = [
|
normalized_y_values = [
|
||||||
(1.0 - (point['y'] / 512) - 0.0) * (max_value - min_value) + min_value
|
(1.0 - (point['y'] / mask_height) - 0.0) * (max_value - min_value) + min_value
|
||||||
for point in coordinates
|
for point in coordinates
|
||||||
]
|
]
|
||||||
if float_output_type == 'list':
|
if float_output_type == 'list':
|
||||||
@ -539,7 +539,7 @@ Experimental, does not function yet as ComfyUI base changes are needed
|
|||||||
# Concatenate prev and position_params_batch, ensuring both are lists of lists
|
# Concatenate prev and position_params_batch, ensuring both are lists of lists
|
||||||
# and each sublist corresponds to a batch item
|
# and each sublist corresponds to a batch item
|
||||||
combined_position_params = [prev_item + batch_item for prev_item, batch_item in zip(prev, position_params_batch)]
|
combined_position_params = [prev_item + batch_item for prev_item, batch_item in zip(prev, position_params_batch)]
|
||||||
n[1]['gligen'] = ("position", gligen_textbox_model, combined_position_params)
|
n[1]['gligen'] = ("position_batched", gligen_textbox_model, combined_position_params)
|
||||||
c.append(n)
|
c.append(n)
|
||||||
|
|
||||||
return (c, plot_image_tensor,)
|
return (c, plot_image_tensor,)
|
||||||
|
|||||||
@ -1393,6 +1393,28 @@ Segments an image or batch of images using CLIPSeg.
|
|||||||
|
|
||||||
return results,
|
return results,
|
||||||
|
|
||||||
|
class GetMaskSize:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required": {
|
||||||
|
"mask": ("MASK",),
|
||||||
|
}}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("MASK","INT", "INT", )
|
||||||
|
RETURN_NAMES = ("mask", "width", "height",)
|
||||||
|
FUNCTION = "getsize"
|
||||||
|
CATEGORY = "KJNodes/masking"
|
||||||
|
DESCRIPTION = """
|
||||||
|
Returns the width and height of the mask,
|
||||||
|
and passes through the mask unchanged.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def getsize(self, mask):
|
||||||
|
width = mask.shape[2]
|
||||||
|
height = mask.shape[1]
|
||||||
|
return (mask, width, height,)
|
||||||
|
|
||||||
class RoundMask:
|
class RoundMask:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
|
|||||||
@ -147,13 +147,13 @@ app.registerExtension({
|
|||||||
this.menuItem2.textContent = "Display sample points";
|
this.menuItem2.textContent = "Display sample points";
|
||||||
styleMenuItem(this.menuItem2);
|
styleMenuItem(this.menuItem2);
|
||||||
|
|
||||||
// this.menuItem3 = document.createElement("a");
|
this.menuItem3 = document.createElement("a");
|
||||||
// this.menuItem3.href = "#";
|
this.menuItem3.href = "#";
|
||||||
// this.menuItem3.id = "menu-item-2";
|
this.menuItem3.id = "menu-item-2";
|
||||||
// this.menuItem3.textContent = "Switch sampling method";
|
this.menuItem3.textContent = "Switch point shape";
|
||||||
// styleMenuItem(this.menuItem3);
|
styleMenuItem(this.menuItem3);
|
||||||
|
|
||||||
const menuItems = [this.menuItem1, this.menuItem2];
|
const menuItems = [this.menuItem1, this.menuItem2, this.menuItem3];
|
||||||
|
|
||||||
menuItems.forEach(menuItem => {
|
menuItems.forEach(menuItem => {
|
||||||
menuItem.addEventListener('mouseover', function() {
|
menuItem.addEventListener('mouseover', function() {
|
||||||
@ -190,7 +190,6 @@ app.registerExtension({
|
|||||||
|
|
||||||
chainCallback(this, "onGraphConfigured", function() {
|
chainCallback(this, "onGraphConfigured", function() {
|
||||||
createSplineEditor(this);
|
createSplineEditor(this);
|
||||||
this.setSize([550, 920]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}); // onAfterGraphConfigured
|
}); // onAfterGraphConfigured
|
||||||
@ -245,22 +244,22 @@ function createSplineEditor(context, reset=false) {
|
|||||||
updatePath();
|
updatePath();
|
||||||
});
|
});
|
||||||
|
|
||||||
// context.menuItem3.addEventListener('click', function(e) {
|
context.menuItem3.addEventListener('click', function(e) {
|
||||||
// e.preventDefault();
|
e.preventDefault();
|
||||||
// if (pointSamplingMethod == samplePointsTime) {
|
if (dotShape == "circle"){
|
||||||
// pointSamplingMethod = samplePointsPath
|
dotShape = "triangle"
|
||||||
// }
|
}
|
||||||
// else {
|
else {
|
||||||
// pointSamplingMethod = samplePointsTime
|
dotShape = "circle"
|
||||||
// }
|
}
|
||||||
// updatePath();
|
console.log(dotShape)
|
||||||
// });
|
updatePath();
|
||||||
|
});
|
||||||
|
var dotShape = "circle";
|
||||||
var drawSamplePoints = false;
|
var drawSamplePoints = false;
|
||||||
//var pointSamplingMethod = samplePointsTime
|
|
||||||
|
|
||||||
function updatePath() {
|
function updatePath() {
|
||||||
let coords = samplePoints(pathElements[0], points_to_sample, samplingMethod);
|
let coords = samplePoints(pathElements[0], points_to_sample, samplingMethod, w);
|
||||||
|
|
||||||
if (drawSamplePoints) {
|
if (drawSamplePoints) {
|
||||||
if (pointsLayer) {
|
if (pointsLayer) {
|
||||||
@ -303,6 +302,8 @@ function createSplineEditor(context, reset=false) {
|
|||||||
const minValueWidget = context.widgets.find(w => w.name === "min_value");
|
const minValueWidget = context.widgets.find(w => w.name === "min_value");
|
||||||
const maxValueWidget = context.widgets.find(w => w.name === "max_value");
|
const maxValueWidget = context.widgets.find(w => w.name === "max_value");
|
||||||
const samplingMethodWidget = context.widgets.find(w => w.name === "sampling_method");
|
const samplingMethodWidget = context.widgets.find(w => w.name === "sampling_method");
|
||||||
|
const widthWidget = context.widgets.find(w => w.name === "mask_width");
|
||||||
|
const heightWidget = context.widgets.find(w => w.name === "mask_height");
|
||||||
//const segmentedWidget = context.widgets.find(w => w.name === "segmented");
|
//const segmentedWidget = context.widgets.find(w => w.name === "segmented");
|
||||||
|
|
||||||
var interpolation = interpolationWidget.value
|
var interpolation = interpolationWidget.value
|
||||||
@ -337,12 +338,26 @@ function createSplineEditor(context, reset=false) {
|
|||||||
rangeMax = maxValueWidget.value
|
rangeMax = maxValueWidget.value
|
||||||
updatePath();
|
updatePath();
|
||||||
}
|
}
|
||||||
|
widthWidget.callback = () => {
|
||||||
|
w = widthWidget.value
|
||||||
|
vis.width(w)
|
||||||
|
context.setSize([w + 45, context.size[1]]);
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
heightWidget.callback = () => {
|
||||||
|
h = heightWidget.value
|
||||||
|
vis.height(h)
|
||||||
|
context.setSize([context.size[0], h + 410]);
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize or reset points array
|
// Initialize or reset points array
|
||||||
var drawHandles = false
|
var drawHandles = false;
|
||||||
var w = 512
|
var hoverIndex = -1;
|
||||||
var h = 512
|
var isDragging = false;
|
||||||
var i = 3
|
var w = widthWidget.value;
|
||||||
|
var h = heightWidget.value;
|
||||||
|
var i = 3;
|
||||||
let points = [];
|
let points = [];
|
||||||
|
|
||||||
if (!reset && pointsStoreWidget.value != "") {
|
if (!reset && pointsStoreWidget.value != "") {
|
||||||
@ -408,12 +423,12 @@ function createSplineEditor(context, reset=false) {
|
|||||||
context.contextMenu.style.display = 'block';
|
context.contextMenu.style.display = 'block';
|
||||||
context.contextMenu.style.left = `${pv.event.clientX}px`;
|
context.contextMenu.style.left = `${pv.event.clientX}px`;
|
||||||
context.contextMenu.style.top = `${pv.event.clientY}px`;
|
context.contextMenu.style.top = `${pv.event.clientY}px`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
vis.add(pv.Rule)
|
vis.add(pv.Rule)
|
||||||
.data(pv.range(0, 8, .5))
|
.data(pv.range(0, h, 64))
|
||||||
.bottom(d => d * 64)
|
.bottom(d => d)
|
||||||
.strokeStyle("gray")
|
.strokeStyle("gray")
|
||||||
.lineWidth(3)
|
.lineWidth(3)
|
||||||
|
|
||||||
@ -432,15 +447,42 @@ function createSplineEditor(context, reset=false) {
|
|||||||
.segmented(() => false)
|
.segmented(() => false)
|
||||||
.strokeStyle(pv.Colors.category10().by(pv.index))
|
.strokeStyle(pv.Colors.category10().by(pv.index))
|
||||||
.lineWidth(3)
|
.lineWidth(3)
|
||||||
|
|
||||||
var hoverIndex = -1;
|
|
||||||
var isDragging
|
|
||||||
|
|
||||||
vis.add(pv.Dot)
|
vis.add(pv.Dot)
|
||||||
.data(() => points)
|
.data(() => points)
|
||||||
.left(d => d.x)
|
.left(d => d.x)
|
||||||
.top(d => d.y)
|
.top(d => d.y)
|
||||||
.radius(10)
|
.radius(10)
|
||||||
|
.shape(function() {
|
||||||
|
return dotShape;
|
||||||
|
})
|
||||||
|
.angle(function() {
|
||||||
|
const index = this.index;
|
||||||
|
let angle = 0;
|
||||||
|
|
||||||
|
if (dotShape === "triangle") {
|
||||||
|
let dxNext = 0, dyNext = 0;
|
||||||
|
if (index < points.length - 1) {
|
||||||
|
dxNext = points[index + 1].x - points[index].x;
|
||||||
|
dyNext = points[index + 1].y - points[index].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dxPrev = 0, dyPrev = 0;
|
||||||
|
if (index > 0) {
|
||||||
|
dxPrev = points[index].x - points[index - 1].x;
|
||||||
|
dyPrev = points[index].y - points[index - 1].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dx = (dxNext + dxPrev) / 2;
|
||||||
|
const dy = (dyNext + dyPrev) / 2;
|
||||||
|
|
||||||
|
angle = Math.atan2(dy, dx);
|
||||||
|
angle -= Math.PI / 2;
|
||||||
|
angle = (angle + 2 * Math.PI) % (2 * Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
})
|
||||||
.cursor("move")
|
.cursor("move")
|
||||||
.strokeStyle(function() { return i == this.index ? "#ff7f0e" : "#1f77b4"; })
|
.strokeStyle(function() { return i == this.index ? "#ff7f0e" : "#1f77b4"; })
|
||||||
.fillStyle(function() { return "rgba(100, 100, 100, 0.2)"; })
|
.fillStyle(function() { return "rgba(100, 100, 100, 0.2)"; })
|
||||||
@ -498,7 +540,7 @@ function createSplineEditor(context, reset=false) {
|
|||||||
return `F: ${frame}, X: ${normalizedX.toFixed(2)}, Y: ${normalizedY.toFixed(2)}`;
|
return `F: ${frame}, X: ${normalizedX.toFixed(2)}, Y: ${normalizedY.toFixed(2)}`;
|
||||||
})
|
})
|
||||||
.textStyle("orange")
|
.textStyle("orange")
|
||||||
|
|
||||||
vis.render();
|
vis.render();
|
||||||
var svgElement = vis.canvas();
|
var svgElement = vis.canvas();
|
||||||
svgElement.style['zIndex'] = "2"
|
svgElement.style['zIndex'] = "2"
|
||||||
@ -508,8 +550,8 @@ function createSplineEditor(context, reset=false) {
|
|||||||
updatePath();
|
updatePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
function samplePoints(svgPathElement, numSamples, samplingMethod) {
|
function samplePoints(svgPathElement, numSamples, samplingMethod, width) {
|
||||||
var svgWidth = 512; // Fixed width of the SVG element
|
var svgWidth = width; // Fixed width of the SVG element
|
||||||
var pathLength = svgPathElement.getTotalLength();
|
var pathLength = svgPathElement.getTotalLength();
|
||||||
var points = [];
|
var points = [];
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user