107 lines
5.6 KiB
JavaScript
107 lines
5.6 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { AnglesSelector3DWidget } from './widget.js';
|
|
import { t } from './i18n.js';
|
|
|
|
const STYLES = `
|
|
.angles-selector-container { font-family: Arial, sans-serif; color: #fff; padding: 5px; height: 100%; display: flex; flex-direction: column; }
|
|
.angles-selector-container canvas { border-radius: 8px; display: block; width: 100% !important; height: 100% !important; }
|
|
.canvas-container { width: 100%; flex: 1; min-height: 200px; }
|
|
.selection-display { margin-top: 8px; max-height: 100px; overflow-y: auto; font-size: 11px; }
|
|
.selection-count { font-weight: bold; margin-bottom: 4px; color: #4ECDC4; }
|
|
.selection-list { max-height: 80px; overflow-y: auto; }
|
|
.selection-item { display: flex; justify-content: space-between; align-items: center; padding: 3px 6px; margin: 2px 0; background: rgba(255,255,255,0.1); border-radius: 3px; font-size: 10px; }
|
|
.remove-btn { background: none; border: none; color: #ff6b6b; cursor: pointer; font-size: 14px; padding: 0 4px; }
|
|
.remove-btn:hover { color: #ff4444; }
|
|
.no-selection { color: #888; font-style: italic; font-size: 11px; }
|
|
.control-buttons { display: flex; gap: 4px; margin-top: 8px; flex-wrap: wrap; }
|
|
.control-btn { padding: 4px 8px; border: none; border-radius: 3px; cursor: pointer; font-size: 10px; color: #fff; }
|
|
.control-btn:hover { opacity: 0.8; }
|
|
.control-btn.clear { background: #ff6b6b; }
|
|
.control-btn.close-up { background: #FF6B6B; }
|
|
.control-btn.medium { background: #FFD93D; color: #333; }
|
|
.control-btn.wide { background: #6BCB77; }
|
|
.bottom-controls { display: flex; gap: 8px; margin-top: 8px; align-items: center; flex-wrap: wrap; }
|
|
.legend { display: flex; gap: 8px; font-size: 10px; align-items: center; }
|
|
.legend-item { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; padding: 2px 6px; border-radius: 3px; }
|
|
.legend-item:hover { background: rgba(255,255,255,0.1); }
|
|
.legend-item.layer-hidden { opacity: 0.4; }
|
|
.legend-item.layer-hidden span:last-child { text-decoration: line-through; }
|
|
.legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
|
|
`;
|
|
|
|
function getTemplate() {
|
|
return `
|
|
<style>${STYLES}</style>
|
|
<div class="canvas-container"></div>
|
|
<div class="selection-display"><div class="no-selection">${t('noSelection')}</div></div>
|
|
<div class="control-buttons">
|
|
<button class="control-btn clear">${t('clearAll')}</button>
|
|
<button class="control-btn close-up">${t('selectAllCloseUp')}</button>
|
|
<button class="control-btn medium">${t('selectAllMedium')}</button>
|
|
<button class="control-btn wide">${t('selectAllWide')}</button>
|
|
</div>
|
|
<div class="legend">
|
|
<div class="legend-item" data-layer="0"><span class="legend-dot" style="background:#FF6B6B"></span><span>${t('closeUp')}</span></div>
|
|
<div class="legend-item" data-layer="1"><span class="legend-dot" style="background:#FFD93D"></span><span>${t('medium')}</span></div>
|
|
<div class="legend-item" data-layer="2"><span class="legend-dot" style="background:#6BCB77"></span><span>${t('wide')}</span></div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "Comfy.AnglesSelector3D",
|
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData.name !== "AnglesSelector3D") return;
|
|
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = async function() {
|
|
if (onNodeCreated) onNodeCreated.apply(this, arguments);
|
|
|
|
this.selector3D = null;
|
|
this.size = [420, 520];
|
|
|
|
const container = document.createElement('div');
|
|
container.className = 'angles-selector-container';
|
|
container.innerHTML = getTemplate();
|
|
|
|
this.addDOMWidget("selector3d", "custom", container, { serialize: false, hideOnZoom: false });
|
|
|
|
this.selector3D = new AnglesSelector3DWidget(this, container);
|
|
await this.selector3D.init();
|
|
|
|
// 隐藏 selected_points 文本输入框(但保留其功能)
|
|
const selectedPointsWidget = this.widgets?.find(w => w.name === "selected_points");
|
|
if (selectedPointsWidget) {
|
|
selectedPointsWidget.computeSize = () => [0, 0];
|
|
selectedPointsWidget.type = "converted-widget";
|
|
selectedPointsWidget.hidden = true;
|
|
if (selectedPointsWidget.inputEl) {
|
|
selectedPointsWidget.inputEl.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
container.querySelector('.control-btn.clear').onclick = () => this.selector3D.clearAll();
|
|
container.querySelector('.control-btn.close-up').onclick = () => this.selector3D.selectLayer(0);
|
|
container.querySelector('.control-btn.medium').onclick = () => this.selector3D.selectLayer(1);
|
|
container.querySelector('.control-btn.wide').onclick = () => this.selector3D.selectLayer(2);
|
|
|
|
// 图例点击切换层可见性
|
|
container.querySelectorAll('.legend-item').forEach(item => {
|
|
item.onclick = (e) => {
|
|
e.stopPropagation();
|
|
const layer = parseInt(item.dataset.layer);
|
|
const visible = this.selector3D.toggleLayerVisibility(layer);
|
|
item.classList.toggle('layer-hidden', !visible);
|
|
};
|
|
});
|
|
};
|
|
|
|
const onRemoved = nodeType.prototype.onRemoved;
|
|
nodeType.prototype.onRemoved = function() {
|
|
if (onRemoved) onRemoved.apply(this, arguments);
|
|
if (this.selector3D) this.selector3D.destroy();
|
|
};
|
|
}
|
|
});
|