vault backup: 2023-03-08 10:17:01

This commit is contained in:
2023-03-08 10:17:01 +01:00
parent 2afe227b2f
commit 82650694a2
24 changed files with 218137 additions and 38 deletions

View File

@@ -0,0 +1,784 @@
---
excalidraw-plugin: parsed
tags: [excalidraw]
---
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==
# Text Elements
%%
# Drawing
```compressed-json
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
CirpgxE0hfRtELESqFy7ZQfBB9guU2S3maUbyTwSh1TBtqukmMUZIiSKSBfZHLxJ
8F/ot2blAyf6uuA4ILe+fa4DmEMo+q3gnk5OlZIjo6bLJAU7TcOGQIMIjNnq44PD
KdWQVtk1wGTTbV4rjFqMLgkPhHWckqb2yxqyCr2wop5hC65mjSQ8UbQmTfGXRZoJ
cCHB6K41utCMYmpxnJrYxqa3UjMqhoMa5eCy7vnmokA8JNAyOIQNaB4TGZauG0Zw
BtDhAYEoAhAR8B+EbWNNkZ0wp7o8vgaJsXlQIDsUHhMUUMsO6wixX8qVlX4gVt+W
NlrLnU6yX500t+W/zhVzSV1v+Xhsw0tkeKnh+eB7uMROAtYh4Hw6JYFE/QIwji44
K9Z+JvVzkqV94mlb50fVPS3150ggWyuZ4crvpNElQpSNw0X1ZCSE3DZiJ5W4aSNY
hZOaQvp6BEPtJEoCYEX+101Qd8eTDWBNFqfkoKmG2Xvi0PJxFoWjAojcxrR3aqmi
uqyEs5tRKokK+dc51cgXMm6bzNdkXlmMkLmub/e+YG4BGBc16aq64YROhZK810lQ
wGKWycfCDXTFJwwnBME4KfEaiZJz6QqOcWC0i7uGFBGNVpuRyXAiS5xcIQcX51jJ
n03mQSiFquJGqTeXReyrGo8qxzYtoy5uZK1bmJaW+aa9vqhXZ6LLH2Qi3Rj0D2hM
ItoYoD1DwnwBNAOAj4ZYD0BSCMJNAcAWrc600kbyeCw8Jqs8tbUdiGNR/HqoOp+X
DqIApMfrbgwnXAqp1oKzWY4u1lP9xtestxVNo8UzaNqq6+bX/03Vort1D6aUIKUu
CVoIlR6myCBqgG9YBO38M2saMO0srjtwPJFKkvgy+jswV2ple+tbmfrV2360ja9p
YG79lV3BWfbBOY30jSadG2XiTLxGwt59bhX6dDvxFL6IdRIgQbhveUEtodzImLSf
r5WK9MNfaqGtvrQry06N0GujcUog3fS39dShQdnJXaNKQpbJccNZS01hRy+QYTzT
TreAN7TNedd1XSXc1gGddTOyAwiVoq7A+W5Ouney0Z3mbg5odNnRAaZLN03VBBin
Z8QLrs6HBXRaA+NFgMOCnImMAMQQZE6bETg/mnwScAF0JDaDbmu0S3XQO91QoZlO
4vJRkpMLSNkUk3UmvN2cLkt6a2ZanjEF266hyyiQNsGxx3gWg1QJoKQEziEAKAxA
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
EXNt1bwcB9kz1f9YAG3AQAbcCAA=
```
%%

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,399 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg)
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.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-auto-layout.png)
This script performs automatic layout for the selected top-level grouping objects. It is powered by [elkjs](https://github.com/kieler/elkjs) and needs to be connected to the Internet.
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["Layout Options JSON"]) {
settings = {
"Layout Options JSON": {
height: "450px",
value: `{\n "org.eclipse.elk.layered.crossingMinimization.semiInteractive": "true",\n "org.eclipse.elk.layered.considerModelOrder.components": "FORCE_MODEL_ORDER"\n}`,
description: `You can use layout options to configure the layout algorithm. A list of all options and further details of their exact effects is available in <a href="http://www.eclipse.org/elk/reference.html" rel="nofollow">ELK's documentation</a>.`,
},
};
ea.setScriptSettings(settings);
}
if (typeof ELK === "undefined") {
loadELK(doAutoLayout);
} else {
doAutoLayout();
}
async function doAutoLayout() {
const selectedElements = ea.getViewSelectedElements();
const groups = ea
.getMaximumGroups(selectedElements)
.map((g) => g.filter((el) => el.containerId == null)) // ignore text in stickynote
.filter((els) => els.length > 0);
const stickynotesMap = selectedElements
.filter((el) => el.containerId != null)
.reduce((result, el) => {
result.set(el.containerId, el);
return result;
}, new Map());
const elk = new ELK();
const knownLayoutAlgorithms = await elk.knownLayoutAlgorithms();
const layoutAlgorithms = knownLayoutAlgorithms
.map((knownLayoutAlgorithm) => ({
id: knownLayoutAlgorithm.id,
displayText:
knownLayoutAlgorithm.id === "org.eclipse.elk.layered" ||
knownLayoutAlgorithm.id === "org.eclipse.elk.radial" ||
knownLayoutAlgorithm.id === "org.eclipse.elk.mrtree"
? "* " +
knownLayoutAlgorithm.name +
": " +
knownLayoutAlgorithm.description
: knownLayoutAlgorithm.name + ": " + knownLayoutAlgorithm.description,
}))
.sort((lha, rha) => lha.displayText.localeCompare(rha.displayText));
const layoutAlgorithmsSimple = knownLayoutAlgorithms
.map((knownLayoutAlgorithm) => ({
id: knownLayoutAlgorithm.id,
displayText:
knownLayoutAlgorithm.id === "org.eclipse.elk.layered" ||
knownLayoutAlgorithm.id === "org.eclipse.elk.radial" ||
knownLayoutAlgorithm.id === "org.eclipse.elk.mrtree"
? "* " + knownLayoutAlgorithm.name
: knownLayoutAlgorithm.name,
}))
.sort((lha, rha) => lha.displayText.localeCompare(rha.displayText));
// const knownOptions = knownLayoutAlgorithms
// .reduce(
// (result, knownLayoutAlgorithm) => [
// ...result,
// ...knownLayoutAlgorithm.knownOptions,
// ],
// []
// )
// .filter((value, index, self) => self.indexOf(value) === index) // remove duplicates
// .sort((lha, rha) => lha.localeCompare(rha));
// console.log("knownOptions", knownOptions);
const selectedAlgorithm = await utils.suggester(
layoutAlgorithms.map((algorithmInfo) => algorithmInfo.displayText),
layoutAlgorithms.map((algorithmInfo) => algorithmInfo.id),
"Layout algorithm"
);
const knownNodePlacementStrategy = [
"SIMPLE",
"INTERACTIVE",
"LINEAR_SEGMENTS",
"BRANDES_KOEPF",
"NETWORK_SIMPLEX",
];
const knownDirections = [
"UNDEFINED",
"RIGHT",
"LEFT",
"DOWN",
"UP"
];
let nodePlacementStrategy = "BRANDES_KOEPF";
let componentComponentSpacing = "10";
let nodeNodeSpacing = "100";
let nodeNodeBetweenLayersSpacing = "100";
let discoComponentLayoutAlgorithm = "org.eclipse.elk.layered";
let direction = "UNDEFINED";
if (selectedAlgorithm === "org.eclipse.elk.layered") {
nodePlacementStrategy = await utils.suggester(
knownNodePlacementStrategy,
knownNodePlacementStrategy,
"Node placement strategy"
);
selectedDirection = await utils.suggester(
knownDirections,
knownDirections,
"Direction"
);
direction = selectedDirection??"UNDEFINED";
} else if (selectedAlgorithm === "org.eclipse.elk.disco") {
const componentLayoutAlgorithms = layoutAlgorithmsSimple.filter(al => al.id !== "org.eclipse.elk.disco");
const selectedDiscoComponentLayoutAlgorithm = await utils.suggester(
componentLayoutAlgorithms.map((algorithmInfo) => algorithmInfo.displayText),
componentLayoutAlgorithms.map((algorithmInfo) => algorithmInfo.id),
"Disco Connected Components Layout Algorithm"
);
discoComponentLayoutAlgorithm = selectedDiscoComponentLayoutAlgorithm??"org.eclipse.elk.layered";
}
if (
selectedAlgorithm === "org.eclipse.elk.box" ||
selectedAlgorithm === "org.eclipse.elk.rectpacking"
) {
nodeNodeSpacing = await utils.inputPrompt("Node Spacing", "number", "10");
} else {
let userSpacingStr = await utils.inputPrompt(
"Components Spacing, Node Spacing, Node Node Between Layers Spacing",
"number, number, number",
"10, 100, 100"
);
let userSpacingArr = (userSpacingStr??"").split(",");
componentComponentSpacing = userSpacingArr[0] ?? "10";
nodeNodeSpacing = userSpacingArr[1] ?? "100";
nodeNodeBetweenLayersSpacing = userSpacingArr[2] ?? "100";
}
let layoutOptionsJson = {};
try {
layoutOptionsJson = JSON.parse(settings["Layout Options JSON"].value);
} catch (e) {
new Notice(
"Error reading Layout Options JSON, see developer console for more information",
4000
);
console.log(e);
}
layoutOptionsJson["elk.algorithm"] = selectedAlgorithm;
layoutOptionsJson["org.eclipse.elk.spacing.componentComponent"] =
componentComponentSpacing;
layoutOptionsJson["org.eclipse.elk.spacing.nodeNode"] = nodeNodeSpacing;
layoutOptionsJson["org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers"] =
nodeNodeBetweenLayersSpacing;
layoutOptionsJson["org.eclipse.elk.layered.nodePlacement.strategy"] =
nodePlacementStrategy;
layoutOptionsJson["org.eclipse.elk.disco.componentCompaction.componentLayoutAlgorithm"] =
discoComponentLayoutAlgorithm;
layoutOptionsJson["org.eclipse.elk.direction"] = direction;
const graph = {
id: "root",
layoutOptions: layoutOptionsJson,
children: [],
edges: [],
};
let groupMap = new Map();
let targetElkMap = new Map();
let arrowEls = [];
for (let i = 0; i < groups.length; i++) {
const elements = groups[i];
if (
elements.length === 1 &&
(elements[0].type === "arrow" || elements[0].type === "line")
) {
if (
elements[0].type === "arrow" &&
elements[0].startBinding &&
elements[0].endBinding
) {
arrowEls.push(elements[0]);
}
} else {
let elkId = "g" + i;
elements.reduce((result, el) => {
result.set(el.id, elkId);
return result;
}, targetElkMap);
const box = ea.getBoundingBox(elements);
groupMap.set(elkId, {
elements: elements,
boundingBox: box,
});
graph.children.push({
id: elkId,
width: box.width,
height: box.height,
x: box.topX,
y: box.topY,
});
}
}
for (let i = 0; i < arrowEls.length; i++) {
const arrowEl = arrowEls[i];
const startElkId = targetElkMap.get(arrowEl.startBinding.elementId);
const endElkId = targetElkMap.get(arrowEl.endBinding.elementId);
graph.edges.push({
id: "e" + i,
sources: [startElkId],
targets: [endElkId],
});
}
const initTopX =
Math.min(...Array.from(groupMap.values()).map((v) => v.boundingBox.topX)) -
12;
const initTopY =
Math.min(...Array.from(groupMap.values()).map((v) => v.boundingBox.topY)) -
12;
elk
.layout(graph)
.then((resultGraph) => {
for (const elkEl of resultGraph.children) {
const group = groupMap.get(elkEl.id);
for (const groupEl of group.elements) {
const originalDistancX = groupEl.x - group.boundingBox.topX;
const originalDistancY = groupEl.y - group.boundingBox.topY;
const groupElDistanceX =
elkEl.x + initTopX + originalDistancX - groupEl.x;
const groupElDistanceY =
elkEl.y + initTopY + originalDistancY - groupEl.y;
groupEl.x = groupEl.x + groupElDistanceX;
groupEl.y = groupEl.y + groupElDistanceY;
if (stickynotesMap.has(groupEl.id)) {
const stickynote = stickynotesMap.get(groupEl.id);
stickynote.x = stickynote.x + groupElDistanceX;
stickynote.y = stickynote.y + groupElDistanceY;
}
}
}
ea.copyViewElementsToEAforEditing(selectedElements);
ea.addElementsToView(false, false);
normalizeSelectedArrows();
})
.catch(console.error);
}
function loadELK(doAfterLoaded) {
let script = document.createElement("script");
script.onload = function () {
if (typeof ELK !== "undefined") {
doAfterLoaded();
}
};
script.src =
"https://cdn.jsdelivr.net/npm/elkjs@0.8.2/lib/elk.bundled.min.js";
document.head.appendChild(script);
}
/*
* Normalize Selected Arrows
*/
function normalizeSelectedArrows() {
let gapValue = 2;
const selectedIndividualArrows = ea.getMaximumGroups(ea.getViewSelectedElements())
.reduce((result, g) => [...result, ...g.filter(el => el.type === 'arrow')], []);
const allElements = ea.getViewElements();
for (const arrow of selectedIndividualArrows) {
const startBindingEl = allElements.filter(
(el) => el.id === (arrow.startBinding || {}).elementId
)[0];
const endBindingEl = allElements.filter(
(el) => el.id === (arrow.endBinding || {}).elementId
)[0];
if (startBindingEl) {
recalculateStartPointOfLine(
arrow,
startBindingEl,
endBindingEl,
gapValue
);
}
if (endBindingEl) {
recalculateEndPointOfLine(arrow, endBindingEl, startBindingEl, gapValue);
}
}
ea.copyViewElementsToEAforEditing(selectedIndividualArrows);
ea.addElementsToView(false, false);
}
function recalculateStartPointOfLine(line, el, elB, gapValue) {
const aX = el.x + el.width / 2;
const bX =
line.points.length <= 2 && elB
? elB.x + elB.width / 2
: line.x + line.points[1][0];
const aY = el.y + el.height / 2;
const bY =
line.points.length <= 2 && elB
? elB.y + elB.height / 2
: line.y + line.points[1][1];
line.startBinding.gap = gapValue;
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 (let 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, elB, gapValue) {
const aX = el.x + el.width / 2;
const bX =
line.points.length <= 2 && elB
? elB.x + elB.width / 2
: line.x + line.points[line.points.length - 2][0];
const aY = el.y + el.height / 2;
const bY =
line.points.length <= 2 && elB
? elB.y + elB.height / 2
: line.y + line.points[line.points.length - 2][1];
line.endBinding.gap = gapValue;
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,
];
}
}

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1670131481615" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3504" width="128" height="128" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M947.2 0H76.8C33.6 0 0 33.6 0 76.8v870.4C0 990.4 33.6 1024 76.8 1024h870.4c38.4 0 72-30.4 76.8-68.8V76.8C1024 33.6 990.4 0 947.2 0zM84.8 84.8h852.8V256H84.8V84.8z m256 256h596.8v256H340.8v-256z m-256 598.4V340.8H256v596.8H84.8z m256 0v-256h596.8v256H340.8z" p-id="3505"></path></svg>

