Skip to content

Instantly share code, notes, and snippets.

@jmetzger
Created March 13, 2026 17:49
Show Gist options
  • Select an option

  • Save jmetzger/270d6927bb5fd63510b5875b8862859b to your computer and use it in GitHub Desktop.

Select an option

Save jmetzger/270d6927bb5fd63510b5875b8862859b to your computer and use it in GitHub Desktop.
/**
* draw.io Plugin: Quick Nodes
*
* Extras → "Quick Nodes" – eine Node-Bezeichnung pro Zeile.
* Zeichnet die Boxen in einem Raster auf dem Canvas.
*
* Installation:
* draw.io Desktop: Extras → Plugins → Add → diese Datei → Neustart
*/
Draw.loadPlugin(function (ui) {
ui.actions.addAction('quickNodes', function () {
var dlg = new QuickNodesDialog(ui);
ui.showDialog(dlg.container, 420, 380, true, true);
dlg.init();
});
var menu = ui.menus.get('extras');
if (menu) {
var origFunct = menu.funct;
menu.funct = function (m, parent) {
origFunct.apply(this, arguments);
ui.menus.addMenuItems(m, ['-', 'quickNodes'], parent);
};
}
function QuickNodesDialog(editorUi) {
var div = document.createElement('div');
div.style.padding = '8px';
var title = document.createElement('h3');
title.textContent = 'Quick Nodes';
title.style.margin = '0 0 8px 0';
div.appendChild(title);
var desc = document.createElement('p');
desc.style.margin = '0 0 12px 0';
desc.style.fontSize = '12px';
desc.style.color = '#666';
desc.textContent = 'Node-Namen mit Leerzeichen oder Zeilenumbruch getrennt:';
div.appendChild(desc);
var textarea = document.createElement('textarea');
textarea.style.width = '100%';
textarea.style.height = '180px';
textarea.style.fontFamily = 'monospace';
textarea.style.fontSize = '13px';
textarea.style.boxSizing = 'border-box';
textarea.style.padding = '8px';
textarea.style.border = '1px solid #ccc';
textarea.style.borderRadius = '4px';
textarea.value = 'node1 node2 node3 node4 node5';
div.appendChild(textarea);
// Columns selector
var colRow = document.createElement('div');
colRow.style.margin = '8px 0';
colRow.style.fontSize = '13px';
var colLabel = document.createElement('label');
colLabel.textContent = 'Spalten: ';
var colInput = document.createElement('input');
colInput.type = 'number';
colInput.min = '1';
colInput.max = '20';
colInput.value = '3';
colInput.style.width = '50px';
colRow.appendChild(colLabel);
colRow.appendChild(colInput);
div.appendChild(colRow);
var btnRow = document.createElement('div');
btnRow.style.marginTop = '12px';
btnRow.style.textAlign = 'right';
var cancelBtn = mxUtils.button(mxResources.get('cancel') || 'Cancel', function () {
editorUi.hideDialog();
});
cancelBtn.style.marginRight = '8px';
btnRow.appendChild(cancelBtn);
var okBtn = mxUtils.button(mxResources.get('apply') || 'Apply', function () {
var cols = parseInt(colInput.value, 10) || 3;
generateNodes(editorUi, textarea.value, cols);
editorUi.hideDialog();
});
okBtn.className = 'geBtn gePrimaryBtn';
btnRow.appendChild(okBtn);
div.appendChild(btnRow);
this.container = div;
}
QuickNodesDialog.prototype.init = function () {};
function generateNodes(editorUi, text, cols) {
var graph = editorUi.editor.graph;
var model = graph.getModel();
var parent = graph.getDefaultParent();
var names = text.trim().split(/\s+/)
.filter(function (l) { return l.length > 0; });
if (names.length === 0) return;
var boxW = 140;
var boxH = 40;
var gapX = 30;
var gapY = 30;
var startX = 40;
var startY = 40;
var fills = ['#dae8fc', '#d5e8d4', '#fff2cc', '#f8cecc', '#e1d5e7', '#d0e2f1', '#fce5cd'];
var strokes = ['#6c8ebf', '#82b366', '#d6b656', '#b85450', '#9673a6', '#5b8fbc', '#d79b00'];
model.beginUpdate();
try {
names.forEach(function (name, i) {
var col = i % cols;
var row = Math.floor(i / cols);
var x = startX + col * (boxW + gapX);
var y = startY + row * (boxH + gapY);
var ci = i % fills.length;
var style = 'rounded=1;whiteSpace=wrap;html=1;fillColor=' + fills[ci] +
';strokeColor=' + strokes[ci] + ';fontSize=13;fontStyle=1;';
graph.insertVertex(parent, null, name, x, y, boxW, boxH, style);
});
} finally {
model.endUpdate();
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment