| import { app } from '../../../scripts/app.js' |
| import { $el } from '../../../scripts/ui.js' |
|
|
| const getLocalData = key => { |
| let data = {} |
| try { |
| data = JSON.parse(localStorage.getItem(key)) || {} |
| } catch (error) { |
| return {} |
| } |
| return data |
| } |
| function get_position_style (ctx, widget_width, y, node_height) { |
| const MARGIN = 4 |
|
|
| |
| const elRect = ctx.canvas.getBoundingClientRect() |
| const transform = new DOMMatrix() |
| .scaleSelf( |
| elRect.width / ctx.canvas.width, |
| elRect.height / ctx.canvas.height |
| ) |
| .multiplySelf(ctx.getTransform()) |
| .translateSelf(MARGIN, MARGIN + y) |
|
|
| return { |
| transformOrigin: '0 0', |
| transform: transform, |
| left: `0`, |
| top: `0`, |
| cursor: 'pointer', |
| position: 'absolute', |
| maxWidth: `${widget_width - MARGIN * 2}px`, |
| |
| width: `${widget_width - MARGIN * 2}px`, |
| |
| |
| display: 'flex', |
| flexDirection: 'column', |
| |
| justifyContent: 'space-around' |
| } |
| } |
|
|
| function hexToRGBA (hexColor) { |
| var hex = hexColor.replace('#', '') |
| var r = parseInt(hex.substring(0, 2), 16) |
| var g = parseInt(hex.substring(2, 4), 16) |
| var b = parseInt(hex.substring(4, 6), 16) |
|
|
| |
| var alphaHex = hex.substring(6) |
|
|
| |
| var alpha = parseInt(alphaHex, 16) / 255 |
|
|
| return [r, g, b, alpha] |
| } |
|
|
| app.registerExtension({ |
| name: 'Mixlab.utils.Color', |
| init () { |
| $el('link', { |
| rel: 'stylesheet', |
| href: '/extensions/comfyui-mixlab-nodes/lib/classic.min.css', |
| parent: document.head |
| }) |
|
|
| $el('style', { |
| textContent: ` |
| .pickr{ |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| } |
| .pickr .pcr-button { |
| width: 56px; |
| height: 56px; |
| outline: 1px solid white; |
| } |
| |
| `, |
| parent: document.body |
| }) |
| }, |
| async getCustomWidgets (app) { |
| return { |
| TCOLOR (node, inputName, inputData, app) { |
| |
| const widget = { |
| type: inputData[0], |
| name: inputName, |
| size: [128, 32], |
| draw (ctx, node, width, y) {}, |
| computeSize (...args) { |
| return [128, 32] |
| }, |
| async serializeValue (nodeId, widgetIndex) { |
| |
| |
| let hex = widget.value || '#000000' |
| let [r, g, b, a] = hexToRGBA(hex) |
| return { |
| hex, |
| r, |
| g, |
| b, |
| a |
| } |
| } |
| } |
| |
| node.addCustomWidget(widget) |
| return widget |
| } |
| } |
| }, |
|
|
| async beforeRegisterNodeDef (nodeType, nodeData, app) { |
| if (nodeType.comfyClass == 'Color') { |
| const orig_nodeCreated = nodeType.prototype.onNodeCreated |
| nodeType.prototype.onNodeCreated = function () { |
| orig_nodeCreated?.apply(this, arguments) |
|
|
| |
|
|
| const widget = { |
| type: 'div', |
| name: 'input_color', |
| draw (ctx, node, widget_width, y, widget_height) { |
| Object.assign( |
| this.div.style, |
| get_position_style(ctx, widget_width, 44, node.size[1]) |
| ) |
| |
| } |
| } |
|
|
| widget.div = $el('div', {}) |
|
|
| document.body.appendChild(widget.div) |
|
|
| const inputDiv = () => { |
| let div = document.createElement('div') |
| div.id = `color_picker_${this.id}` |
| return div |
| } |
|
|
| let inputColor = inputDiv('_mixlab_utils_color', 'Color', '#000000') |
|
|
| widget.div.appendChild(inputColor) |
|
|
| this.addCustomWidget(widget) |
|
|
| const pickr = Pickr.create({ |
| el: `#${inputColor.id}`, |
| theme: 'classic', |
| |
| default: '#000000', |
| swatches: [ |
| 'rgba(244, 67, 54, 1)', |
| 'rgba(233, 30, 99, 0.95)', |
| 'rgba(156, 39, 176, 0.9)', |
| 'rgba(103, 58, 183, 0.85)', |
| 'rgba(63, 81, 181, 0.8)', |
| 'rgba(33, 150, 243, 0.75)', |
| 'rgba(3, 169, 244, 0.7)', |
| 'rgba(0, 188, 212, 0.7)', |
| 'rgba(0, 150, 136, 0.75)', |
| 'rgba(76, 175, 80, 0.8)', |
| 'rgba(139, 195, 74, 0.85)', |
| 'rgba(205, 220, 57, 0.9)', |
| 'rgba(255, 235, 59, 0.95)', |
| 'rgba(255, 193, 7, 1)' |
| ], |
|
|
| components: { |
| |
| preview: true, |
| opacity: true, |
| hue: true, |
| |
| interaction: { |
| hex: true, |
| rgba: true, |
| hsla: true, |
| hsva: true, |
| cmyk: true, |
| input: true, |
| |
| save: true, |
| cancel: true |
| } |
| } |
| }) |
|
|
| pickr |
| .on('save', (color, instance) => { |
| |
| |
| |
| |
|
|
| try { |
| let tc = this.widgets.filter(w => w.type == 'TCOLOR')[0] |
| tc.value = color.toHEXA().toString() |
| } catch (error) {} |
| }) |
| .on('cancel', instance => { |
| pickr && pickr.hide() |
| }) |
| this.pickr = pickr |
| const handleMouseWheel = () => { |
| try { |
| this.pickr && this.pickr.hide() |
| } catch (error) {} |
| } |
|
|
| document.addEventListener('wheel', handleMouseWheel) |
|
|
| const onRemoved = this.onRemoved |
| this.onRemoved = () => { |
| inputColor.remove() |
| widget.div.remove() |
|
|
| try { |
| this.pickr.destroyAndRemove() |
| this.pickr = null |
| document.removeEventListener('wheel', handleMouseWheel) |
| } catch (error) { |
| console.log(error) |
| } |
|
|
| return onRemoved?.() |
| } |
|
|
| this.serialize_widgets = true |
| } |
| } |
| }, |
| async loadedGraphNode (node, app) { |
| |
| |
|
|
| if (node.type === 'Color') { |
| try { |
| let TCOLOR = node.widgets.filter(w => w.type == 'TCOLOR')[0] |
|
|
| setTimeout(() => node.pickr.setColor(TCOLOR.value || '#000000'), 1000) |
| } catch (error) {} |
| } |
| } |
| }) |
|
|
| app.registerExtension({ |
| name: 'Mixlab.utils.TextToNumber', |
| async beforeRegisterNodeDef (nodeType, nodeData, app) { |
| if (nodeType.comfyClass == 'TextToNumber') { |
| const onExecuted = nodeType.prototype.onExecuted |
| nodeType.prototype.onExecuted = function (message) { |
| onExecuted?.apply(this, arguments) |
| const random_number = this.widgets.filter( |
| w => w.name === 'random_number' |
| )[0] |
| if (random_number.value === 'enable') { |
| const n = this.widgets.filter(w => w.name === 'number')[0] |
| n.value = message.num[0] |
| } |
| console.log('TextToNumber', random_number.value) |
| } |
| } |
| } |
| }) |
|
|
| const min_max = node => { |
| if(node.widgets){ |
| const min_value = node.widgets.filter(w => w.name === 'min_value')[0] |
| const max_value = node.widgets.filter(w => w.name === 'max_value')[0] |
| |
| const number = node.widgets.filter(w => w.name === 'number')[0] |
| if (number) { |
| number.options.min = min_value.value |
| number.options.max = max_value.value |
| |
| number.value = Math.min(number.options.max, number.value) |
| number.value = Math.max(number.options.min, number.value) |
| } |
| |
| if (min_value) |
| min_value.callback = e => { |
| number.options.min = e |
| number.value = e |
| } |
| if (max_value) |
| max_value.callback = e => { |
| number.options.max = e |
| number.value = e |
| } |
| } |
| |
| } |
|
|
| app.registerExtension({ |
| name: 'Mixlab.utils.FloatSlider', |
| async beforeRegisterNodeDef (nodeType, nodeData, app) { |
|
|
| if (nodeType.comfyClass == 'FloatSlider') { |
| const orig_nodeCreated = nodeType.prototype.onNodeCreated; |
| nodeType.prototype.onNodeCreated = function () { |
| orig_nodeCreated?.apply(this, arguments) |
| min_max(this) |
| } |
| } |
|
|
| |
| }, |
| async loadedGraphNode (node, app) { |
| if (node.type === 'FloatSlider') { |
| min_max(node) |
| } |
| } |
| }) |
| app.registerExtension({ |
| name: 'Mixlab.utils.IntNumber', |
| async beforeRegisterNodeDef (nodeType, nodeData, app) { |
| |
| if (nodeType.comfyClass == 'IntNumber') { |
| const orig_nodeCreated = nodeType.prototype.onNodeCreated |
| nodeType.prototype.onNodeCreated = function () { |
| orig_nodeCreated?.apply(this, arguments) |
| min_max(this) |
| } |
| } |
| |
| }, |
| async loadedGraphNode (node, app) { |
| if (node.type === 'IntNumber') { |
| min_max(node) |
| } |
| } |
| }) |
|
|
|
|
| app.registerExtension({ |
| name: 'Mixlab.utils.TESTNODE_', |
| async beforeRegisterNodeDef (nodeType, nodeData, app) { |
| |
| if (nodeType.comfyClass == 'TESTNODE_') { |
| |
| const onExecuted = nodeType.prototype.onExecuted; |
| nodeType.prototype.onExecuted = function (message) { |
| onExecuted?.apply(this, arguments); |
| console.log('##',message) |
| |
| }; |
|
|
|
|
| } |
| |
| }, |
| }) |
|
|