After

Width:  |  Height:  |  Size: 616 B

View File

@@ -0,0 +1,55 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-box-elements.jpg)
This script will add an encapsulating box around the currently selected elements in Excalidraw.
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"
}
};
ea.setScriptSettings(settings);
}
let padding = settings["Default padding"].value;
if(settings["Prompt for padding?"]) {
padding = parseInt (await utils.inputPrompt("padding?","number",padding.toString()));
}
if(isNaN(padding)) {
new Notice("The padding value provided is not a number");
return;
}
elements = ea.getViewSelectedElements();
const box = ea.getBoundingBox(elements);
color = ea
.getExcalidrawAPI()
.getAppState()
.currentItemStrokeColor;
//uncomment for random color:
//color = '#'+(Math.random()*0xFFFFFF<<0).toString(16).padStart(6,"0");
ea.style.strokeColor = color;
id = ea.addRect(
box.topX - padding,
box.topY - padding,
box.width + 2*padding,
box.height + 2*padding
);
ea.copyViewElementsToEAforEditing(elements);
ea.addToGroup([id].concat(elements.map((el)=>el.id)));
ea.addElementsToView(false,false);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 80 500 400"><path d="M164.27 110.96h158.32v-28H136.27v170.87h28zM377.42 110.96h158.32v142.87h28V82.96H377.42zM535.73 449.04H377.41v28h186.32V306.17h-28zM164.27 306.16h-28v170.87h186.32v-28H164.27z"/><path d="M197.86 220.36v119.3c0 42.34 34.445 76.789 76.793 76.789h150.68c42.348 0 76.793-34.445 76.793-76.789l.004-119.3c0-42.34-34.445-76.789-76.793-76.789h-150.69c-42.348-.004-76.793 34.445-76.793 76.789zm276.27 0v119.3c0 26.902-21.887 48.789-48.793 48.789l-150.69-.004c-26.906 0-48.793-21.887-48.793-48.789v-119.29c0-26.902 21.887-48.789 48.793-48.789h150.68c26.91-.004 48.797 21.88 48.797 48.79z"/></svg>

