Compare commits

..

15 Commits

Author SHA1 Message Date
zsviczian
272804afc8 allow jfif and avif 2025-01-14 14:59:47 +00:00
zsviczian
dc0b50f717 Update How-to.yml
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-01-09 08:52:41 +01:00
zsviczian
a0eb625b8a Update How-to.yml 2025-01-09 08:52:11 +01:00
zsviczian
524dc54d03 Update bug_report.yml 2025-01-09 08:50:35 +01:00
zsviczian
918718be90 Update bug_report.yml 2025-01-09 08:49:59 +01:00
zsviczian
78ee784be1 Update bug_report.yml 2025-01-09 08:48:58 +01:00
zsviczian
7e0e016bf9 Update bug_report.yml 2025-01-09 08:48:18 +01:00
zsviczian
4f875a03a0 2.7.5
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-01-05 23:09:16 +01:00
zsviczian
63c56e0e98 similar elements allows selection of containers
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-01-05 12:49:11 +01:00
zsviczian
46477208be split ellipse and concatenate line now works with rotated lines
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-01-05 11:38:45 +01:00
zsviczian
3194c014c7 updated concatenate lines 2025-01-05 10:33:31 +01:00
zsviczian
25ccb9dc43 updated EA lib in docs 2025-01-05 07:03:04 +01:00
zsviczian
fa46f8c39d Merge pull request #1880 from karaolidis/package-lock
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Allow automated & deterministic builds
2025-01-04 22:18:09 +01:00
zsviczian
8ffe5c3942 2.7.5-beta-1 2025-01-04 21:26:49 +01:00
Nikolaos Karaolidis
d759abbc47 Allow commiting package-lock.json
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
2025-01-04 18:38:56 +02:00
22 changed files with 12096 additions and 801 deletions

View File

@@ -12,6 +12,8 @@ body:
Before submitting a support request, please:
1. **Review the [documentation](https://github.com/zsviczian/obsidian-excalidraw-plugin/wiki)** your question may already be answered.
2. **[Search issues](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues) (including closed ones)** to see if your question has already been addressed.
3. **[Watch the Feature Walkthrough Video](https://youtu.be/P_Q6avJGoWI)**: As it infact answers 90% of the typical questions I receive
4. **[Consult NotebookLM with your question](https://excalidraw-obsidian.online/WIKI/09+Video+Transcripts/Videos/Turn+any+YouTube+Channel+into+your+AI+Mentor+-+Obsidian+is+the+ultimate+automation+workbench+for+PKM)**
- type: markdown
attributes:
@@ -31,6 +33,13 @@ body:
options:
- label: Yes, I have reviewed the documentation and searched for related issues.
- type: textarea
id: notebook_lm
attributes:
label: "Your NotebookLM query"
description: "See point 4) above. Paste the question and answer you received from NotebookLM. This serves partly as proof, partly to help me see where the model is incorrect"
placeholder: "Copy/Paste your question and the resulting answer you got from NotebookLM"
- type: textarea
id: support_question
attributes:

View File

@@ -1,5 +1,5 @@
name: Bug report
description: If something is clearly broken, its a bug. Everything else is a feature or support request. Most reported “bugs” are actually how-to questions or feature requests.
description: If something is clearly broken, its a bug. **Everything else** is a feature or support request. Most reported “bugs” are actually how-to questions or feature requests.
title: "BUG: "
body:
- type: markdown
@@ -12,6 +12,8 @@ body:
Before creating a bug report, please:
1. **Review recent [release notes](https://github.com/zsviczian/obsidian-excalidraw-plugin/releases)** maybe there is already an answer.
2. **[Search issues](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues) (including closed ones)** to see if there is anything similar.
3. **[Watch the Feature Walkthrough Video](https://youtu.be/P_Q6avJGoWI)**: As it infact answers 90% of the typical questions I receive
4. **[Consult NotebookLM with your question](https://excalidraw-obsidian.online/WIKI/09+Video+Transcripts/Videos/Turn+any+YouTube+Channel+into+your+AI+Mentor+-+Obsidian+is+the+ultimate+automation+workbench+for+PKM)**
- type: markdown
attributes:
@@ -46,6 +48,13 @@ body:
description: "Run `Command Palette/Show Debug info` in Obsidian and paste the result here."
placeholder: "Paste your Obsidian debug info here..."
- type: textarea
id: notebook_lm
attributes:
label: "Your NotebookLM query"
description: "See point 4) above. Paste the question and answer you received from NotebookLM. This serves partly as proof, partly to help me see where the model is incorrect"
placeholder: "Copy/Paste your question and the resulting answer you got from NotebookLM"
- type: textarea
id: bug_description
attributes:

1
.gitignore vendored
View File

@@ -4,7 +4,6 @@
# npm
node_modules
package-lock.json
# build
main.js

2
.nvmrc
View File

@@ -1 +1 @@
18
18

1342
MathjaxToSVG/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,8 @@
"cross-env": "^7.0.3",
"obsidian": "1.5.7-1",
"rollup": "^2.70.1",
"typescript": "^5.2.2",
"rollup-plugin-terser": "^7.0.2"
"rollup-plugin-terser": "^7.0.2",
"tslib": "^2.8.1",
"typescript": "^5.2.2"
}
}
}

View File

@@ -16,10 +16,10 @@ export default {
},
plugins: [
typescript({
tsconfig: '../tsconfig.json',
tsconfig: 'tsconfig.json',
}),
commonjs(),
nodeResolve({
nodeResolve({
browser: true,
preferBuiltins: false
}),
@@ -32,4 +32,4 @@ export default {
}
})
].filter(Boolean)
};
};

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"baseUrl": ".",
"sourceMap": false,
"module": "es2020",
"target": "es2022", //min es2017 because script engine requires for async execution and min es2018 for named capture groups
"allowJs": false,
"noImplicitAny": true,
"moduleResolution": "node",
"esModuleInterop": true,
"importHelpers": true,
"resolveJsonModule": true,
"lib": [
"dom",
"scripthost",
"es2022",
"DOM.Iterable"
],
"jsx": "react",
},
"include": [
"**/*.ts",
"**/*.tsx", "src/shared/Dialogs/OpenDrawing.ts",
"src/types/types.d.ts",
]
}

