182 lines
6.5 KiB
Markdown
182 lines
6.5 KiB
Markdown
/*
|
|

|
|
|
|
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
|
|
|

|
|
|
|
This script will add encapsulating boxes around each of the currently selected groups in Excalidraw.
|
|
|
|
You can focus on content creation first, and then batch add consistent style boxes to each group of text.
|
|
|
|
Tips 1: You can copy the desired style to the global state using script `Copy Selected Element Style to Global`, then add boxes with the same global style using script `Box Each Selected Groups`.
|
|
|
|
Tips 2: Next you can use scripts `Expand rectangles horizontally keep text centered` and `Expand rectangles vertically keep text centered` to make the boxes the same size, if you wish.
|
|
|
|
Tips 3: If you want the left and right margins to be different from the top and bottom margins, input something like `32,16`, this will create a box with left and right margins of `32` and top and bottom margins of `16`.
|
|
|
|
See documentation for more details:
|
|
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
|
|
|
```javascript
|
|
*/
|
|
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
|
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
|
return;
|
|
}
|
|
settings = ea.getScriptSettings();
|
|
//set default values on first run
|
|
if(!settings["Default padding"]) {
|
|
settings = {
|
|
"Prompt for padding?": true,
|
|
"Default padding" : {
|
|
value: 10,
|
|
description: "Padding between the bounding box of the selected elements, and the box the script creates"
|
|
},
|
|
"Remember last padding?": false
|
|
};
|
|
ea.setScriptSettings(settings);
|
|
}
|
|
|
|
let paddingStr = settings["Default padding"].value.toString();
|
|
const rememberLastPadding = settings["Remember last padding?"];
|
|
|
|
if(settings["Prompt for padding?"]) {
|
|
paddingStr = await utils.inputPrompt("padding?","string",paddingStr);
|
|
}
|
|
if(!paddingStr) {
|
|
return;
|
|
}
|
|
if(rememberLastPadding) {
|
|
settings["Default padding"].value = paddingStr;
|
|
ea.setScriptSettings(settings);
|
|
}
|
|
var paddingLR = 0;
|
|
var paddingTB = 0;
|
|
if(paddingStr.indexOf(',') > 0) {
|
|
const paddingParts = paddingStr.split(',');
|
|
paddingLR = parseInt(paddingParts[0]);
|
|
paddingTB = parseInt(paddingParts[1]);
|
|
}
|
|
else {
|
|
paddingLR = paddingTB = parseInt(paddingStr);
|
|
}
|
|
|
|
if(isNaN(paddingLR) || isNaN(paddingTB)) {
|
|
return;
|
|
}
|
|
|
|
const selectedElements = ea.getViewSelectedElements();
|
|
const groups = ea.getMaximumGroups(selectedElements);
|
|
const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements())
|
|
.reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ?
|
|
[...result, group[0]] : result, []);
|
|
for(const elements of groups) {
|
|
if(elements.length === 1 && elements[0].type ==="arrow" || elements[0].type==="line") {
|
|
// individual arrows or lines are not affected
|
|
continue;
|
|
}
|
|
const box = ea.getBoundingBox(elements);
|
|
color = ea
|
|
.getExcalidrawAPI()
|
|
.getAppState()
|
|
.currentItemStrokeColor;
|
|
// use current stroke with and style
|
|
const appState = ea.getExcalidrawAPI().getAppState();
|
|
const strokeWidth = appState.currentItemStrokeWidth;
|
|
const strokeStyle = appState.currentItemStrokeStyle;
|
|
const strokeSharpness = appState.currentItemStrokeSharpness;
|
|
const roughness = appState.currentItemRoughness;
|
|
const fillStyle = appState.currentItemFillStyle;
|
|
const backgroundColor = appState.currentItemBackgroundColor;
|
|
ea.style.strokeWidth = strokeWidth;
|
|
ea.style.strokeStyle = strokeStyle;
|
|
ea.style.strokeSharpness = strokeSharpness;
|
|
ea.style.roughness = roughness;
|
|
ea.style.fillStyle = fillStyle;
|
|
ea.style.backgroundColor = backgroundColor;
|
|
ea.style.strokeColor = color;
|
|
|
|
const id = ea.addRect(
|
|
box.topX - paddingLR,
|
|
box.topY - paddingTB,
|
|
box.width + 2*paddingLR,
|
|
box.height + 2*paddingTB
|
|
);
|
|
|
|
// Change the join point in the group to the new box
|
|
const elementsWithBounded = elements.filter(el => (el.boundElements || []).length > 0);
|
|
const boundedElementsCollection = elementsWithBounded.reduce((result, el) => [...result, ...el.boundElements], []);
|
|
for(const el of elementsWithBounded) {
|
|
el.boundElements = [];
|
|
}
|
|
|
|
const newRect = ea.getElement(id);
|
|
newRect.boundElements = boundedElementsCollection;
|
|
|
|
const elementIds = elements.map(el => el.id);
|
|
|
|
const startBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.startBinding||{}).elementId));
|
|
for(startBindingLine of startBindingLines) {
|
|
startBindingLine.startBinding.elementId = id;
|
|
recalculateStartPointOfLine(startBindingLine, newRect);
|
|
}
|
|
|
|
const endBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.endBinding||{}).elementId));
|
|
for(endBindingLine of endBindingLines) {
|
|
endBindingLine.endBinding.elementId = id;
|
|
recalculateEndPointOfLine(endBindingLine, newRect);
|
|
}
|
|
|
|
ea.copyViewElementsToEAforEditing(elements);
|
|
ea.addToGroup([id].concat(elements.map((el)=>el.id)));
|
|
}
|
|
|
|
await ea.addElementsToView(false,false);
|
|
|
|
function recalculateStartPointOfLine(line, el) {
|
|
const aX = el.x + el.width/2;
|
|
const bX = line.x + line.points[1][0];
|
|
const aY = el.y + el.height/2;
|
|
const bY = line.y + line.points[1][1];
|
|
|
|
line.startBinding.gap = 8;
|
|
line.startBinding.focus = 0;
|
|
const intersectA = ea.intersectElementWithLine(
|
|
el,
|
|
[bX, bY],
|
|
[aX, aY],
|
|
line.startBinding.gap
|
|
);
|
|
|
|
if(intersectA.length > 0) {
|
|
line.points[0] = [0, 0];
|
|
for(var i = 1; i<line.points.length; i++) {
|
|
line.points[i][0] -= intersectA[0][0] - line.x;
|
|
line.points[i][1] -= intersectA[0][1] - line.y;
|
|
}
|
|
line.x = intersectA[0][0];
|
|
line.y = intersectA[0][1];
|
|
}
|
|
}
|
|
|
|
function recalculateEndPointOfLine(line, el) {
|
|
const aX = el.x + el.width/2;
|
|
const bX = line.x + line.points[line.points.length-2][0];
|
|
const aY = el.y + el.height/2;
|
|
const bY = line.y + line.points[line.points.length-2][1];
|
|
|
|
line.endBinding.gap = 8;
|
|
line.endBinding.focus = 0;
|
|
const intersectA = ea.intersectElementWithLine(
|
|
el,
|
|
[bX, bY],
|
|
[aX, aY],
|
|
line.endBinding.gap
|
|
);
|
|
|
|
if(intersectA.length > 0) {
|
|
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
|
}
|
|
}
|