After

Width:  |  Height:  |  Size: 660 B

View File

@@ -0,0 +1,81 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-connect-elements.jpg)
This script will connect two objects with an arrow. If either of the objects are a set of grouped elements (e.g. a text element grouped with an encapsulating rectangle), the script will identify these groups, and connect the arrow to the largest object in the group (assuming you want to connect the arrow to the box around the text element).
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["Starting arrowhead"]) {
settings = {
"Starting arrowhead" : {
value: "none",
valueset: ["none","arrow","triangle","bar","dot"]
},
"Ending arrowhead" : {
value: "triangle",
valueset: ["none","arrow","triangle","bar","dot"]
},
"Line points" : {
value: 1,
description: "Number of line points between start and end"
}
};
ea.setScriptSettings(settings);
}
const arrowStart = settings["Starting arrowhead"].value === "none" ? null : settings["Starting arrowhead"].value;
const arrowEnd = settings["Ending arrowhead"].value === "none" ? null : settings["Ending arrowhead"].value;
const linePoints = Math.floor(settings["Line points"].value);
const elements = ea.getViewSelectedElements();
ea.copyViewElementsToEAforEditing(elements);
groups = ea.getMaximumGroups(elements);
if(groups.length !== 2) {
//unfortunately getMaxGroups returns duplicated resultset for sticky notes
//needs additional filtering
cleanGroups=[];
idList = [];
for (group of groups) {
keep = true;
for(item of group) if(idList.contains(item.id)) keep = false;
if(keep) {
cleanGroups.push(group);
idList = idList.concat(group.map(el=>el.id))
}
}
if(cleanGroups.length !== 2) return;
groups = cleanGroups;
}
els = [
ea.getLargestElement(groups[0]),
ea.getLargestElement(groups[1])
];
ea.style.strokeColor = els[0].strokeColor;
ea.style.strokeWidth = els[0].strokeWidth;
ea.style.strokeStyle = els[0].strokeStyle;
ea.style.strokeSharpness = els[0].strokeSharpness;
ea.connectObjects(
els[0].id,
null,
els[1].id,
null,
{
endArrowHead: arrowEnd,
startArrowHead: arrowStart,
numberOfPoints: linePoints
}
);
ea.addElementsToView(false,false,true);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 170 70" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h60m-60 0h60m0 0v60m0-60v60m0 0H10m60 0H10m0 0V10m0 60V10"/><g stroke-linecap="round"><path fill="none" stroke-width="4" d="M70 40h40m-40 0h40"/><path fill-rule="evenodd" stroke-width="0" d="m110 40-13.59 6.34V33.66L110 40"/><path fill="none" stroke-width="4" d="M110 40c-4.72 2.2-9.43 4.4-13.59 6.34M110 40c-4.7 2.19-9.4 4.38-13.59 6.34m0 0V33.66m0 12.68V33.66m0 0c5.07 2.37 10.14 4.73 13.59 6.34m-13.59-6.34c3.25 1.52 6.51 3.04 13.59 6.34m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M110 10h60m-60 0h60m0 0v60m0-60v60m0 0h-60m60 0h-60m0 0V10m0 60V10"/></svg>

