This commit is contained in:
Zsolt Viczian
2022-02-19 00:00:52 +01:00
parent 2dc10af004
commit bc71bde9b7
15 changed files with 445 additions and 444 deletions

View File

@@ -1,378 +1,378 @@
/*
![](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
*/
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 = colorNameToHex(selectedElements[0].backgroundColor);
const rgbBgColor1 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(bgColor1);
const bgColor2 = colorNameToHex(selectedElements[1].backgroundColor);
const rgbBgColor2 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(bgColor2);
let bgHDistance = 0;
let bgSDistance = 0;
let bgLDistance = 0;
if(rgbBgColor1 && rgbBgColor2) {
const bgHsl1 = rgbToHsl([parseInt(rgbBgColor1[1], 16), parseInt(rgbBgColor1[2], 16), parseInt(rgbBgColor1[3], 16)]);
const bgHsl2 = rgbToHsl([parseInt(rgbBgColor2[1], 16), parseInt(rgbBgColor2[2], 16), parseInt(rgbBgColor2[3], 16)]);
bgHDistance = bgHsl2[0] - bgHsl1[0];
bgSDistance = bgHsl2[1] - bgHsl1[1];
bgLDistance = bgHsl2[2] - bgHsl1[2];
}
const strokeColor1 = colorNameToHex(selectedElements[0].strokeColor);
const rgbStrokeColor1 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(strokeColor1);
const strokeColor2 = colorNameToHex(selectedElements[1].strokeColor);
const rgbStrokeColor2 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(strokeColor2);
let strokeHDistance = 0;
let strokeSDistance = 0;
let strokeLDistance = 0;
if(rgbStrokeColor1 && rgbStrokeColor2) {
const strokeHsl1 = rgbToHsl([parseInt(rgbStrokeColor1[1], 16), parseInt(rgbStrokeColor1[2], 16), parseInt(rgbStrokeColor1[3], 16)]);
const strokeHsl2 = rgbToHsl([parseInt(rgbStrokeColor2[1], 16), parseInt(rgbStrokeColor2[2], 16), parseInt(rgbStrokeColor2[3], 16)]);
strokeHDistance = strokeHsl2[0] - strokeHsl1[0];
strokeSDistance = strokeHsl2[1] - strokeHsl1[1];
strokeLDistance = strokeHsl2[2] - strokeHsl1[2];
}
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(rgbBgColor1 && rgbBgColor2) {
const bgHsl2 = rgbToHsl([parseInt(rgbBgColor2[1], 16), parseInt(rgbBgColor2[2], 16), parseInt(rgbBgColor2[3], 16)]);
const newBgH = bgHsl2[0] + bgHDistance * (i + 1);
const newBgS = bgHsl2[1] + bgSDistance * (i + 1);
const newBgL = bgHsl2[2] + bgLDistance * (i + 1);
if(newBgH >= 0 && newBgH <= 360 && newBgS >= 0 && newBgS <= 100 && newBgL >= 0 && newBgL <= 100) {
const newBgRgb = hslToRgb([newBgH, newBgS, newBgL]);
newEl.backgroundColor = "#" + rgbToHexString(newBgRgb);
}
}
if(rgbStrokeColor1 && rgbStrokeColor2) {
const strokeHsl2 = rgbToHsl([parseInt(rgbStrokeColor2[1], 16), parseInt(rgbStrokeColor2[2], 16), parseInt(rgbStrokeColor2[3], 16)]);
const newStrokeH = strokeHsl2[0] + strokeHDistance * (i + 1);
const newStrokeS = strokeHsl2[1] + strokeSDistance * (i + 1);
const newStrokeL = strokeHsl2[2] + strokeLDistance * (i + 1);
if(newStrokeH >= 0 && newStrokeH <= 360 && newStrokeS >= 0 && newStrokeS <= 100 && newStrokeL >= 0 && newStrokeL <= 100) {
const newStrokeRgb = hslToRgb([newStrokeH, newStrokeS, newStrokeL]);
newEl.strokeColor = "#" + rgbToHexString(newStrokeRgb);
}
}
}
await ea.addElementsToView(false, true, true);
function rgbToHexString(args) {
const integer =
((Math.round(args[0]) & 0xff) << 16) +
((Math.round(args[1]) & 0xff) << 8) +
(Math.round(args[2]) & 0xff);
const string = integer.toString(16).toUpperCase();
return "000000".substring(string.length) + string;
}
function hslToRgb(hsl) {
const h = hsl[0] / 360;
const s = hsl[1] / 100;
const l = hsl[2] / 100;
let t2;
let t3;
let val;
if (s === 0) {
val = l * 255;
return [val, val, val];
}
if (l < 0.5) {
t2 = l * (1 + s);
} else {
t2 = l + s - l * s;
}
const t1 = 2 * l - t2;
const rgb = [0, 0, 0];
for (let i = 0; i < 3; i++) {
t3 = h + (1 / 3) * -(i - 1);
if (t3 < 0) {
t3++;
}
if (t3 > 1) {
t3--;
}
if (6 * t3 < 1) {
val = t1 + (t2 - t1) * 6 * t3;
} else if (2 * t3 < 1) {
val = t2;
} else if (3 * t3 < 2) {
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
} else {
val = t1;
}
rgb[i] = val * 255;
}
return rgb;
}
function rgbToHsl(rgb) {
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;
const min = Math.min(r, g, b);
const max = Math.max(r, g, b);
const delta = max - min;
let h;
let s;
if (max === min) {
h = 0;
} else if (r === max) {
h = (g - b) / delta;
} else if (g === max) {
h = 2 + (b - r) / delta;
} else if (b === max) {
h = 4 + (r - g) / delta;
}
h = Math.min(h * 60, 360);
if (h < 0) {
h += 360;
}
const l = (min + max) / 2;
if (max === min) {
s = 0;
} else if (l <= 0.5) {
s = delta / (max + min);
} else {
s = delta / (2 - max - min);
}
return [h, s * 100, l * 100];
}
function colorNameToHex(color) {
const colors = {
aliceblue: "#f0f8ff",
antiquewhite: "#faebd7",
aqua: "#00ffff",
aquamarine: "#7fffd4",
azure: "#f0ffff",
beige: "#f5f5dc",
bisque: "#ffe4c4",
black: "#000000",
blanchedalmond: "#ffebcd",
blue: "#0000ff",
blueviolet: "#8a2be2",
brown: "#a52a2a",
burlywood: "#deb887",
cadetblue: "#5f9ea0",
chartreuse: "#7fff00",
chocolate: "#d2691e",
coral: "#ff7f50",
cornflowerblue: "#6495ed",
cornsilk: "#fff8dc",
crimson: "#dc143c",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b",
darkslategray: "#2f4f4f",
darkturquoise: "#00ced1",
darkviolet: "#9400d3",
deeppink: "#ff1493",
deepskyblue: "#00bfff",
dimgray: "#696969",
dodgerblue: "#1e90ff",
firebrick: "#b22222",
floralwhite: "#fffaf0",
forestgreen: "#228b22",
fuchsia: "#ff00ff",
gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff",
gold: "#ffd700",
goldenrod: "#daa520",
gray: "#808080",
green: "#008000",
greenyellow: "#adff2f",
honeydew: "#f0fff0",
hotpink: "#ff69b4",
"indianred ": "#cd5c5c",
indigo: "#4b0082",
ivory: "#fffff0",
khaki: "#f0e68c",
lavender: "#e6e6fa",
lavenderblush: "#fff0f5",
lawngreen: "#7cfc00",
lemonchiffon: "#fffacd",
lightblue: "#add8e6",
lightcoral: "#f08080",
lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2",
lightgrey: "#d3d3d3",
lightgreen: "#90ee90",
lightpink: "#ffb6c1",
lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa",
lightskyblue: "#87cefa",
lightslategray: "#778899",
lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0",
lime: "#00ff00",
limegreen: "#32cd32",
linen: "#faf0e6",
magenta: "#ff00ff",
maroon: "#800000",
mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd",
mediumorchid: "#ba55d3",
mediumpurple: "#9370d8",
mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585",
midnightblue: "#191970",
mintcream: "#f5fffa",
mistyrose: "#ffe4e1",
moccasin: "#ffe4b5",
navajowhite: "#ffdead",
navy: "#000080",
oldlace: "#fdf5e6",
olive: "#808000",
olivedrab: "#6b8e23",
orange: "#ffa500",
orangered: "#ff4500",
orchid: "#da70d6",
palegoldenrod: "#eee8aa",
palegreen: "#98fb98",
paleturquoise: "#afeeee",
palevioletred: "#d87093",
papayawhip: "#ffefd5",
peachpuff: "#ffdab9",
peru: "#cd853f",
pink: "#ffc0cb",
plum: "#dda0dd",
powderblue: "#b0e0e6",
purple: "#800080",
rebeccapurple: "#663399",
red: "#ff0000",
rosybrown: "#bc8f8f",
royalblue: "#4169e1",
saddlebrown: "#8b4513",
salmon: "#fa8072",
sandybrown: "#f4a460",
seagreen: "#2e8b57",
seashell: "#fff5ee",
sienna: "#a0522d",
silver: "#c0c0c0",
skyblue: "#87ceeb",
slateblue: "#6a5acd",
slategray: "#708090",
snow: "#fffafa",
springgreen: "#00ff7f",
steelblue: "#4682b4",
tan: "#d2b48c",
teal: "#008080",
thistle: "#d8bfd8",
tomato: "#ff6347",
turquoise: "#40e0d0",
violet: "#ee82ee",
wheat: "#f5deb3",
white: "#ffffff",
whitesmoke: "#f5f5f5",
yellow: "#ffff00",
yellowgreen: "#9acd32",
};
if (typeof colors[color.toLowerCase()] != "undefined")
return colors[color.toLowerCase()];
return color;
/*
![](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
*/
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 = colorNameToHex(selectedElements[0].backgroundColor);
const rgbBgColor1 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(bgColor1);
const bgColor2 = colorNameToHex(selectedElements[1].backgroundColor);
const rgbBgColor2 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(bgColor2);
let bgHDistance = 0;
let bgSDistance = 0;
let bgLDistance = 0;
if(rgbBgColor1 && rgbBgColor2) {
const bgHsl1 = rgbToHsl([parseInt(rgbBgColor1[1], 16), parseInt(rgbBgColor1[2], 16), parseInt(rgbBgColor1[3], 16)]);
const bgHsl2 = rgbToHsl([parseInt(rgbBgColor2[1], 16), parseInt(rgbBgColor2[2], 16), parseInt(rgbBgColor2[3], 16)]);
bgHDistance = bgHsl2[0] - bgHsl1[0];
bgSDistance = bgHsl2[1] - bgHsl1[1];
bgLDistance = bgHsl2[2] - bgHsl1[2];
}
const strokeColor1 = colorNameToHex(selectedElements[0].strokeColor);
const rgbStrokeColor1 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(strokeColor1);
const strokeColor2 = colorNameToHex(selectedElements[1].strokeColor);
const rgbStrokeColor2 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(strokeColor2);
let strokeHDistance = 0;
let strokeSDistance = 0;
let strokeLDistance = 0;
if(rgbStrokeColor1 && rgbStrokeColor2) {
const strokeHsl1 = rgbToHsl([parseInt(rgbStrokeColor1[1], 16), parseInt(rgbStrokeColor1[2], 16), parseInt(rgbStrokeColor1[3], 16)]);
const strokeHsl2 = rgbToHsl([parseInt(rgbStrokeColor2[1], 16), parseInt(rgbStrokeColor2[2], 16), parseInt(rgbStrokeColor2[3], 16)]);
strokeHDistance = strokeHsl2[0] - strokeHsl1[0];
strokeSDistance = strokeHsl2[1] - strokeHsl1[1];
strokeLDistance = strokeHsl2[2] - strokeHsl1[2];
}
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(rgbBgColor1 && rgbBgColor2) {
const bgHsl2 = rgbToHsl([parseInt(rgbBgColor2[1], 16), parseInt(rgbBgColor2[2], 16), parseInt(rgbBgColor2[3], 16)]);
const newBgH = bgHsl2[0] + bgHDistance * (i + 1);
const newBgS = bgHsl2[1] + bgSDistance * (i + 1);
const newBgL = bgHsl2[2] + bgLDistance * (i + 1);
if(newBgH >= 0 && newBgH <= 360 && newBgS >= 0 && newBgS <= 100 && newBgL >= 0 && newBgL <= 100) {
const newBgRgb = hslToRgb([newBgH, newBgS, newBgL]);
newEl.backgroundColor = "#" + rgbToHexString(newBgRgb);
}
}
if(rgbStrokeColor1 && rgbStrokeColor2) {
const strokeHsl2 = rgbToHsl([parseInt(rgbStrokeColor2[1], 16), parseInt(rgbStrokeColor2[2], 16), parseInt(rgbStrokeColor2[3], 16)]);
const newStrokeH = strokeHsl2[0] + strokeHDistance * (i + 1);
const newStrokeS = strokeHsl2[1] + strokeSDistance * (i + 1);
const newStrokeL = strokeHsl2[2] + strokeLDistance * (i + 1);
if(newStrokeH >= 0 && newStrokeH <= 360 && newStrokeS >= 0 && newStrokeS <= 100 && newStrokeL >= 0 && newStrokeL <= 100) {
const newStrokeRgb = hslToRgb([newStrokeH, newStrokeS, newStrokeL]);
newEl.strokeColor = "#" + rgbToHexString(newStrokeRgb);
}
}
}
await ea.addElementsToView(false, true, true);
function rgbToHexString(args) {
const integer =
((Math.round(args[0]) & 0xff) << 16) +
((Math.round(args[1]) & 0xff) << 8) +
(Math.round(args[2]) & 0xff);
const string = integer.toString(16).toUpperCase();
return "000000".substring(string.length) + string;
}
function hslToRgb(hsl) {
const h = hsl[0] / 360;
const s = hsl[1] / 100;
const l = hsl[2] / 100;
let t2;
let t3;
let val;
if (s === 0) {
val = l * 255;
return [val, val, val];
}
if (l < 0.5) {
t2 = l * (1 + s);
} else {
t2 = l + s - l * s;
}
const t1 = 2 * l - t2;
const rgb = [0, 0, 0];
for (let i = 0; i < 3; i++) {
t3 = h + (1 / 3) * -(i - 1);
if (t3 < 0) {
t3++;
}
if (t3 > 1) {
t3--;
}
if (6 * t3 < 1) {
val = t1 + (t2 - t1) * 6 * t3;
} else if (2 * t3 < 1) {
val = t2;
} else if (3 * t3 < 2) {
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
} else {
val = t1;
}
rgb[i] = val * 255;
}
return rgb;
}
function rgbToHsl(rgb) {
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;
const min = Math.min(r, g, b);
const max = Math.max(r, g, b);
const delta = max - min;
let h;
let s;
if (max === min) {
h = 0;
} else if (r === max) {
h = (g - b) / delta;
} else if (g === max) {
h = 2 + (b - r) / delta;
} else if (b === max) {
h = 4 + (r - g) / delta;
}
h = Math.min(h * 60, 360);
if (h < 0) {
h += 360;
}
const l = (min + max) / 2;
if (max === min) {
s = 0;
} else if (l <= 0.5) {
s = delta / (max + min);
} else {
s = delta / (2 - max - min);
}
return [h, s * 100, l * 100];
}
function colorNameToHex(color) {
const colors = {
aliceblue: "#f0f8ff",
antiquewhite: "#faebd7",
aqua: "#00ffff",
aquamarine: "#7fffd4",
azure: "#f0ffff",
beige: "#f5f5dc",
bisque: "#ffe4c4",
black: "#000000",
blanchedalmond: "#ffebcd",
blue: "#0000ff",
blueviolet: "#8a2be2",
brown: "#a52a2a",
burlywood: "#deb887",
cadetblue: "#5f9ea0",
chartreuse: "#7fff00",
chocolate: "#d2691e",
coral: "#ff7f50",
cornflowerblue: "#6495ed",
cornsilk: "#fff8dc",
crimson: "#dc143c",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b",
darkslategray: "#2f4f4f",
darkturquoise: "#00ced1",
darkviolet: "#9400d3",
deeppink: "#ff1493",
deepskyblue: "#00bfff",
dimgray: "#696969",
dodgerblue: "#1e90ff",
firebrick: "#b22222",
floralwhite: "#fffaf0",
forestgreen: "#228b22",
fuchsia: "#ff00ff",
gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff",
gold: "#ffd700",
goldenrod: "#daa520",
gray: "#808080",
green: "#008000",
greenyellow: "#adff2f",
honeydew: "#f0fff0",
hotpink: "#ff69b4",
"indianred ": "#cd5c5c",
indigo: "#4b0082",
ivory: "#fffff0",
khaki: "#f0e68c",
lavender: "#e6e6fa",
lavenderblush: "#fff0f5",
lawngreen: "#7cfc00",
lemonchiffon: "#fffacd",
lightblue: "#add8e6",
lightcoral: "#f08080",
lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2",
lightgrey: "#d3d3d3",
lightgreen: "#90ee90",
lightpink: "#ffb6c1",
lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa",
lightskyblue: "#87cefa",
lightslategray: "#778899",
lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0",
lime: "#00ff00",
limegreen: "#32cd32",
linen: "#faf0e6",
magenta: "#ff00ff",
maroon: "#800000",
mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd",
mediumorchid: "#ba55d3",
mediumpurple: "#9370d8",
mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585",
midnightblue: "#191970",
mintcream: "#f5fffa",
mistyrose: "#ffe4e1",
moccasin: "#ffe4b5",
navajowhite: "#ffdead",
navy: "#000080",
oldlace: "#fdf5e6",
olive: "#808000",
olivedrab: "#6b8e23",
orange: "#ffa500",
orangered: "#ff4500",
orchid: "#da70d6",
palegoldenrod: "#eee8aa",
palegreen: "#98fb98",
paleturquoise: "#afeeee",
palevioletred: "#d87093",
papayawhip: "#ffefd5",
peachpuff: "#ffdab9",
peru: "#cd853f",
pink: "#ffc0cb",
plum: "#dda0dd",
powderblue: "#b0e0e6",
purple: "#800080",
rebeccapurple: "#663399",
red: "#ff0000",
rosybrown: "#bc8f8f",
royalblue: "#4169e1",
saddlebrown: "#8b4513",
salmon: "#fa8072",
sandybrown: "#f4a460",
seagreen: "#2e8b57",
seashell: "#fff5ee",
sienna: "#a0522d",
silver: "#c0c0c0",
skyblue: "#87ceeb",
slateblue: "#6a5acd",
slategray: "#708090",
snow: "#fffafa",
springgreen: "#00ff7f",
steelblue: "#4682b4",
tan: "#d2b48c",
teal: "#008080",
thistle: "#d8bfd8",
tomato: "#ff6347",
turquoise: "#40e0d0",
violet: "#ee82ee",
wheat: "#f5deb3",
white: "#ffffff",
whitesmoke: "#f5f5f5",
yellow: "#ffff00",
yellowgreen: "#9acd32",
};
if (typeof colors[color.toLowerCase()] != "undefined")
return colors[color.toLowerCase()];
return color;
}

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "1.6.11",
"version": "1.6.12",
"minAppVersion": "0.12.16",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",