View File

@@ -1,4 +0,0 @@
The project runs with `node 18`.
After running `npm -i` you'll need to make two manual changes:

File diff suppressed because it is too large Load Diff

View File

@@ -8,20 +8,76 @@ if(lines.length !== 2) {
return;
}
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
const rotate = (point, element) => {
const [x1, y1] = point;
const x2 = element.x + element.width/2;
const y2 = element.y - element.height/2;
const angle = element.angle;
return [
(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2,
(x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2,
];
//Same line but with angle=0
function getNormalizedLine(originalElement) {
if(originalElement.angle === 0) return originalElement;
// Get absolute coordinates for all points first
const pointRotateRads = (point, center, angle) => {
const [x, y] = point;
const [cx, cy] = center;
return [
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy
];
};
// Get element absolute coordinates (matching Excalidraw's approach)
const getElementAbsoluteCoords = (element) => {
const points = element.points;
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
for (const [x, y] of points) {
const absX = x + element.x;
const absY = y + element.y;
minX = Math.min(minX, absX);
minY = Math.min(minY, absY);
maxX = Math.max(maxX, absX);
maxY = Math.max(maxY, absY);
}
return [minX, minY, maxX, maxY];
};
// Calculate center point based on absolute coordinates
const [x1, y1, x2, y2] = getElementAbsoluteCoords(originalElement);
const centerX = (x1 + x2) / 2;
const centerY = (y1 + y2) / 2;
// Calculate absolute coordinates of all points
const absolutePoints = originalElement.points.map(([x, y]) => [
x + originalElement.x,
y + originalElement.y
]);
// Rotate all points around the center
const rotatedPoints = absolutePoints.map(point =>
pointRotateRads(point, [centerX, centerY], originalElement.angle)
);
// Convert back to relative coordinates
const newPoints = rotatedPoints.map(([x, y]) => [
x - rotatedPoints[0][0],
y - rotatedPoints[0][1]
]);
const newLineId = ea.addLine(newPoints);
// Set the position of the new line to the first rotated point
const newLine = ea.getElement(newLineId);
newLine.x = rotatedPoints[0][0];
newLine.y = rotatedPoints[0][1];
newLine.angle = 0;
delete ea.elementsDict[newLine.id];
return newLine;
}
const points = lines.map(
el=>el.points.map(p=>rotate([p[0]+el.x, p[1]+el.y],el))
const points = lines.map(getNormalizedLine).map(
el=>el.points.map(p=>[p[0]+el.x, p[1]+el.y])
);
const last = (p) => p[p.length-1];
@@ -99,4 +155,4 @@ switch (lineTypes) {
}
ea.addElementsToView();
await ea.addElementsToView();

View File

@@ -7,16 +7,41 @@ This script enables the selection of elements based on matching properties. Sele
```js */
let config = window.ExcalidrawSelectConfig;
config = Boolean(config) && (Date.now() - config.timestamp < 60000) ? config : null;
const isValidConfig = config && (Date.now() - config.timestamp < 60000);
config = isValidConfig ? config : null;
let elements = ea.getViewSelectedElements();
if(!config && (elements.length !==1)) {
new Notice("Select a single element");
return;
} else {
if(elements.length === 0) {
elements = ea.getViewElements();
if(!config) {
async function shouldAbort() {
if(elements.length === 1) return false;
if(elements.length !== 2) return true;
//maybe container?
const textEl = elements.find(el=>el.type==="text");
if(!textEl || !textEl.containerId) return true;
const containerEl = elements.find(el=>el.id === textEl.containerId);
if(!containerEl) return true;
const id = await utils.suggester(
elements.map(el=>el.type),
elements.map(el=>el.id),
"Select container component"
);
if(!id) return true;
elements = elements.filter(el=>el.id === id);
return false;
}
if(await shouldAbort()) {
new Notice("Select a single element");
return;
}
}
if(Boolean(config) && elements.length === 0) {
elements = ea.getViewElements();
}
const {angle, backgroundColor, fillStyle, fontFamily, fontSize, height, width, opacity, roughness, roundness, strokeColor, strokeStyle, strokeWidth, type, startArrowhead, endArrowhead, fileId} = ea.getViewSelectedElement();

View File

@@ -18,6 +18,7 @@ if (!ellipse) return;
let lines = elements.filter(el => el.type == "line" || el.type == "arrow");
if (lines.length == 0) lines = ea.getViewElements().filter(el => el.type == "line" || el.type == "arrow");
lines = lines.map(getNormalizedLine);
const subLines = getSubLines(lines);
const angles = subLines.flatMap(line => {
@@ -206,3 +207,70 @@ function isBetween(num, min, max) {
function clamp(number, min, max) {
return Math.max(min, Math.min(number, max));
}
//Same line but with angle=0
function getNormalizedLine(originalElement) {
if(originalElement.angle === 0) return originalElement;
// Get absolute coordinates for all points first
const pointRotateRads = (point, center, angle) => {
const [x, y] = point;
const [cx, cy] = center;
return [
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy
];
};
// Get element absolute coordinates (matching Excalidraw's approach)
const getElementAbsoluteCoords = (element) => {
const points = element.points;
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
for (const [x, y] of points) {
const absX = x + element.x;
const absY = y + element.y;
minX = Math.min(minX, absX);
minY = Math.min(minY, absY);
maxX = Math.max(maxX, absX);
maxY = Math.max(maxY, absY);
}
return [minX, minY, maxX, maxY];
};
// Calculate center point based on absolute coordinates
const [x1, y1, x2, y2] = getElementAbsoluteCoords(originalElement);
const centerX = (x1 + x2) / 2;
const centerY = (y1 + y2) / 2;
// Calculate absolute coordinates of all points
const absolutePoints = originalElement.points.map(([x, y]) => [
x + originalElement.x,
y + originalElement.y
]);
// Rotate all points around the center
const rotatedPoints = absolutePoints.map(point =>
pointRotateRads(point, [centerX, centerY], originalElement.angle)
);
// Convert back to relative coordinates
const newPoints = rotatedPoints.map(([x, y]) => [
x - rotatedPoints[0][0],
y - rotatedPoints[0][1]
]);
const newLineId = ea.addLine(newPoints);
// Set the position of the new line to the first rotated point
const newLine = ea.getElement(newLineId);
newLine.x = rotatedPoints[0][0];
newLine.y = rotatedPoints[0][1];
newLine.angle = 0;
delete ea.elementsDict[newLine.id];
return newLine;
}

File diff suppressed because one or more lines are too long

View File

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

View File

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

9290
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/excalidraw": "0.17.6-24",
"@zsviczian/excalidraw": "0.17.6-25",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"@zsviczian/colormaster": "^1.2.2",
@@ -58,7 +58,7 @@
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-typescript": "^11.1.6",
"@rollup/plugin-typescript": "^12.1.2",
"@types/chroma-js": "^2.4.0",
"@types/js-beautify": "^1.14.0",
"@types/js-yaml": "^4.0.9",
@@ -79,10 +79,10 @@
"rollup-plugin-copy": "^3.5.0",
"@zsviczian/rollup-plugin-postprocess": "^1.0.3",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.34.1",
"rollup-plugin-typescript2": "^0.36.0",
"tslib": "^2.6.1",
"ttypescript": "^1.5.15",
"typescript": "^5.2.2",
"typescript": "^5.7.3",
"fs-extra": "^11.2.0",
"uglify-js": "^3.19.3"
},

View File

@@ -198,7 +198,7 @@ export const REG_BLOCK_REF_CLEAN = /[!"#$%&()*+,.:;<=>?@^`{|}~\/\[\]\\\r\n]/g;
// /[!"#$%&()*+,.:;<=>?@^`{|}~\/\[\]\\]/g;
// https://discord.com/channels/686053708261228577/989603365606531104/1000128926619816048
// /\+|\/|~|=|%|\(|\)|{|}|,|&|\.|\$|!|\?|;|\[|]|\^|#|\*|<|>|&|@|\||\\|"|:|\s/g;
export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg", "webp", "bmp", "ico", "jtif", "tif"];
export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg", "webp", "bmp", "ico", "jtif", "tif", "jfif", "avif"];
export const ANIMATED_IMAGE_TYPES = ["gif", "webp", "apng", "svg"];
export const EXPORT_TYPES = ["svg", "dark.svg", "light.svg", "png", "dark.png", "light.png"];
export const MAX_IMAGE_SIZE = 500;

View File

@@ -17,6 +17,32 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://storage.ko-fi.com/cdn/kofi6.png?v=6" border="0" alt="Buy Me a Coffee at ko-fi.com" height=45></a></div>
`,
"2.7.5":`
## Fixed
- PDF export scenario described in [#2184](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2184)
- Elbow arrows do not work within frames [#2187](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2187)
- Embedding images into Excalidraw with areaRef links did not work as expected due to conflicting SVG viewbox and width and height values
- Can't exit full-screen mode in popout windows using the Command Palette toggle action [#2188](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2188)
- If the image mask extended beyond the image in "Mask and Crop" image mode, the mask got misaligned from the image.
- PDF image embedding fixes that impacted some PDF files (not all):
- When cropping the PDF page in the scene (by double-clicking the image to crop), the size and position of the PDF cutout drifted.
- Using PDF++ there was a small offset in the position of the cutout in PDF++ and the image in Excalidraw.
- Updated a number of scripts including Split Ellipse, Select Similar Elements, and Concatenate Lines
## New in ExcalidrawAutomate
${String.fromCharCode(96,96,96)}
/**
* Add, modify, or delete keys in element.customData and preserve existing keys.
* Creates customData={} if it does not exist.
* Takes the element id for an element in ea.elementsDict and the newData to add or modify.
* To delete keys set key value in newData to undefined. So {keyToBeDeleted:undefined} will be deleted.
* @param id
* @param newData
* @returns undefined if element does not exist in elementsDict, returns the modified element otherwise.
*/
public addAppendUpdateCustomData(id:string, newData: Partial<Record<string, unknown>>);
${String.fromCharCode(96,96,96)}
`,
"2.7.4":`
## Fixed
- Regression from 2.7.3 where image fileId got overwritten in some cases

File diff suppressed because it is too large Load Diff

View File

@@ -226,20 +226,25 @@ export const addFiles = async (
.forEach((f:FileData) => {
s.scene.elements
.filter((el:ExcalidrawElement)=>el.type === "image" && el.fileId === f.id && (
(el.crop && el.crop.naturalWidth !== f.size.width) || !el.customData?.pdfPageViewProps
(el.crop && el.crop?.naturalWidth !== f.size.width) || !el.customData?.pdfPageViewProps
))
.forEach((el:Mutable<ExcalidrawImageElement>) => {
s.dirty = true;
const scale = f.size.width / el.crop.naturalWidth;
el.crop = {
x: el.crop.x * scale,
y: el.crop.y * scale,
width: el.crop.width * scale,
height: el.crop.height * scale,
naturalWidth: f.size.width,
naturalHeight: f.size.height,
};
addAppendUpdateCustomData(el, { pdfPageViewProps: f.pdfPageViewProps});
if(el.crop) {
s.dirty = true;
const scale = f.size.width / el.crop.naturalWidth;
el.crop = {
x: el.crop.x * scale,
y: el.crop.y * scale,
width: el.crop.width * scale,
height: el.crop.height * scale,
naturalWidth: f.size.width,
naturalHeight: f.size.height,
};
}
if(!el.customData?.pdfPageViewProps) {
s.dirty = true;
addAppendUpdateCustomData(el, { pdfPageViewProps: f.pdfPageViewProps});
}
});
});