After

Width:  |  Height:  |  Size: 753 B

View File

@@ -0,0 +1,64 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-convert-freedraw-to-line.jpg)
Convert selected freedraw objects into editable lines. This will allow you to adjust your drawings by dragging line points and will also allow you to select shape fill in case of enclosed lines. You can adjust conversion point density in settings.
```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["Point density"]) {
settings = {
"Point density" : {
value: "7:1",
valueset: ["1:1","2:1","3:1","4:1","5:1","6:1","7:1","8:1","9:1","10:1","11:1"],
description: "A freedraw object has many points. Converting freedraw to a line with too many points will result in an impractical object that is hard to edit. This setting sepcifies how many points from freedraw should be averaged to form a point on the line"
},
};
ea.setScriptSettings(settings);
}
const scale = settings["Point density"].value;
const setSize = parseInt(scale.substring(0,scale.indexOf(":")));
const elements = ea.getViewSelectedElements().filter(el=>el.type==="freedraw");
if(elements.length === 0) {
new Notice("No freedraw object is selected");
}
ea.style.roughness=0;
ea.style.strokeSharpness="round";
elements.forEach((el)=>{
points = [];
points.push(el.points[0]);
for(i=1;i<el.points.length;i+=setSize) {
point = [0,0];
count = 0;
for(p of el.points.slice(i,i+setSize)) {
point = [ point[0]+p[0] , point[1]+p[1] ];
count++;
}
point = [point[0]/count,point[1]/count];
points.push(point);
}
const lineId = ea.addLine(points);
const line = ea.getElement(lineId);
line.strokeWidth = el.strokeWidth*3;
line.strokeColor = el.strokeColor;
line.width = el.width;
line.height = el.height;
line.x = el.x;
line.y = el.y;
});
ea.deleteViewElements(elements);
await ea.addElementsToView(false,false,true);
ea.selectElementsInView(ea.getElements());

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M480 256c-17.67 0-32 14.31-32 32c0 52.94-43.06 96-96 96H192L192 344c0-9.469-5.578-18.06-14.23-21.94C169.1 318.3 159 319.8 151.9 326.2l-80 72C66.89 402.7 64 409.2 64 416s2.891 13.28 7.938 17.84l80 72C156.4 509.9 162.2 512 168 512c3.312 0 6.615-.6875 9.756-2.062C186.4 506.1 192 497.5 192 488L192 448h160c88.22 0 160-71.78 160-160C512 270.3 497.7 256 480 256zM160 128h159.1L320 168c0 9.469 5.578 18.06 14.23 21.94C337.4 191.3 340.7 192 343.1 192c5.812 0 11.57-2.125 16.07-6.156l80-72C445.1 109.3 448 102.8 448 95.1s-2.891-13.28-7.938-17.84l-80-72c-7.047-6.312-17.19-7.875-25.83-4.094C325.6 5.938 319.1 14.53 319.1 24L320 64H160C71.78 64 0 135.8 0 224c0 17.69 14.33 32 32 32s32-14.31 32-32C64 171.1 107.1 128 160 128z"/></svg>

After

Width:  |  Height:  |  Size: 794 B

View File

@@ -0,0 +1,93 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg)
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.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/elbow-connectors.png)
This script converts the selected connectors to elbows.
See documentation for more details:
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
```javascript
*/
const selectedCenterConnectPoints = await utils.suggester(
['Yes', 'No'],
[true, false],
"Center connect points?"
);
const centerConnectPoints = selectedCenterConnectPoints??false;
const allElements = ea.getViewElements();
const elements = ea.getViewSelectedElements();
const lines = elements.filter((el)=>el.type==="arrow" || el.type==="line");
for (const line of lines) {
if (line.points.length >= 3) {
if(centerConnectPoints) {
const startBindingEl = allElements.filter(el => el.id === (line.startBinding||{}).elementId)[0];
const endBindingEl = allElements.filter(el => el.id === (line.endBinding||{}).elementId)[0];
if(startBindingEl) {
const startPointX = line.x +line.points[0][0];
if(startPointX >= startBindingEl.x && startPointX <= startBindingEl.x + startBindingEl.width) {
line.points[0][0] = startBindingEl.x + startBindingEl.width / 2 - line.x;
}
const startPointY = line.y +line.points[0][1];
if(startPointY >= startBindingEl.y && startPointY <= startBindingEl.y + startBindingEl.height) {
line.points[0][1] = startBindingEl.y + startBindingEl.height / 2 - line.y;
}
}
if(endBindingEl) {
const startPointX = line.x +line.points[line.points.length-1][0];
if(startPointX >= endBindingEl.x && startPointX <= endBindingEl.x + endBindingEl.width) {
line.points[line.points.length-1][0] = endBindingEl.x + endBindingEl.width / 2 - line.x;
}
const startPointY = line.y +line.points[line.points.length-1][1];
if(startPointY >= endBindingEl.y && startPointY <= endBindingEl.y + endBindingEl.height) {
line.points[line.points.length-1][1] = endBindingEl.y + endBindingEl.height / 2 - line.y;
}
}
}
for (var i = 0; i < line.points.length - 2; i++) {
var p1;
var p3;
if (line.points[i][0] < line.points[i + 2][0]) {
p1 = line.points[i];
p3 = line.points[i+2];
} else {
p1 = line.points[i + 2];
p3 = line.points[i];
}
const p2 = line.points[i + 1];
if (p1[0] === p3[0]) {
continue;
}
const k = (p3[1] - p1[1]) / (p3[0] - p1[0]);
const b = p1[1] - k * p1[0];
y0 = k * p2[0] + b;
const up = p2[1] < y0;
if ((k > 0 && !up) || (k < 0 && up)) {
p2[0] = p1[0];
p2[1] = p3[1];
} else {
p2[0] = p3[0];
p2[1] = p1[1];
}
}
}
}
ea.copyViewElementsToEAforEditing(lines);
await ea.addElementsToView(false,false);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 120" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="8" d="M10 10v80m0-80v80m0 0h80m-80 0h80M70 70l20 20M70 70l20 20m0 0-20 20m20-20-20 20"/></svg>