View File

@@ -12,7 +12,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"@zsviczian/excalidraw": "0.10.0-obsidian-49",
"@zsviczian/excalidraw": "0.11.0-obsidian-1",
"monkey-around": "^2.3.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",

View File

@@ -1168,14 +1168,9 @@ export async function initExcalidrawAutomate(
commitToHistory: false,
});
}
if (
document.fullscreenElement ===
(this.targetView as ExcalidrawView).contentEl
) {
document.exitFullscreen();
} else {
(this.targetView as ExcalidrawView).contentEl.requestFullscreen();
}
const view = this.targetView as ExcalidrawView;
if(view.isFullscreen()) view.exitFullscreen();
else view.gotoFullscreen();
},
connectObjectWithViewSelectedElement(
objectA: string,
@@ -1445,6 +1440,9 @@ export function measureText(
fontSize: number,
fontFamily: number,
) {
//following odd error with mindmap on iPad while synchornizing with desktop.
if(!fontSize) fontSize = 20;
if(!fontFamily) fontFamily = 1;
const line = document.createElement("div");
const body = document.body;
line.style.position = "absolute";

View File

@@ -21,7 +21,7 @@ import { JSON_parse } from "./constants";
import { TextMode } from "./ExcalidrawView";
import {
getAttachmentsFolderAndFilePath,
getBakPath,
//getBakPath,
getBinaryFileFromDataURL,
getLinkParts,
isObsidianThemeDark,
@@ -265,17 +265,17 @@ export class ExcalidrawData {
}
return sceneJSONandPOS;
};
try {
//try {
sceneJSONandPOS = loadJSON();
} catch (e) {
/*} catch (e) {
if(await this.app.vault.adapter.exists(getBakPath(file))) {
data = await this.app.vault.adapter.read(getBakPath(file))
sceneJSONandPOS = loadJSON();
new Notice(t("LOAD_FROM_BACKUP"), 4000);
} else {
throw e;
}
}
}*/
if (!this.scene.files) {
this.scene.files = {}; //loading legacy scenes that do not yet have the files attribute.
@@ -909,7 +909,7 @@ export class ExcalidrawData {
let result = false;
if (!this.compatibilityMode) {
result = await this.syncFiles();
this.scene.files = {};
this.scene.files = {}; //files contains the dataURLs of files. Once synced these are all saved to disk
}
this.updateElementLinksFromScene();
result =

View File

@@ -53,7 +53,7 @@ import {
download,
embedFontsInSVG,
errorlog,
getBakPath,
//getBakPath,
getIMGFilename,
getNewOrAdjacentLeaf,
getNewUniqueFilepath,
@@ -278,6 +278,7 @@ export default class ExcalidrawView extends TextFileView {
}
this.preventReload = preventReload;
const allowSave = (this.dirty !== null && this.dirty) || this.autosaving; //dirty == false when view.file == null;
this.dirty = null;
const scene = this.getScene();
@@ -287,12 +288,11 @@ export default class ExcalidrawView extends TextFileView {
(await this.excalidrawData.syncElements(scene)) &&
!this.autosaving
) {
//debug({where:"ExcalidrawView.save",file:this.file.name,dataTheme:this.excalidrawData.scene.appState.theme,before:"loadDrawing(false)"})
await this.loadDrawing(false);
}
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/396
const bakfilepath = getBakPath(this.file);
/*const bakfilepath = getBakPath(this.file);
try {
if (await this.app.vault.adapter.exists(bakfilepath)) {
await this.app.vault.adapter.remove(bakfilepath);
@@ -300,15 +300,17 @@ export default class ExcalidrawView extends TextFileView {
await this.app.vault.adapter.copy(this.file.path, bakfilepath);
} catch(e) {
console.error({where: "ExcalidrawView.save copy backup file", error: e});
}*/
if(allowSave) {
await super.save();
this.diskIcon.querySelector("svg").removeClass("excalidraw-dirty");
}
await super.save();
try {
/*try {
await this.app.vault.adapter.remove(bakfilepath);
} catch(e) {
console.error({where: "ExcalidrawView.save removing backup file", error: e});
}
}*/
if (!this.autosaving) {
if (this.plugin.settings.autoexportSVG) {
@@ -601,12 +603,13 @@ export default class ExcalidrawView extends TextFileView {
this.zoomToFit(false);
}
diskIcon: HTMLElement;
onload() {
this.addAction(SCRIPTENGINE_ICON_NAME, t("INSTALL_SCRIPT_BUTTON"), () => {
new ScriptInstallPrompt(this.plugin).open();
});
this.addAction(DISK_ICON_NAME, t("FORCE_SAVE"), async () => {
this.diskIcon = this.addAction(DISK_ICON_NAME, t("FORCE_SAVE"), async () => {
await this.save(false);
this.plugin.triggerEmbedUpdates();
this.loadSceneFiles();
@@ -733,6 +736,7 @@ export default class ExcalidrawView extends TextFileView {
this.preventReload = false;
return;
}
this.diskIcon.querySelector("svg").removeClass("excalidraw-dirty");
if (this.compatibilityMode) {
this.dirty = null;
return;
@@ -780,6 +784,7 @@ export default class ExcalidrawView extends TextFileView {
data = this.data = data.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
this.app.workspace.onLayoutReady(async () => {
this.dirty = null;
this.diskIcon.querySelector("svg").removeClass("excalidraw-dirty");
this.compatibilityMode = this.file.extension === "excalidraw";
await this.plugin.loadSettings();
if (this.compatibilityMode) {
@@ -865,16 +870,6 @@ export default class ExcalidrawView extends TextFileView {
*/
private async loadDrawing(justloaded: boolean) {
const excalidrawData = this.excalidrawData.scene;
const appState = excalidrawData.appState as AppState;
if (appState.colorPalette?.canvasBackground && appState.colorPalette.canvasBackground.length !== 15) {
new Notice ("appState.colorPalette.canvasBackground must have exactly 15 colors");
}
if (appState.colorPalette?.elementBackground && appState.colorPalette.elementBackground.length !== 15) {
new Notice ("appState.colorPalette.elementBackground must have exactly 15 colors");
}
if (appState.colorPalette?.elementStroke && appState.colorPalette.elementStroke.length !== 15) {
new Notice ("appState.colorPalette.elementStroke must have exactly 15 colors");
}
this.justLoaded = justloaded;
const om = this.excalidrawData.getOpenMode();
this.preventReload = false;
@@ -1102,11 +1097,12 @@ export default class ExcalidrawView extends TextFileView {
return data?.library ? data.library : data?.libraryItems ?? [];
}
previousSceneVersion = 0;
private instantiateExcalidraw(initdata: any) {
//console.log("ExcalidrawView.instantiateExcalidraw()");
this.dirty = null;
this.diskIcon.querySelector("svg").removeClass("excalidraw-dirty");
const reactElement = React.createElement(() => {
let previousSceneVersion = 0;
let currentPosition = { x: 0, y: 0 };
const excalidrawWrapperRef = React.useRef(null);
const [dimensions, setDimensions] = React.useState({
@@ -1293,20 +1289,18 @@ export default class ExcalidrawView extends TextFileView {
return { id: imageElement[0].id, fileId: imageElement[0].fileId }; //return image element fileId
};
this.addText = (text: string, fontFamily?: 1 | 2 | 3) => {
this.addText = (text: string, fontFamily?: 1 | 2 | 3 | 4) => {
if (!excalidrawRef?.current) {
return;
}
const st: AppState = this.excalidrawAPI.getAppState();
const ea = this.plugin.ea;
ea.reset();
ea.style.strokeColor = st.currentItemStrokeColor;
ea.style.opacity = st.currentItemOpacity;
ea.style.fontFamily = fontFamily
? fontFamily
: st.currentItemFontFamily;
ea.style.fontSize = st.currentItemFontSize;
ea.style.textAlign = st.currentItemTextAlign;
ea.style.strokeColor = st.currentItemStrokeColor??"black";
ea.style.opacity = st.currentItemOpacity??1;
ea.style.fontFamily = fontFamily??st.currentItemFontFamily??1;
ea.style.fontSize = st.currentItemFontSize??20;
ea.style.textAlign = st.currentItemTextAlign??"left";
ea.addText(currentPosition.x, currentPosition.y, text);
this.addElements(ea.getElements(), false, true);
};
@@ -1410,6 +1404,7 @@ export default class ExcalidrawView extends TextFileView {
await this.save(false); //preventReload=false will ensure that markdown links are paresed and displayed correctly
} else {
this.dirty = this.file?.path;
this.diskIcon.querySelector("svg").addClass("excalidraw-dirty");
}
return true;
};
@@ -1808,20 +1803,21 @@ export default class ExcalidrawView extends TextFileView {
if (this.justLoaded) {
this.justLoaded = false;
this.zoomToFit(false);
previousSceneVersion = getSceneVersion(et);
this.previousSceneVersion = getSceneVersion(et);
return;
}
if (
st.editingElement == null &&
st.resizingElement == null &&
st.draggingElement == null &&
st.editingGroupId == null &&
st.editingLinearElement == null
st.editingElement === null &&
st.resizingElement === null &&
st.draggingElement === null &&
st.editingGroupId === null &&
st.editingLinearElement === null
) {
const sceneVersion = getSceneVersion(et);
if (sceneVersion != previousSceneVersion) {
previousSceneVersion = sceneVersion;
if (sceneVersion !== this.previousSceneVersion) {
this.previousSceneVersion = sceneVersion;
this.dirty = this.file?.path;
this.diskIcon.querySelector("svg").addClass("excalidraw-dirty");
}
}
},
@@ -1912,7 +1908,7 @@ export default class ExcalidrawView extends TextFileView {
currentPosition.y,
draggable.file,
);
ea.addElementsToView(false, false);
ea.addElementsToView(false, false, true);
})();
return false;
}
@@ -2027,6 +2023,7 @@ export default class ExcalidrawView extends TextFileView {
if (isDeleted) {
this.excalidrawData.deleteTextElement(textElement.id);
this.dirty = this.file?.path;
this.diskIcon.querySelector("svg").addClass("excalidraw-dirty");
this.setupAutosaveTimer();
return [null, null, null];
}

View File

@@ -45,7 +45,7 @@ export class InsertImageDialog extends FuzzySuggestModal<TFile> {
ea.canvas.theme = this.view.excalidrawAPI.getAppState().theme;
(async () => {
await ea.addImage(0, 0, item);
ea.addElementsToView(true, false);
ea.addElementsToView(true, false, true);
})();
}

View File

@@ -39,7 +39,7 @@ export class InsertMDDialog extends FuzzySuggestModal<TFile> {
ea.setView(this.view);
(async () => {
await ea.addImage(0, 0, item);
ea.addElementsToView(true, false);
ea.addElementsToView(true, false, true);
})();
}

View File

@@ -125,10 +125,10 @@ export function getIMGPathFromExcalidrawFile(
);
}
export function getBakPath(file:TFile):string {
/*export function getBakPath(file:TFile):string {
const re = new RegExp(`${file.name}$`,"g");
return file.path.replace(re,`.${file.name}.bak`);
}
}*/
/**
* Create new file, if file already exists find first unique filename by adding a number to the end of the filename

View File

@@ -98,7 +98,7 @@ export default {
"The folder may not be the root folder of your Vault. ",
AUTOSAVE_NAME: "Enable Autosave",
AUTOSAVE_DESC:
"Automatically save the active drawing every 30 seconds, or 1, 2, 3, 4, or 5 minutes. Save normally happens when you close Excalidraw or Obsidian, or move " +
"Automatically save the active drawing, in case there are changes, every 15, 30 seconds, or 1, 2, 3, 4, or 5 minute. Save normally happens when you close Excalidraw or Obsidian, or move " +
"focus to another pane. I created this feature with mobile " +
"phones and tablets in mind, where 'swiping out Obsidian to close it' led to some data loss.",
AUTOSAVE_INTERVAL_NAME: "Interval for autosave",

View File

@@ -942,7 +942,7 @@ export default class ExcalidrawPlugin extends Plugin {
ea.reset();
await ea.addLaTex(0, 0, formula);
ea.setView(view);
ea.addElementsToView(true, false);
ea.addElementsToView(true, false, true);
});
return true;
}
@@ -1295,13 +1295,14 @@ export default class ExcalidrawPlugin extends Plugin {
self.registerEvent(self.app.vault.on("delete", deleteEventHandler));
//save open drawings when user quits the application
const quitEventHandler = async () => {
//Removing because it is not guaranteed to run, and frequently gets terminated mid flight, causing file consistency issues
/*const quitEventHandler = async () => {
const leaves = self.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
for (let i = 0; i < leaves.length; i++) {
await (leaves[i].view as ExcalidrawView).save(true);
}
};
self.registerEvent(self.app.workspace.on("quit", quitEventHandler));
self.registerEvent(self.app.workspace.on("quit", quitEventHandler));*/
//save Excalidraw leaf and update embeds when switching to another leaf
const activeLeafChangeEventHandler = async (leaf: WorkspaceLeaf) => {

View File

@@ -80,7 +80,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
templateFilePath: "Excalidraw/Template.excalidraw",
scriptFolderPath: "Excalidraw/Scripts",
autosave: true,
autosaveInterval: 30000,
autosaveInterval: 15000,
drawingFilenamePrefix: "Drawing ",
drawingEmbedPrefixWithFilename: true,
drawingFilenameDateTime: "YYYY-MM-DD HH.mm.ss",
@@ -345,6 +345,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
.setDesc(fragWithHTML(t("AUTOSAVE_INTERVAL_DESC")))
.addDropdown(async (d: DropdownComponent) => {
autosaveDropdown = d;
d.addOption("15000", "15 seconds");
d.addOption("30000", "30 seconds");
d.addOption("60000", "1 minute");
d.addOption("120000", "2 minutes");

View File

@@ -144,4 +144,8 @@ li[data-testid] {
text-align: center;
font-weight: bold;
margin-bottom: 2em;
}
.excalidraw-dirty {
color: red;
}

View File

@@ -1,4 +1,4 @@
{
"1.6.11": "0.12.16",
"1.6.12": "0.12.16",
"1.4.2": "0.11.13"
}

View File

@@ -2127,10 +2127,10 @@
"resolved" "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz"
"version" "4.2.2"
"@zsviczian/excalidraw@0.10.0-obsidian-49":
"integrity" "sha512-32XoMHNyvzWOkkwBMzlS7L6ijabWxCmmA24Pvpn0PUkVQf9dy8OhDDtMHd7NmxD8zglnAXihlAMhTX/l+CLo3A=="
"resolved" "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.10.0-obsidian-49.tgz"
"version" "0.10.0-obsidian-49"
"@zsviczian/excalidraw@0.11.0-obsidian-1":
"integrity" "sha512-jW2vCnNvk8/0QDBEhnVZ2yImHXkbUISCTdb+KG3yWhU5rwn8nH6tQPJGxHfnr5dN5D5TPrguh9ScqdezoKOzUw=="
"resolved" "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.11.0-obsidian-1.tgz"
"version" "0.11.0-obsidian-1"
dependencies:
"dotenv" "10.0.0"