After

Width:  |  Height:  |  Size: 226 B

View File

@@ -0,0 +1,116 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg)
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.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-repeat-elements.png)
This script will detect the difference between 2 selected elements, including position, size, angle, stroke and background color, and create several elements that repeat these differences based on the number of repetitions entered by the user.
See documentation for more details:
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
```javascript
*/
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.7.19")) {
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
return;
}
let repeatNum = parseInt(await utils.inputPrompt("repeat times?","number","5"));
if(!repeatNum) {
new Notice("Please enter a number.");
return;
}
const selectedElements = ea.getViewSelectedElements().sort((lha,rha) =>
lha.x === rha.x? (lha.y === rha.y?
(lha.width === rha.width?
(lha.height - rha.height) : lha.width - rha.width)
: lha.y - rha.y) : lha.x - rha.x);
if(selectedElements.length !== 2) {
new Notice("Please select 2 elements.");
return;
}
if(selectedElements[0].type !== selectedElements[1].type) {
new Notice("The selected elements must be of the same type.");
return;
}
const xDistance = selectedElements[1].x - selectedElements[0].x;
const yDistance = selectedElements[1].y - selectedElements[0].y;
const widthDistance = selectedElements[1].width - selectedElements[0].width;
const heightDistance = selectedElements[1].height - selectedElements[0].height;
const angleDistance = selectedElements[1].angle - selectedElements[0].angle;
const bgColor1 = ea.colorNameToHex(selectedElements[0].backgroundColor);
const cmBgColor1 = ea.getCM(bgColor1);
const bgColor2 = ea.colorNameToHex(selectedElements[1].backgroundColor);
let cmBgColor2 = ea.getCM(bgColor2);
const isBgTransparent = cmBgColor1.alpha === 0 || cmBgColor2.alpha === 0;
const bgHDistance = cmBgColor2.hue - cmBgColor1.hue;
const bgSDistance = cmBgColor2.saturation - cmBgColor1.saturation;
const bgLDistance = cmBgColor2.lightness - cmBgColor1.lightness;
const bgADistance = cmBgColor2.alpha - cmBgColor1.alpha;
const strokeColor1 = ea.colorNameToHex(selectedElements[0].strokeColor);
const cmStrokeColor1 = ea.getCM(strokeColor1);
const strokeColor2 = ea.colorNameToHex(selectedElements[1].strokeColor);
let cmStrokeColor2 = ea.getCM(strokeColor2);
const isStrokeTransparent = cmStrokeColor1.alpha === 0 || cmStrokeColor2.alpha ===0;
const strokeHDistance = cmStrokeColor2.hue - cmStrokeColor1.hue;
const strokeSDistance = cmStrokeColor2.saturation - cmStrokeColor1.saturation;
const strokeLDistance = cmStrokeColor2.lightness - cmStrokeColor1.lightness;
const strokeADistance = cmStrokeColor2.alpha - cmStrokeColor1.alpha;
ea.copyViewElementsToEAforEditing(selectedElements);
for(let i=0; i<repeatNum; i++) {
const newEl = ea.cloneElement(selectedElements[1]);
ea.elementsDict[newEl.id] = newEl;
newEl.x += xDistance * (i + 1);
newEl.y += yDistance * (i + 1);
newEl.angle += angleDistance * (i + 1);
const originWidth = newEl.width;
const originHeight = newEl.height;
const newWidth = newEl.width + widthDistance * (i + 1);
const newHeight = newEl.height + heightDistance * (i + 1);
if(newWidth >= 0 && newHeight >= 0) {
if(newEl.type === 'arrow' || newEl.type === 'line' || newEl.type === 'freedraw') {
const minX = Math.min(...newEl.points.map(pt => pt[0]));
const minY = Math.min(...newEl.points.map(pt => pt[1]));
for(let j = 0; j < newEl.points.length; j++) {
if(newEl.points[j][0] > minX) {
newEl.points[j][0] = newEl.points[j][0] + ((newEl.points[j][0] - minX) / originWidth) * (newWidth - originWidth);
}
if(newEl.points[j][1] > minY) {
newEl.points[j][1] = newEl.points[j][1] + ((newEl.points[j][1] - minY) / originHeight) * (newHeight - originHeight);
}
}
}
else {
newEl.width = newWidth;
newEl.height = newHeight;
}
}
if(!isBgTransparent) {
cmBgColor2 = cmBgColor2.hueBy(bgHDistance).saturateBy(bgSDistance).lighterBy(bgLDistance).alphaBy(bgADistance);
newEl.backgroundColor = cmBgColor2.stringHEX();
} else {
newEl.backgroundColor = "transparent";
}
if(!isStrokeTransparent) {
cmStrokeColor2 = cmStrokeColor2.hueBy(strokeHDistance).saturateBy(strokeSDistance).lighterBy(strokeLDistance).alphaBy(strokeADistance);
newEl.strokeColor = cmStrokeColor2.stringHEX();
} else {
newEl.strokeColor = "transparent";
}
}
await ea.addElementsToView(false, false, true);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 120" stroke="#000"><defs/><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 110h200m-200 0h200M30 90h160M30 90h160M50 70h120M50 70h120M70 50h80m-80 0h80M90 30h40m-40 0h40M110 10s0 0 0 0m0 0s0 0 0 0"/></svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -0,0 +1,49 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/text-arch.jpg)
Fit a text to the arch of a circle. The script will prompt you for the radius of the circle and then split your text to individual letters and place each letter to the arch defined by the radius. Setting a lower radius value will increase the arching of the text. Note that the arched-text will no longer be editable as a text element and it will no longer function as a markdown link. Emojis are currently not supported.
```javascript
*/
el = ea.getViewSelectedElement();
if(!el || el.type!=="text") {
new Notice("Please select a text element");
return;
}
ea.style.fontSize = el.fontSize;
ea.style.fontFamily = el.fontFamily;
ea.style.strokeColor = el.strokeColor;
ea.style.opacity = el.opacity;
const r = parseInt (await utils.inputPrompt("The radius of the arch you'd like to fit the text to","number","150"));
const archAbove = await utils.suggester(["Arch above","Arch below"],[true,false]);
if(isNaN(r)) {
new Notice("The radius is not a number");
return;
}
circlePoint = (angle) => archAbove
? [
r * Math.sin(angle),
-r * Math.cos(angle)
]
: [
-r * Math.sin(angle),
r * Math.cos(angle)
];
let rot = (archAbove ? -0.5 : 0.5) * ea.measureText(el.text).width/r;
let objectIDs = [];
for(i=0;i<el.text.length;i++) {
const character = el.text.substring(i,i+1);
const width = ea.measureText(character).width;
ea.style.angle = rot;
const [x,y] = circlePoint(rot);
rot += (archAbove ? 1 : -1) *width / r;
objectIDs.push(ea.addText(x,y,character));
}
ea.addToGroup(objectIDs);
ea.addElementsToView(true);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" stroke="#000" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><g stroke-width="2" fill="none"><circle cx="12" cy="12" r="10"></circle><path d="M17 12h.01"></path><path d="M12 12h.01"></path><path d="M7 12h.01"></path></g></svg>

After

Width:  |  Height:  |  Size: 327 B