Compare commits

...

20 Commits

Author SHA1 Message Date
zsviczian
6dbae61212 2.8.1
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-01-31 22:08:16 +01:00
zsviczian
75c65d61c5 Merge pull request #2229 from md42/master
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
fix grammar
2025-01-26 06:21:57 +01:00
Martin Dürrmeier
37e0de41af fix grammar
affect as a verb and effect as a noun
2025-01-26 00:31:54 +01:00
zsviczian
57f9e43508 fixed layerUIWrapper not available
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-01-25 16:16:47 +01:00
zsviczian
3b7f931f28 Fix noticeEl in slideshow 2025-01-25 16:13:46 +01:00
zsviczian
b37a7aad4f update manifest-beta.json 2025-01-25 15:11:01 +01:00
zsviczian
667ab31ed9 publish slideshow
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-01-25 13:06:27 +01:00
zsviczian
b15ddef7fe 2.8.0 2025-01-25 13:04:21 +01:00
zsviczian
ef785e5fb0 Merge pull request #2228 from Sintuz/master
Fixing a couple issues with LaTeX
2025-01-25 12:21:42 +01:00
zsviczian
15ba4146ac styling 2025-01-25 10:58:03 +01:00
Enrico Sintoni
9956fd1756 FIX: trim additional newline characters after LaTeX formula before saving it to the MD file 2025-01-25 01:23:06 +01:00
Enrico Sintoni
b6f2161f1c FIX: lines not being displayed in the array environment in LaTeX 2025-01-25 01:21:42 +01:00
zsviczian
22b8b1f707 Merge pull request #2226 from Sintuz/master
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Allow custom location for LaTeX preamble file and small fix
2025-01-24 23:47:58 +01:00
zsviczian
98f6871caa 2.8.0-rc-2 2025-01-24 22:38:18 +01:00
Enrico Sintoni
aae588249a FIX: LaTeX rendering not working if % is put at the end of the preamble 2025-01-24 18:54:08 +01:00
Enrico Sintoni
ef890d51e3 Allow specifying a custom LaTeX preamble file location 2025-01-24 18:48:53 +01:00
zsviczian
b0bc03437a 2.8.0-rc-1, 0.17.6-28
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-01-24 17:11:28 +01:00
zsviczian
23b94da8f0 update LOCALE to read from localStorage
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-01-24 13:12:24 +01:00
zsviczian
1f227ddd24 Update manifest-beta.json 2025-01-24 07:24:50 +01:00
zsviczian
12152665af 2.8.0-beta-5
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-01-22 23:55:10 +01:00
26 changed files with 607 additions and 153 deletions

View File

@@ -38,7 +38,7 @@ async function getImageSize(src: string): Promise<{ height: number; width: numbe
export async function tex2dataURL(
tex: string,
scale: number = 4,
app?: any
plugin?: any
): Promise<{
mimeType: string;
fileId: FileId;
@@ -50,9 +50,9 @@ export async function tex2dataURL(
let output: SVG<unknown, unknown, unknown>;
if(!adaptor) {
if (app) {
const file = app.vault.getAbstractFileByPath("preamble.sty");
preamble = file ? await app.vault.read(file) : null;
if (plugin) {
const file = plugin.app.vault.getAbstractFileByPath(plugin.settings.latexPreambleLocation || "preamble.sty");
preamble = file ? await plugin.app.vault.read(file) : null;
}
adaptor = liteAdaptor();
RegisterHTMLHandler(adaptor);
@@ -69,10 +69,18 @@ export async function tex2dataURL(
try {
const node = html.convert(
preamble ? `${preamble}${tex}` : tex,
preamble ? `${preamble}\n${tex}` : tex,
{ display: true, scale }
);
const svg = new DOMParser().parseFromString(adaptor.innerHTML(node), "image/svg+xml").firstChild as SVGSVGElement;
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2195
//https://stackoverflow.com/a/77181931
let styleNode = document.createElement('style');
styleNode.setAttribute("type", "text/css");
styleNode.appendChild(document.createTextNode(".mjx-solid { stroke-width: 80px; }"));
svg.appendChild(styleNode);
if (svg) {
if(svg.width.baseVal.valueInSpecifiedUnits < 2) {
svg.width.baseVal.valueAsString = `${(svg.width.baseVal.valueInSpecifiedUnits+1).toFixed(3)}ex`;

View File

@@ -89,8 +89,8 @@ Plugin settings are grouped into the following sections:
- **Basic settings**: such as default folders to use.
- **Saving**: compression and autosave timer.
- **Filename**: configure the automatically created Excalidraw filename.
- **Display**: settings that effect the handling of Excalidraw (e.g.: left-handed mode, theme settings, mouse wheel and pinch zoom settings, zoom to fit settings).
- **Links and transclusions**: Settings that effect how links and embedded items behave on the Excalidraw canvas.
- **Display**: settings that affect the handling of Excalidraw (e.g.: left-handed mode, theme settings, mouse wheel and pinch zoom settings, zoom to fit settings).
- **Links and transclusions**: Settings that affect how links and embedded items behave on the Excalidraw canvas.
- **Markdown-embed settings**: These settings control how markdown documents from your Vault embedded into Excalidraw drawings will behave.
- **Embed & Export**: Settings that control how Excalidraw images are displayed when embedding them into markdown documents.
- **Auto-export Settings**: You can configure Excalidraw to create a PNG or SVG copy of your drawing each time it gets saved.

View File

@@ -21,7 +21,7 @@ The script will convert your drawing into a slideshow presentation.
```javascript
*/
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("2.1.7")) {
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("2.8.0")) {
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
return;
}
@@ -46,6 +46,8 @@ const TRANSITION_DELAY = 1000; //maximum time for transition between slides in m
const FRAME_SLEEP = 1; //milliseconds
const EDIT_ZOOMOUT = 0.7; //70% of original slide zoom, set to a value between 1 and 0
const FADE_LEVEL = 0.1; //opacity of the slideshow controls after fade delay (value between 0 and 1)
const PRINT_SLIDE_WIDTH = 1920;
const PRINT_SLIDE_HEIGHT = 1080;
//using outerHTML because the SVG object returned by Obsidin is in the main workspace window
//but excalidraw might be open in a popout window which has a different document object
const SVG_COG = ea.obsidian.getIcon("lucide-settings").outerHTML;
@@ -57,6 +59,7 @@ const SVG_MAXIMIZE = ea.obsidian.getIcon("lucide-maximize").outerHTML;
const SVG_MINIMIZE = ea.obsidian.getIcon("lucide-minimize").outerHTML;
const SVG_LASER_ON = ea.obsidian.getIcon("lucide-hand").outerHTML;
const SVG_LASER_OFF = ea.obsidian.getIcon("lucide-wand").outerHTML;
const SVG_PRINTER = ea.obsidian.getIcon("lucide-printer").outerHTML;
//-------------------------------
//utility & convenience functions
@@ -202,7 +205,7 @@ const gotoFullscreen = async () => {
}
await waitForExcalidrawResize();
const layerUIWrapper = contentEl.querySelector(".layer-ui__wrapper");
if(!layerUIWrapper.hasClass("excalidraw-hidden")) layerUIWrapper.addClass("excalidraw-hidden");
if(!layerUIWrapper?.hasClass("excalidraw-hidden")) layerUIWrapper.addClass("excalidraw-hidden");
if(toggleFullscreenButton) toggleFullscreenButton.innerHTML = SVG_MINIMIZE;
resetControlPanelElPosition();
isFullscreen = true;
@@ -271,8 +274,8 @@ if(presentationPathType==="line") {
//-----------------------------
// scroll-to-location functions
//-----------------------------
const getNavigationRect = ({ x1, y1, x2, y2 }) => {
const { width, height } = excalidrawAPI.getAppState();
const getNavigationRect = ({ x1, y1, x2, y2, printDimensions }) => {
const { width, height } = printDimensions ? printDimensions : excalidrawAPI.getAppState();
const ratioX = width / Math.abs(x1 - x2);
const ratioY = height / Math.abs(y1 - y2);
let ratio = Math.min(Math.max(ratioX, ratioY), 30);
@@ -534,6 +537,20 @@ const createPresentationNavigationPanel = () => {
}
});
}
if(ea.DEVICE.isDesktop) {
el.createEl("button",{
attr: {
style: `
margin-right: calc(var(--default-button-size)*0.25);`,
title: `Print to PDF\nClick to print slides at ${PRINT_SLIDE_WIDTH}x${
PRINT_SLIDE_HEIGHT}\nHold SHIFT to print the presentation as displayed`
//${!presentationPathLineEl ? "\nHold ALT/OPT to clip frames":""}`
}
}, button => {
button.innerHTML = SVG_PRINTER;
button.onclick = (e) => printToPDF(e);
});
}
el.createEl("button",{
attr: {
style: `
@@ -542,7 +559,7 @@ const createPresentationNavigationPanel = () => {
}
}, button => {
button.innerHTML = SVG_FINISH;
button.onclick = () => exitPresentation()
button.onclick = () => exitPresentation();
});
});
}
@@ -741,6 +758,96 @@ const exitPresentation = async (openForEdit = false) => {
}
}
//--------------------------
// Print to PDF
//--------------------------
let notice;
let noticeEl;
function setSingleNotice(message) {
if(noticeEl?.parentElement) {
notice.setMessage(message);
return;
}
notice = new Notice(message, 0);
noticeEl = notice.containerEl ?? notice.noticeEl;
}
function hideSingleNotice() {
if(noticeEl?.parentElement) {
notice.hide();
}
}
const translateToZero = ({ top, left, bottom, right }, padding) => {
const {topX, topY, width, height} = ea.getBoundingBox(ea.getViewElements());
const newTop = top - (topY - padding);
const newLeft = left - (topX - padding);
const newBottom = bottom - (topY - padding);
const newRight = right - (topX - padding);
return {
top: newTop,
left: newLeft,
bottom: newBottom,
right: newRight,
};
}
const printToPDF = async (e) => {
const slideWidth = e.shiftKey ? excalidrawAPI.getAppState().width : PRINT_SLIDE_WIDTH;
const slideHeight = e.shiftKey ? excalidrawAPI.getAppState().height : PRINT_SLIDE_HEIGHT;
//const shouldClipFrames = !presentationPathLineEl && e.altKey;
const shouldClipFrames = false;
//huge padding to ensure the HD window always fits the width
//no padding if frames are clipped
const padding = shouldClipFrames ? 0 : Math.round(Math.max(slideWidth,slideHeight)/2)+10;
const st = ea.getExcalidrawAPI().getAppState();
setSingleNotice("Generating image. This can take a longer time depending on the size of the image and speed of your device");
const svg = await ea.createViewSVG({
withBackground: true,
theme: st.theme,
frameRendering: { enabled: shouldClipFrames, name: false, outline: false, clip: shouldClipFrames },
padding,
selectedOnly: false,
skipInliningFonts: false,
embedScene: false,
});
const pages = [];
for(i=0;i<slides.length;i++) {
setSingleNotice(`Generating slide ${i+1}`);
const s = slides[i];
const { top, left, bottom, right } = translateToZero(
getNavigationRect({
...s,
printDimensions: {width: slideWidth, height: slideHeight}
}), padding
);
//always create the new SVG in the main Obsidian workspace (not the popout window, if present)
const host = window.createDiv();
host.innerHTML = svg.outerHTML;
const clonedSVG = host.firstElementChild;
const width = Math.abs(left-right);
const height = Math.abs(top-bottom);
clonedSVG.setAttribute("viewBox", `${left} ${top} ${width} ${height}`);
clonedSVG.setAttribute("width", `${width}`);
clonedSVG.setAttribute("height", `${height}`);
pages.push(clonedSVG);
}
const bgColor = ea.getExcalidrawAPI().getAppState().viewBackgroundColor;
setSingleNotice("Creating PDF Document");
ea.createPDF({
SVG: pages,
scale: { fitToPage: true },
pageProps: {
dimensions: { width: slideWidth, height: slideHeight },
backgroundColor: bgColor,
margin: { left: 0, right: 0, top: 0, bottom: 0 },
alignment: "center"
},
filename: ea.targetView.file.basename + ".pdf",
}).then(()=>hideSingleNotice());
}
//--------------------------
// Start presentation or open presentation settings on double click
//--------------------------
@@ -768,7 +875,11 @@ const start = async () => {
}
const timestamp = Date.now();
if(window.ExcalidrawSlideshow && (window.ExcalidrawSlideshow.script === utils.scriptFile.path) && (timestamp - window.ExcalidrawSlideshow.timestamp <400) ) {
if(
window.ExcalidrawSlideshow &&
(window.ExcalidrawSlideshow.script === utils.scriptFile.path) &&
(timestamp - window.ExcalidrawSlideshow.timestamp <400)
) {
if(window.ExcalidrawSlideshowStartTimer) {
window.clearTimeout(window.ExcalidrawSlideshowStartTimer);
delete window.ExcalidrawSlideshowStartTimer;
@@ -789,4 +900,4 @@ if(window.ExcalidrawSlideshow && (window.ExcalidrawSlideshow.script === utils.sc
window.ExcalidrawSlideshow.slide[ea.targetView.file.path] = 0;
window.ExcalidrawSlideshowStartTimer = window.setTimeout(start,500);
}
}

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.8.0-beta-4",
"version": "2.8.1",
"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.5",
"version": "2.8.1",
"minAppVersion": "1.1.6",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",

8
package-lock.json generated
View File

@@ -11,7 +11,7 @@
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/colormaster": "^1.2.2",
"@zsviczian/excalidraw": "0.17.6-27",
"@zsviczian/excalidraw": "0.17.6-29",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"es6-promise-pool": "2.5.0",
@@ -3336,9 +3336,9 @@
"license": "MIT"
},
"node_modules/@zsviczian/excalidraw": {
"version": "0.17.6-27",
"resolved": "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.17.6-27.tgz",
"integrity": "sha512-8E5pfMbKO80d9oXyApF43SCKaR0CcLhVHjiQYEuAXzS7v6XzrDHODsNg+HuN9kOiShXmmn/e1MKVawo7bmeuOQ==",
"version": "0.17.6-29",
"resolved": "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.17.6-29.tgz",
"integrity": "sha512-4UpAk1JGlHacjr3pyIhBU6e5+tgSggSq0+FhHEYPbeahLUAhnLXnpSLZUpEXTaftO4xooXOOvObB6BG/cfjaRA==",
"dependencies": {
"@braintree/sanitize-url": "6.0.2",
"@excalidraw/random-username": "1.1.0",

View File

@@ -24,7 +24,7 @@
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/excalidraw": "0.17.6-27",
"@zsviczian/excalidraw": "0.17.6-29",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"@zsviczian/colormaster": "^1.2.2",

View File

@@ -26,7 +26,7 @@ export const ERROR_IFRAME_CONVERSION_CANCELED = "iframe conversion canceled";
declare const excalidrawLib: typeof ExcalidrawLib;
export const LOCALE = moment.locale();
export const LOCALE = localStorage.getItem("language")?.toLowerCase() || "en";
export const CJK_FONTS = "CJK Fonts";
export const obsidianToExcalidrawMap: { [key: string]: string } = {
@@ -446,4 +446,4 @@ export const SCRIPTENGINE_ICON = `<g transform="translate(-8,-8)"><path d="M24.3
export const DISK_ICON_NAME = "save";
export const EXPORT_IMG_ICON = ` <g transform="scale(4.166)" strokeWidth="1.25" fill="none" stroke="currentColor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M15 8h.01"></path><path d="M12 20h-5a3 3 0 0 1 -3 -3v-10a3 3 0 0 1 3 -3h10a3 3 0 0 1 3 3v5"></path><path d="M4 15l4 -4c.928 -.893 2.072 -.893 3 0l4 4"></path><path d="M14 14l1 -1c.617 -.593 1.328 -.793 2.009 -.598"></path><path d="M19 16v6"></path><path d="M22 19l-3 3l-3 -3"></path></g>`;
export const EXPORT_IMG_ICON_NAME = `export-img`;
export const EXCALIDRAW_ICON = `<path d="M24 17h121v121H24z" style="fill:none" transform="matrix(.8843 0 0 .83471 -21.223 -14.19)"/><path d="M119.81 105.98a.549.549 0 0 0-.53-.12c-4.19-6.19-9.52-12.06-14.68-17.73l-.85-.93c0-.11-.05-.21-.12-.3a.548.548 0 0 0-.34-.2l-.17-.18-.12-.09c-.15-.32-.53-.56-.95-.35-1.58.81-3 1.97-4.4 3.04-1.87 1.43-3.7 2.92-5.42 4.52-.7.65-1.39 1.33-1.97 2.09-.28.37-.07.72.27.87-1.22 1.2-2.45 2.45-3.68 3.74-.11.12-.17.28-.16.44.01.16.09.31.22.41l2.16 1.65s.01.03.03.04c3.09 3.05 8.51 7.28 14.25 11.76.85.67 1.71 1.34 2.57 2.01.39.47.76.94 1.12 1.4.19.25.55.3.8.11.13.1.26.21.39.31a.57.57 0 0 0 .8-.1c.07-.09.1-.2.11-.31.04 0 .07.03.1.03.15 0 .31-.06.42-.18l10.18-11.12a.56.56 0 0 0-.04-.8l.01-.01Zm-29.23-3.85c.07.09.14.17.21.25 1.16.98 2.4 2.04 3.66 3.12l-5.12-3.91s-.32-.22-.52-.36c-.11-.08-.21-.16-.31-.24l-.38-.32s.07-.07.1-.11l.35-.35c1.72-1.74 4.67-4.64 6.19-6.06-1.61 1.62-4.87 6.37-4.17 7.98h-.01Zm17.53 13.81-4.22-3.22c-1.65-1.71-3.43-3.4-5.24-5.03 2.28 1.76 4.23 3.25 4.52 3.51 2.21 1.97 2.11 1.61 3.63 2.91l1.83 1.33c-.18.16-.36.33-.53.49l.01.01Zm1.06.81-.08-.06c.16-.13.33-.25.49-.38l-.4.44h-.01Zm-66.93-65.3c.14.72.27 1.43.4 2.11.69 3.7 1.33 7.03 2.55 9.56l.48 1.92c.19.73.46 1.64.71 1.83 2.85 2.52 7.22 6.28 11.89 9.82.21.16.5.15.7-.01.01.02.03.03.04.04.11.1.24.15.38.15.16 0 .31-.06.42-.19 5.98-6.65 10.43-12.12 13.6-16.7.2-.25.3-.54.29-.84.2-.24.41-.48.6-.68a.558.558 0 0 0-.1-.86.578.578 0 0 0-.17-.36c-1.39-1.34-2.42-2.31-3.46-3.28-1.84-1.72-3.74-3.5-7.77-7.51-.02-.02-.05-.04-.07-.06a.555.555 0 0 0-.22-.14c-1.11-.39-3.39-.78-6.26-1.28-4.22-.72-10-1.72-15.2-3.27h-.04v-.01s-.02 0-.03.02h-.01l.04-.02s-.31.01-.37.04c-.08.04-.14.09-.19.15-.05.06-.09.12-.47.2-.38.08.08 0 .11 0h-.11v.03c.07.34.05.58.16.97-.02.1.21 1.02.24 1.11l1.83 7.26h.03Zm30.95 6.54s-.03.04-.04.05l-.64-.71c.22.21.44.42.68.66Zm-7.09 9.39s-.07.08-.1.12l-.02-.02c.04-.03.08-.07.13-.1h-.01Zm-7.07 8.47Zm3.02-28.57c.35.35 1.74 1.65 2.06 1.97-1.45-.66-5.06-2.34-6.74-2.88 1.65.29 3.93.66 4.68.91Zm-19.18-2.77c.84 1.44 1.5 6.49 2.16 11.4-.37-1.58-.69-3.12-.99-4.6-.52-2.56-1-4.85-1.67-6.88.14.01.31.03.49.05 0 .01 0 .02.02.03h-.01Zm-.29-1.21c-.23-.02-.44-.04-.62-.05-.02-.04-.03-.08-.04-.12l.66.18v-.01Zm-2.22.45v-.02.02Zm78.54-1.18c.04-.23-1.1-1.24-.74-1.26.85-.04.86-1.35 0-1.31-1.13.06-2.27.32-3.37.53-1.98.37-3.95.78-5.92 1.21-4.39.94-8.77 1.93-13.1 3.11-1.36.37-2.86.7-4.11 1.36-.42.22-.4.67-.17.95-.09.05-.18.08-.28.09-.37.07-.74.13-1.11.19a.566.566 0 0 0-.39.86c-2.32 3.1-4.96 6.44-7.82 9.95-2.81 3.21-5.73 6.63-8.72 10.14-9.41 11.06-20.08 23.6-31.9 34.64-.23.21-.24.57-.03.8.05.06.12.1.19.13-.16.15-.32.3-.48.44-.1.09-.14.2-.16.32-.08.08-.16.17-.23.25-.21.23-.2.59.03.8.23.21.59.2.8-.03.04-.04.08-.09.12-.13a.84.84 0 0 1 1.22 0c.69.74 1.34 1.44 1.95 2.09l-1.38-1.15a.57.57 0 0 0-.8.07c-.2.24-.17.6.07.8l14.82 12.43c.11.09.24.13.37.13.15 0 .29-.06.4-.17l.36-.36a.56.56 0 0 0 .63-.12c20.09-20.18 36.27-35.43 54.8-49.06.17-.12.25-.32.23-.51a.57.57 0 0 0 .48-.39c3.42-10.46 4.08-19.72 4.28-24.27 0-.03.01-.05.02-.07.02-.05.03-.1.04-.14.03-.11.05-.19.05-.19.26-.78.17-1.53-.15-2.15v.02ZM82.98 58.94c.9-1.03 1.79-2.04 2.67-3.02-5.76 7.58-15.3 19.26-28.81 33.14 9.2-10.18 18.47-20.73 26.14-30.12Zm-32.55 52.81-.03-.03c.11.02.19.04.2.04a.47.47 0 0 0-.17 0v-.01Zm6.9 6.42-.05-.04.03-.03c.02 0 .03.02.04.02 0 .02-.02.03-.03.05h.01Zm8.36-7.21 1.38-1.44c.01.01.02.03.03.05-.47.46-.94.93-1.42 1.39h.01Zm2.24-2.21c.26-.3.56-.65.87-1.02.01-.01.02-.03.04-.04 3.29-3.39 6.68-6.82 10.18-10.25.02-.02.05-.04.07-.06.86-.66 1.82-1.39 2.72-2.08-4.52 4.32-9.11 8.78-13.88 13.46v-.01Zm21.65-55.88c-1.86 2.42-3.9 5.56-5.63 8.07-5.46 7.91-23.04 27.28-23.43 27.65-2.71 2.62-10.88 10.46-16.09 15.37-.14.13-.25.24-.34.35a.794.794 0 0 1 .03-1.13c24.82-23.4 39.88-42.89 46-51.38-.13.33-.24.69-.55 1.09l.01-.02Zm16.51 7.1-.01.02c0-.02-.02-.07.01-.02Zm-.91-5.13Zm-5.89 9.45c-2.26-1.31-3.32-3.27-2.71-5.25l.19-.66c.08-.19.17-.38.28-.57.59-.98 1.49-1.85 2.52-2.36.05-.02.1-.03.15-.04a.795.795 0 0 1-.04-.43c.05-.31.25-.58.66-.58.67 0 2.75.62 3.54 1.3.24.19.47.4.68.63.3.35.74.92.96 1.33.13.06.23.62.38.91.14.46.2.93.18 1.4 0 .02 0 .02.01.03-.03.07 0 .37-.04.4-.1.72-.36 1.43-.75 2.05-.04.05-.07.11-.11.16 0 .01-.02.02-.03.04-.3.43-.65.83-1.08 1.13-1.26.89-2.73 1.16-4.2.79a6.33 6.33 0 0 1-.57-.25l-.02-.03Zm16.27-1.63c-.49 2.05-1.09 4.19-1.8 6.38-.03.08-.03.16-.03.23-.1.01-.19.05-.27.11-4.44 3.26-8.73 6.62-12.98 10.11 3.67-3.32 7.39-6.62 11.23-9.95a6.409 6.409 0 0 0 2.11-3.74l.56-3.37.03-.1c.25-.71 1.34-.4 1.17.33h-.02Z" style="fill:currentColor;fill-rule:nonzero" transform="translate(-26.41 -29.49)"/>`;
export const EXCALIDRAW_ICON = `<path d="M24 17h121v121H24z" style="fill:none" transform="matrix(.8843 0 0 .83471 -21.223 -14.19)"/><path d="M119.81 105.98a.549.549 0 0 0-.53-.12c-4.19-6.19-9.52-12.06-14.68-17.73l-.85-.93c0-.11-.05-.21-.12-.3a.548.548 0 0 0-.34-.2l-.17-.18-.12-.09c-.15-.32-.53-.56-.95-.35-1.58.81-3 1.97-4.4 3.04-1.87 1.43-3.7 2.92-5.42 4.52-.7.65-1.39 1.33-1.97 2.09-.28.37-.07.72.27.87-1.22 1.2-2.45 2.45-3.68 3.74-.11.12-.17.28-.16.44.01.16.09.31.22.41l2.16 1.65s.01.03.03.04c3.09 3.05 8.51 7.28 14.25 11.76.85.67 1.71 1.34 2.57 2.01.39.47.76.94 1.12 1.4.19.25.55.3.8.11.13.1.26.21.39.31a.57.57 0 0 0 .8-.1c.07-.09.1-.2.11-.31.04 0 .07.03.1.03.15 0 .31-.06.42-.18l10.18-11.12a.56.56 0 0 0-.04-.8l.01-.01Zm-29.23-3.85c.07.09.14.17.21.25 1.16.98 2.4 2.04 3.66 3.12l-5.12-3.91s-.32-.22-.52-.36c-.11-.08-.21-.16-.31-.24l-.38-.32s.07-.07.1-.11l.35-.35c1.72-1.74 4.67-4.64 6.19-6.06-1.61 1.62-4.87 6.37-4.17 7.98h-.01Zm17.53 13.81-4.22-3.22c-1.65-1.71-3.43-3.4-5.24-5.03 2.28 1.76 4.23 3.25 4.52 3.51 2.21 1.97 2.11 1.61 3.63 2.91l1.83 1.33c-.18.16-.36.33-.53.49l.01.01Zm1.06.81-.08-.06c.16-.13.33-.25.49-.38l-.4.44h-.01Zm-66.93-65.3c.14.72.27 1.43.4 2.11.69 3.7 1.33 7.03 2.55 9.56l.48 1.92c.19.73.46 1.64.71 1.83 2.85 2.52 7.22 6.28 11.89 9.82.21.16.5.15.7-.01.01.02.03.03.04.04.11.1.24.15.38.15.16 0 .31-.06.42-.19 5.98-6.65 10.43-12.12 13.6-16.7.2-.25.3-.54.29-.84.2-.24.41-.48.6-.68a.558.558 0 0 0-.1-.86.578.578 0 0 0-.17-.36c-1.39-1.34-2.42-2.31-3.46-3.28-1.84-1.72-3.74-3.5-7.77-7.51-.02-.02-.05-.04-.07-.06a.555.555 0 0 0-.22-.14c-1.11-.39-3.39-.78-6.26-1.28-4.22-.72-10-1.72-15.2-3.27h-.04v-.01s-.02 0-.03.02h-.01l.04-.02s-.31.01-.37.04c-.08.04-.14.09-.19.15-.05.06-.09.12-.47.2-.38.08.08 0 .11 0h-.11v.03c.07.34.05.58.16.97-.02.1.21 1.02.24 1.11l1.83 7.26h.03Zm30.95 6.54s-.03.04-.04.05l-.64-.71c.22.21.44.42.68.66Zm-7.09 9.39s-.07.08-.1.12l-.02-.02c.04-.03.08-.07.13-.1h-.01Zm-7.07 8.47Zm3.02-28.57c.35.35 1.74 1.65 2.06 1.97-1.45-.66-5.06-2.34-6.74-2.88 1.65.29 3.93.66 4.68.91Zm-19.18-2.77c.84 1.44 1.5 6.49 2.16 11.4-.37-1.58-.69-3.12-.99-4.6-.52-2.56-1-4.85-1.67-6.88.14.01.31.03.49.05 0 .01 0 .02.02.03h-.01Zm-.29-1.21c-.23-.02-.44-.04-.62-.05-.02-.04-.03-.08-.04-.12l.66.18v-.01Zm-2.22.45v-.02.02Zm78.54-1.18c.04-.23-1.1-1.24-.74-1.26.85-.04.86-1.35 0-1.31-1.13.06-2.27.32-3.37.53-1.98.37-3.95.78-5.92 1.21-4.39.94-8.77 1.93-13.1 3.11-1.36.37-2.86.7-4.11 1.36-.42.22-.4.67-.17.95-.09.05-.18.08-.28.09-.37.07-.74.13-1.11.19a.566.566 0 0 0-.39.86c-2.32 3.1-4.96 6.44-7.82 9.95-2.81 3.21-5.73 6.63-8.72 10.14-9.41 11.06-20.08 23.6-31.9 34.64-.23.21-.24.57-.03.8.05.06.12.1.19.13-.16.15-.32.3-.48.44-.1.09-.14.2-.16.32-.08.08-.16.17-.23.25-.21.23-.2.59.03.8.23.21.59.2.8-.03.04-.04.08-.09.12-.13a.84.84 0 0 1 1.22 0c.69.74 1.34 1.44 1.95 2.09l-1.38-1.15a.57.57 0 0 0-.8.07c-.2.24-.17.6.07.8l14.82 12.43c.11.09.24.13.37.13.15 0 .29-.06.4-.17l.36-.36a.56.56 0 0 0 .63-.12c20.09-20.18 36.27-35.43 54.8-49.06.17-.12.25-.32.23-.51a.57.57 0 0 0 .48-.39c3.42-10.46 4.08-19.72 4.28-24.27 0-.03.01-.05.02-.07.02-.05.03-.1.04-.14.03-.11.05-.19.05-.19.26-.78.17-1.53-.15-2.15v.02ZM82.98 58.94c.9-1.03 1.79-2.04 2.67-3.02-5.76 7.58-15.3 19.26-28.81 33.14 9.2-10.18 18.47-20.73 26.14-30.12Zm-32.55 52.81-.03-.03c.11.02.19.04.2.04a.47.47 0 0 0-.17 0v-.01Zm6.9 6.42-.05-.04.03-.03c.02 0 .03.02.04.02 0 .02-.02.03-.03.05h.01Zm8.36-7.21 1.38-1.44c.01.01.02.03.03.05-.47.46-.94.93-1.42 1.39h.01Zm2.24-2.21c.26-.3.56-.65.87-1.02.01-.01.02-.03.04-.04 3.29-3.39 6.68-6.82 10.18-10.25.02-.02.05-.04.07-.06.86-.66 1.82-1.39 2.72-2.08-4.52 4.32-9.11 8.78-13.88 13.46v-.01Zm21.65-55.88c-1.86 2.42-3.9 5.56-5.63 8.07-5.46 7.91-23.04 27.28-23.43 27.65-2.71 2.62-10.88 10.46-16.09 15.37-.14.13-.25.24-.34.35a.794.794 0 0 1 .03-1.13c24.82-23.4 39.88-42.89 46-51.38-.13.33-.24.69-.55 1.09l.01-.02Zm16.51 7.1-.01.02c0-.02-.02-.07.01-.02Zm-.91-5.13Zm-5.89 9.45c-2.26-1.31-3.32-3.27-2.71-5.25l.19-.66c.08-.19.17-.38.28-.57.59-.98 1.49-1.85 2.52-2.36.05-.02.1-.03.15-.04a.795.795 0 0 1-.04-.43c.05-.31.25-.58.66-.58.67 0 2.75.62 3.54 1.3.24.19.47.4.68.63.3.35.74.92.96 1.33.13.06.23.62.38.91.14.46.2.93.18 1.4 0 .02 0 .02.01.03-.03.07 0 .37-.04.4-.1.72-.36 1.43-.75 2.05-.04.05-.07.11-.11.16 0 .01-.02.02-.03.04-.3.43-.65.83-1.08 1.13-1.26.89-2.73 1.16-4.2.79a6.33 6.33 0 0 1-.57-.25l-.02-.03Zm16.27-1.63c-.49 2.05-1.09 4.19-1.8 6.38-.03.08-.03.16-.03.23-.1.01-.19.05-.27.11-4.44 3.26-8.73 6.62-12.98 10.11 3.67-3.32 7.39-6.62 11.23-9.95a6.409 6.409 0 0 0 2.11-3.74l.56-3.37.03-.1c.25-.71 1.34-.4 1.17.33h-.02Z" style="fill:currentColor;fill-rule:nonzero" transform="translate(-26.41 -29.49)"/>`;

View File

@@ -756,7 +756,6 @@ export class CommandManager {
if (view) {
if(!view.exportDialog) {
view.exportDialog = new ExportDialog(this.plugin, view,view.file);
view.exportDialog.createForm();
}
view.exportDialog.open();
return true;

View File

@@ -173,6 +173,7 @@ export interface ExcalidrawSettings {
showNewVersionNotification: boolean;
//mathjaxSourceURL: string;
latexBoilerplate: string;
latexPreambleLocation: string;
taskboneEnabled: boolean;
taskboneAPIkey: string;
pinnedScripts: string[];
@@ -348,6 +349,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
showNewVersionNotification: true,
//mathjaxSourceURL: "https://cdn.jsdelivr.net/npm/mathjax@3.2.1/es5/tex-svg.js",
latexBoilerplate: "\\color{blue}",
latexPreambleLocation: "preamble.sty",
taskboneEnabled: false,
taskboneAPIkey: "",
pinnedScripts: [],
@@ -2616,6 +2618,19 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
}),
);
new Setting(detailsEl)
.setName(t("LATEX_PREAMBLE_NAME"))
.setDesc(fragWithHTML(t("LATEX_PREAMBLE_DESC")))
.addText((text) =>
text
.setPlaceholder("e.g.: preamble.sty")
.setValue(this.plugin.settings.latexPreambleLocation)
.onChange(async (value) => {
this.plugin.settings.latexPreambleLocation = value;
this.applySettingsUpdate();
}),
);
new Setting(detailsEl)
.setName(t("FILETYPE_NAME"))
.setDesc(fragWithHTML(t("FILETYPE_DESC")))

View File

@@ -722,6 +722,8 @@ FILENAME_HEAD: "Filename",
"restart Obsidian after closing settings, for this change to take effect.",
LATEX_DEFAULT_NAME: "Default LaTeX formula for new equations",
LATEX_DEFAULT_DESC: "Leave empty if you don't want a default formula. You can add default formatting here such as <code>\\color{white}</code>.",
LATEX_PREAMBLE_NAME: "LaTeX preamble file (CasE SEnSiTivE!)",
LATEX_PREAMBLE_DESC: "Full filepath to the preamble file, leave empty for default. If the file doesn't exist this option will be ignored.<br><strong>Important:</strong> Requires obsidian reload after change to take effect!",
NONSTANDARD_HEAD: "Non-Excalidraw.com supported features",
NONSTANDARD_DESC: `These settings in the "Non-Excalidraw.com Supported Features" section provide customization options beyond the default Excalidraw.com features. These features are not available on excalidraw.com. When exporting the drawing to Excalidraw.com these features will appear different.
You can configure the number of custom pens displayed next to the Obsidian Menu on the canvas, allowing you to choose from a range of options. Additionally, you can enable a local font option, which adds a local font to the list of fonts on the element properties panel for text elements. `,
@@ -1050,12 +1052,12 @@ FILENAME_HEAD: "Filename",
EXPORTDIALOG_ORIENTATION_LANDSCAPE: "Landscape",
EXPORTDIALOG_PDF_FIT_TO_PAGE: "Page Fitting",
EXPORTDIALOG_PDF_FIT_OPTION: "Fit to page",
EXPORTDIALOG_PDF_FIT_2_OPTION: "Fit to 2-pages",
EXPORTDIALOG_PDF_FIT_4_OPTION: "Fit to 4-pages",
EXPORTDIALOG_PDF_FIT_6_OPTION: "Fit to 6-pages",
EXPORTDIALOG_PDF_FIT_8_OPTION: "Fit to 8-pages",
EXPORTDIALOG_PDF_FIT_12_OPTION: "Fit to 12-pages",
EXPORTDIALOG_PDF_FIT_16_OPTION: "Fit to 16-pages",
EXPORTDIALOG_PDF_FIT_2_OPTION: "Fit to max 2-pages",
EXPORTDIALOG_PDF_FIT_4_OPTION: "Fit to max 4-pages",
EXPORTDIALOG_PDF_FIT_6_OPTION: "Fit to max 6-pages",
EXPORTDIALOG_PDF_FIT_8_OPTION: "Fit to max 8-pages",
EXPORTDIALOG_PDF_FIT_12_OPTION: "Fit to max 12-pages",
EXPORTDIALOG_PDF_FIT_16_OPTION: "Fit to max 16-pages",
EXPORTDIALOG_PDF_SCALE_OPTION: "Use image scale (may span multiple pages)",
EXPORTDIALOG_PDF_PAPER_COLOR: "Paper Color",
EXPORTDIALOG_PDF_PAPER_WHITE: "White",
@@ -1063,6 +1065,8 @@ FILENAME_HEAD: "Filename",
EXPORTDIALOG_PDF_PAPER_CUSTOM: "Custom color",
EXPORTDIALOG_PDF_ALIGNMENT: "Position on Page",
EXPORTDIALOG_PDF_ALIGN_CENTER: "Center",
EXPORTDIALOG_PDF_ALIGN_CENTER_LEFT: "Center Left",
EXPORTDIALOG_PDF_ALIGN_CENTER_RIGHT: "Center Right",
EXPORTDIALOG_PDF_ALIGN_TOP_LEFT: "Top Left",
EXPORTDIALOG_PDF_ALIGN_TOP_CENTER: "Top Center",
EXPORTDIALOG_PDF_ALIGN_TOP_RIGHT: "Top Right",

View File

@@ -70,6 +70,7 @@ export class ExportDialog extends Modal {
this.margin = plugin.settings.pdfSettings.margin;
this.saveSettings = false;
this.createForm();
}
destroy() {
@@ -97,7 +98,7 @@ export class ExportDialog extends Modal {
this.dirty = this.saveSettings;
}
async createForm() {
createForm() {
if(DEVICE.isDesktop) {
// Create tab container
const tabContainer = this.contentEl.createDiv("nav-buttons-container");
@@ -391,7 +392,6 @@ export class ExportDialog extends Modal {
});
bPDFExport.onclick = () => {
this.view.exportPDF(
false,
this.hasSelectedElements && this.exportSelectedOnly,
this.pageSize,
this.pageOrientation
@@ -402,7 +402,7 @@ export class ExportDialog extends Modal {
public getPaperColor(): string {
switch (this.paperColor) {
case "white": return "#ffffff";
case "white": return this.theme === "light" ? "#ffffff" : "#000000";
case "scene": return this.api.getAppState().viewBackgroundColor;
case "custom": return this.customPaperColor;
default: return "#ffffff";

View File

@@ -17,6 +17,95 @@ 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.8.1":`
## Fixed
- Unable to open Excalidraw files after the 2.8.0 update. [#2235](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2235)
`,
"2.8.0":`
<div class="excalidraw-videoWrapper"><div>
<iframe src="https://www.youtube.com/embed/tWi5xTUTz7E" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></div>
## New
- Updated "Export Image" dialog
- 🚀 PDF Export option including tiling of images over multiple pages. Only available on desktop :(
- SVG to clipboard
- More granular setting for padding and scale
- Slideshow script can now print slides to PDF (update script from script store)
- Set local graph to show the links in the embeddable when it is activated/deactivated [#2200](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2200)
## Fixed
- Fixed several LaTeX issues. 🙏 @Sintuz [#1631](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1631), [#2195](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2195), [#1842](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1842)
- Fixed support for *.jfif and *.avif images [#2212](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2212)
- PDF++ selection is not correctly showing after embedded into a drawing (for some specific files) [#2213](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2213)
- iOS 18 can't upload image and library [#2182](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2182)
- Image block references are broken in hover previews [#2218](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2218)
- ⚠️ Note there is a known issue in Obsidian 1.8.2 ⚠️ affecting preview windows in Excalidraw. I received confirmation that this will be fixed in 1.8.3. For now, if hover previews are important to you, you can downgrade to Obsidian 1.8.1 [#2228](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2225)
- Mobile elements panel and context menu are not scrollable [#2216](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2216)
- "Local Font" menu disappears when opening a drawing in an Obsidian popout-window [#2205](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2205)
## Updates from Excalidraw.com
- Pressing delete on a frame will only delete the children [#9011](https://github.com/excalidraw/excalidraw/pull/9011)
- New crowfoot arrowheads and a new arrowhead picker [#8942](https://github.com/excalidraw/excalidraw/pull/8942)
- Fixed some of the arrow binding issues [#9010](https://github.com/excalidraw/excalidraw/pull/9010), [#2209](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2209)
- New context menu action: "Wrap selection in frame" [#9005](https://github.com/excalidraw/excalidraw/pull/9005)
- Elbow arrow segment fixing and positioning [#8952](https://github.com/excalidraw/excalidraw/pull/8952)
- When drag creating a new frame, do not add a partial group to it. When wrapping a selected partial group in a frame however, do add it to the wrapping frame. But such that it should be separated from the previous containing group. [#9014](https://github.com/excalidraw/excalidraw/pull/9014)
## New in ExcalidrawAutomate
- New hook: ${String.fromCharCode(96)}onImageFileNameHook${String.fromCharCode(96)}. When set, this callback is triggered when a image is being saved in Excalidraw.
- PDF export functions, paving the way for slideshow to export slides to PDF
${String.fromCharCode(96,96,96)}ts
/**
* Returns the dimensions of a standard page size in pixels.
*/
function getPagePDFDimensions(
pageSize: PageSize,
orientation: PageOrientation
): PageDimensions;
/**
* Creates a PDF from the provided SVG elements with specified scaling and page properties.
*/
function createPDF(props: {
SVG: SVGSVGElement[];
scale?: PDFExportScale;
pageProps?: PDFPageProperties;
filename: string;
}): Promise<void>;
/**
* Creates an SVG representation of the current view.
*/
function createViewSVG(props : {
withBackground?: boolean;
theme?: "light" | "dark";
frameRendering?: FrameRenderingOptions;
padding?: number;
selectedOnly?: boolean;
skipInliningFonts?: boolean;
embedScene?: boolean;
}): Promise<SVGSVGElement>;
/**
* If set, this callback is triggered when a image is being saved in Excalidraw.
* You can use this callback to customize the naming and path of pasted images to avoid
* default names like "Pasted image 123147170.png" being saved in the attachments folder,
* and instead use more meaningful names based on the Excalidraw file or other criteria,
* plus save the image in a different folder.
*
* If the function returns null or undefined, the normal Excalidraw operation will continue
* with the excalidraw generated name and default path.
* If a filepath is returned, that will be used. Include the full Vault filepath and filename
* with the file extension.
* The currentImageName is the name of the image generated by excalidraw or provided during paste.
*/
function onImageFilePathHook: (data: {
currentImageName: string;
drawingFilePath: string;
}) => string = null;
${String.fromCharCode(96,96,96)}
`,
"2.7.5":`
## Fixed
- PDF export scenario described in [#2184](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2184)

View File

@@ -129,6 +129,8 @@ export class PDFExportSettingsComponent {
dropdown
.addOptions({
"center": t("EXPORTDIALOG_PDF_ALIGN_CENTER"),
"center-left": t("EXPORTDIALOG_PDF_ALIGN_CENTER_LEFT"),
"center-right": t("EXPORTDIALOG_PDF_ALIGN_CENTER_RIGHT"),
"top-left": t("EXPORTDIALOG_PDF_ALIGN_TOP_LEFT"),
"top-center": t("EXPORTDIALOG_PDF_ALIGN_TOP_CENTER"),
"top-right": t("EXPORTDIALOG_PDF_ALIGN_TOP_RIGHT"),

View File

@@ -226,14 +226,14 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
},
{
field: "createPDF",
code: "async createPDF({SVG: SVGSVGElement[], scale?: PDFExportScale, pageProps?: PDFPageProperties}): Promise<ArrayBuffer>",
desc: "",
after: "Creates a PDF from the provided SVG elements with specified scaling and page properties.\n" +
code: "async createPDF({SVG: SVGSVGElement[], scale?: PDFExportScale, pageProps?: PDFPageProperties, filename: string}): Promise<void>",
desc: "Creates a PDF from the provided SVG elements with specified scaling and page properties.\n" +
"\n" +
"@param {Object} params - The parameters for creating the PDF.\n" +
"@param {SVGSVGElement[]} params.SVG - An array of SVG elements to be included in the PDF. If multiple SVGs are provided, each will be added to a new page.\n" +
"@param {PDFExportScale} [params.scale={ fitToPage: true, zoom: 1 }] - The scaling options for the SVG elements.\n" +
"@param {PDFPageProperties} [params.pageProps] - The properties for the PDF pages.\n" +
"@param {string} params.filename - The name of the PDF file to be created.\n" +
"@returns {Promise<ArrayBuffer>} - A promise that resolves to an ArrayBuffer containing the PDF data.\n" +
"\n" +
"@typedef {Object} PDFExportScale\n" +
@@ -241,14 +241,11 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
"@property {number} [zoom=1] - The zoom level for the SVG. Used only if fitToPage is false. If the SVG does not fit the page, it will be tiled over multiple pages.\n" +
"\n" +
"@typedef {Object} PDFPageProperties\n" +
"@property {{width: number, height: number}} [dimensions] - The dimensions of the PDF pages. Use getPageDimensions to get standard page sizes.\n" +
"@property {{width: number, height: number}} [dimensions] - The dimensions of the PDF pages in pixels. Use getPageDimensions to get standard page sizes.\n" +
"@property {string} [backgroundColor] - The background color of the PDF pages.\n" +
"@property {PDFMargin} margin - The margins of the PDF pages.\n" +
"@property {PDFPageAlignment} alignment - The alignment of the SVG on the PDF pages.\n" +
"@property {number} exportDPI - The DPI of the exported PDF (150/300/600/1200).\n" +
"\n" +
"@example\n" +
"const pdfData = await createPDF({\n" +
"@property {PDFMargin} margin - The margins of the PDF pages in pixels.\n" +
"@property {PDFPageAlignment} alignment - The alignment of the SVG on the PDF pages.",
after: "({\n" +
" SVG: [svgElement1, svgElement2],\n" +
" scale: { fitToPage: true },\n" +
" pageProps: {\n" +
@@ -256,31 +253,57 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
" backgroundColor: \"#ffffff\",\n" +
" margin: { left: 20, right: 20, top: 20, bottom: 20 },\n" +
" alignment: \"center\"\n" +
" exportDPI: 300\n" +
" filename: \"myPDF.pdf\"\n" +
" }\n" +
"});",
},
{
field: "createViewSVG",
code: "async createViewSVG({withBackground?: boolean, theme?: 'light' | 'dark', frameRendering?: FrameRenderingOptions, padding?: number, selectedOnly?: boolean, skipInliningFonts?: boolean, embedScene?: boolean}): Promise<SVGSVGElement>",
desc: "Creates an SVG representation of the current view with specified options.\n" +
"\n" +
"@param {Object} options - The options for creating the SVG.\n" +
"@param {boolean} [options.withBackground=true] - Whether to include the background in the SVG.\n" +
"@param {\"light\" | \"dark\"} [options.theme] - The theme to use for the SVG.\n" +
"@param {FrameRenderingOptions} [options.frameRendering={enabled: true, name: true, outline: true, clip: true}] - The frame rendering options.\n" +
"@param {number} [options.padding] - The padding to apply around the SVG.\n" +
"@param {boolean} [options.selectedOnly=false] - Whether to include only the selected elements in the SVG.\n" +
"@param {boolean} [options.skipInliningFonts=false] - Whether to skip inlining fonts in the SVG.\n" +
"@param {boolean} [options.embedScene=false] - Whether to embed the scene in the SVG.\n" +
"@returns {Promise<SVGSVGElement>} A promise that resolves to the SVG element.\n" +
"\n" +
"@typedef {Object} FrameRenderingOptions\n" +
"@property {boolean} enabled - Whether frame rendering is enabled.\n" +
"@property {boolean} name - Whether to include the name in the frame rendering.\n" +
"@property {boolean} outline - Whether to include the outline in the frame rendering.\n" +
"@property {boolean} clip - Whether to clip the frame rendering.\n",
after: "({\n" +
" withBackground: true,\n" +
" theme: 'light',\n" +
" frameRendering: { enabled: true, name: true, outline: true, clip: true },\n" +
" padding: 10,\n" +
" selectedOnly: false,\n" +
" skipInliningFonts: false,\n" +
" embedScene: false,\n" +
"});",
},
{
field: "getPagePDFDimensions",
code: "getPagePDFDimensions(pageSize: PageSize, orientation: PageOrientation): PageDimensions",
desc: "Returns the dimensions of a standard page size in points (pt).\n" +
desc: "Returns the dimensions of a standard page size in pixels.\n" +
"\n" +
"@param {PageSize} pageSize - The standard page size. Possible values are \"A0\", \"A1\", \"A2\", \"A3\", \"A4\", \"A5\", \"Letter\", \"Legal\", \"Tabloid\".\n" +
"@param {PageOrientation} orientation - The orientation of the page. Possible values are \"portrait\" and \"landscape\".\n" +
"@returns {PageDimensions} - An object containing the width and height of the page in points (pt).\n" +
"@returns {PageDimensions} - An object containing the width and height of the page in pixels.\n" +
"\n" +
"@typedef {Object} PageDimensions\n" +
"@property {number} width - The width of the page in points (pt).\n" +
"@property {number} height - The height of the page in points (pt).\n" +
"@property {number} width - The width of the page in pixels.\n" +
"@property {number} height - The height of the page in pixels.\n" +
"\n" +
"@typedef {\"A0\" | \"A1\" | \"A2\" | \"A3\" | \"A4\" | \"A5\" | \"Letter\" | \"Legal\" | \"Tabloid\"} PageSize\n" +
"\n" +
"@typedef {\"portrait\" | \"landscape\"} PageOrientation\n" +
"\n" +
"@example\n" +
"const dimensions = getPDFPageDimensions(\"A4\", \"portrait\");\n" +
"console.log(dimensions); // { width: 595.28, height: 841.89 }",
after: "",
"@typedef {\"portrait\" | \"landscape\"} PageOrientation",
after: "(\"A4\", \"portrait\");",
},
{
field: "createPNG",

View File

@@ -704,7 +704,7 @@ export class EmbeddedFilesLoader {
}
if (!excalidrawData.getEquation(id).isLoaded) {
const latex = equation.latex;
const data = await tex2dataURL(latex, 4, this.plugin.app);
const data = await tex2dataURL(latex, 4, this.plugin);
if (data) {
const fileData = {
mimeType: data.mimeType,

View File

@@ -42,6 +42,8 @@ import {
wrapTextAtCharLength,
arrayToMap,
addAppendUpdateCustomData,
getSVG,
getWithBackground,
} from "src/utils/utils";
import { getAttachmentsFolderAndFilePath, getExcalidrawViews, getLeaf, getNewOrAdjacentLeaf, isObsidianThemeDark, mergeMarkdownFiles, openLeaf } from "src/utils/obsidianUtils";
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
@@ -84,6 +86,7 @@ import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types";
import { AddImageOptions, ImageInfo, SVGColorInfo } from "src/types/excalidrawAutomateTypes";
import { _measureText, cloneElement, createPNG, createSVG, errorMessage, filterColorMap, getEmbeddedFileForImageElment, getFontFamily, getLineBox, getTemplate, isColorStringTransparent, isSVGColorInfo, mergeColorMapIntoSVGColorInfo, normalizeLinePoints, repositionElementsToCursor, svgColorInfoToColorMap, updateOrAddSVGColorInfo, verifyMinimumPluginVersion } from "src/utils/excalidrawAutomateUtils";
import { exportToPDF, getMarginValue, getPageDimensions, PageDimensions, PageOrientation, PageSize, PDFExportScale, PDFPageProperties } from "src/utils/exportUtils";
import { FrameRenderingOptions } from "src/types/utilTypes";
extendPlugins([
HarmonyPlugin,
@@ -885,7 +888,7 @@ export class ExcalidrawAutomate {
Object.keys(this.imagesDict).forEach((key: FileId)=> {
const item = this.imagesDict[key];
if(item.latex) {
outString += `${key}: $$${item.latex}$$\n\n`;
outString += `${key}: $$${item.latex.trim()}$$\n\n`;
} else {
if(item.file) {
if(item.file instanceof TFile) {
@@ -932,19 +935,19 @@ export class ExcalidrawAutomate {
};
/**
* Returns the dimensions of a standard page size in points (pt).
* Returns the dimensions of a standard page size in pixels.
*
* @param {PageSize} pageSize - The standard page size. Possible values are "A0", "A1", "A2", "A3", "A4", "A5", "Letter", "Legal", "Tabloid".
* @param {PageOrientation} orientation - The orientation of the page. Possible values are "portrait" and "landscape".
* @returns {PageDimensions} - An object containing the width and height of the page in points (pt).
* @returns {PageDimensions} - An object containing the width and height of the page in pixels.
*
* @typedef {Object} PageDimensions
* @property {number} width - The width of the page in points (pt).
* @property {number} height - The height of the page in points (pt).
* @property {number} width - The width of the page in pixels.
* @property {number} height - The height of the page in pixels.
*
* @example
* const dimensions = getPageDimensions("A4", "portrait");
* console.log(dimensions); // { width: 595.28, height: 841.89 }
* console.log(dimensions); // { width: 794.56, height: 1122.56 }
*/
getPagePDFDimensions(pageSize: PageSize, orientation: PageOrientation): PageDimensions {
return getPageDimensions(pageSize, orientation);
@@ -964,12 +967,12 @@ export class ExcalidrawAutomate {
* SVG: [svgElement1, svgElement2],
* scale: { fitToPage: 1 },
* pageProps: {
* dimensions: { width: 595.28, height: 841.89 },
* dimensions: { width: 794.56, height: 1122.56 },
* backgroundColor: "#ffffff",
* margin: { left: 20, right: 20, top: 20, bottom: 20 },
* alignment: "center",
* exportDPI: 300,
* }
* filename: "example.pdf",
* });
*/
async createPDF({
@@ -1003,6 +1006,68 @@ export class ExcalidrawAutomate {
await exportToPDF({SVG, scale, pageProps, filename});
}
/**
* Creates an SVG representation of the current view.
*
* @param {Object} options - The options for creating the SVG.
* @param {boolean} [options.withBackground=true] - Whether to include the background in the SVG.
* @param {"light" | "dark"} [options.theme] - The theme to use for the SVG.
* @param {FrameRenderingOptions} [options.frameRendering={enabled: true, name: true, outline: true, clip: true}] - The frame rendering options.
* @param {number} [options.padding] - The padding to apply around the SVG.
* @param {boolean} [options.selectedOnly=false] - Whether to include only the selected elements in the SVG.
* @param {boolean} [options.skipInliningFonts=false] - Whether to skip inlining fonts in the SVG.
* @param {boolean} [options.embedScene=false] - Whether to embed the scene in the SVG.
* @returns {Promise<SVGSVGElement>} A promise that resolves to the SVG element.
*/
async createViewSVG({
withBackground = true,
theme,
frameRendering = {enabled: true, name: true, outline: true, clip: true},
padding,
selectedOnly = false,
skipInliningFonts = false,
embedScene = false,
} : {
withBackground?: boolean,
theme?: "light" | "dark",
frameRendering?: FrameRenderingOptions,
padding?: number,
selectedOnly?: boolean,
skipInliningFonts?: boolean,
embedScene?: boolean,
}): Promise<SVGSVGElement> {
if(!this.targetView || !this.targetView.file || !this.targetView._loaded) {
console.log("No view loaded");
return;
}
const view = this.targetView;
const scene = this.targetView.getScene(selectedOnly);
const exportSettings: ExportSettings = {
withBackground: view.getViewExportWithBackground(withBackground),
withTheme: true,
isMask: isMaskFile(this.plugin, view.file),
skipInliningFonts,
frameRendering,
};
return await getSVG(
{
...scene,
...{
appState: {
...scene.appState,
theme: view.getViewExportTheme(theme),
exportEmbedScene: view.getViewExportEmbedScene(embedScene),
},
},
},
exportSettings,
view.getViewExportPadding(padding),
view.file,
);
}
/**
* Creates an SVG image from the ExcalidrawAutomate elements and the template provided.
* @param {string} [templatePath] - The template path to use for the SVG.
@@ -1849,7 +1914,7 @@ export class ExcalidrawAutomate {
*/
async addLaTex(topX: number, topY: number, tex: string): Promise<string> {
const id = nanoid();
const image = await tex2dataURL(tex, 4, this.plugin.app);
const image = await tex2dataURL(tex, 4, this.plugin);
if (!image) {
return null;
}
@@ -1891,7 +1956,7 @@ export class ExcalidrawAutomate {
created: number;
size: { height: number; width: number };
}> {
return await tex2dataURL(tex,scale, this.plugin.app);
return await tex2dataURL(tex,scale, this.plugin);
};
/**

View File

@@ -1462,7 +1462,7 @@ export class ExcalidrawData {
: "";
if (this.equations.size > 0) {
for (const key of this.equations.keys()) {
outString += `${key}: $$${this.equations.get(key).latex}$$\n\n`;
outString += `${key}: $$${this.equations.get(key).latex.trim()}$$\n\n`;
}
}
if (this.files.size > 0) {

View File

@@ -3,7 +3,7 @@ import { DataURL } from "@zsviczian/excalidraw/types/excalidraw/types";
import ExcalidrawView from "../view/ExcalidrawView";
import { FileData, MimeType } from "./EmbeddedFileLoader";
import { FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { App } from "obsidian";
import ExcalidrawPlugin from "src/core/main";
declare const loadMathjaxToSVG: Function;
let mathjaxLoaded = false;
@@ -52,7 +52,7 @@ export const updateEquation = async (
export async function tex2dataURL(
tex: string,
scale: number = 4,
app: App,
plugin: ExcalidrawPlugin,
): Promise<{
mimeType: MimeType;
fileId: FileId;
@@ -61,7 +61,7 @@ export async function tex2dataURL(
size: { height: number; width: number };
}> {
await loadMathJax();
return tex2dataURLExternal(tex, scale, app);
return tex2dataURLExternal(tex, scale, plugin);
}
export const clearMathJaxVariables = () => {

View File

@@ -17,4 +17,11 @@ export enum PreviewImageType {
PNG = "PNG",
SVGIMG = "SVGIMG",
SVG = "SVG"
}
export interface FrameRenderingOptions {
enabled: boolean;
name: boolean;
outline: boolean;
clip: boolean;
}

View File

@@ -1,7 +1,7 @@
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { DEVICE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants";
import { getParentOfClass } from "./obsidianUtils";
import { App, TFile, WorkspaceLeaf } from "obsidian";
import { App, Notice, TFile, WorkspaceLeaf } from "obsidian";
import { getLinkParts } from "./utils";
import ExcalidrawView from "src/view/ExcalidrawView";
@@ -62,8 +62,12 @@ export function setFileToLocalGraph(app: App, file: TFile) {
app.workspace.iterateAllLeaves((l) => {
if (l.view?.getViewType() === "localgraph") lgv = l.view;
});
if (lgv) {
//@ts-ignore
lgv.loadFile(file);
try {
if (lgv) {
//@ts-ignore
lgv.loadFile(file);
}
} catch (e) {
console.error(e);
}
}

View File

@@ -4,7 +4,16 @@ import { t } from 'src/lang/helpers';
const DPI = 96;
export type PDFPageAlignment = "center" | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
export type PDFPageAlignment =
| "center"
| "top-left"
| "top-center"
| "top-right"
| "bottom-left"
| "bottom-center"
| "bottom-right"
| "center-left"
| "center-right";
export type PDFPageMarginString = "none" | "tiny" | "normal";
export interface PDFExportScale {
@@ -33,27 +42,30 @@ export interface PageDimensions {
export type PageOrientation = "portrait" | "landscape";
// All dimensions in points (pt)
// All dimensions in pixels (pt)
export const STANDARD_PAGE_SIZES = {
"A0": { width: 2383.94, height: 3370.39 },
"A1": { width: 1683.78, height: 2383.94 },
"A2": { width: 1190.55, height: 1683.78 },
"A3": { width: 841.89, height: 1190.55 },
"A4": { width: 595.28, height: 841.89 },
"A5": { width: 419.53, height: 595.28 },
"Letter": { width: 612, height: 792 },
"Legal": { width: 612, height: 1008 },
"Tabloid": { width: 792, height: 1224 },
A0: { width: 3179.52, height: 4494.96 }, // 33.11 × 46.81 inches
A1: { width: 2245.76, height: 3179.52 }, // 23.39 × 33.11 inches
A2: { width: 1587.76, height: 2245.76 }, // 16.54 × 23.39 inches
A3: { width: 1122.56, height: 1587.76 }, // 11.69 × 16.54 inches
A4: { width: 794.56, height: 1122.56 }, // 8.27 × 11.69 inches
A5: { width: 559.37, height: 794.56 }, // 5.83 × 8.27 inches
A6: { width: 397.28, height: 559.37 }, // 4.13 × 5.83 inches
Legal: { width: 816, height: 1344 }, // 8.5 × 14 inches
Letter: { width: 816, height: 1056 }, // 8.5 × 11 inches
Tabloid: { width: 1056, height: 1632 }, // 11 × 17 inches
Ledger: { width: 1632, height: 1056 } // 17 × 11 inches
} as const;
export type PageSize = keyof typeof STANDARD_PAGE_SIZES;
//margins are in pixels
export function getMarginValue(margin:PDFPageMarginString): PDFMargin {
switch(margin) {
case "none": return { left: 0, right: 0, top: 0, bottom: 0 };
case "tiny": return { left: 5, right: 5, top: 5, bottom: 5 };
case "normal": return { left: 25, right: 25, top: 25, bottom: 25 };
default: return { left: 25, right: 25, top: 25, bottom: 25 };
case "tiny": return { left: 10, right: 10, top: 10, bottom: 10 };
case "normal": return { left: 60, right: 60, top: 60, bottom: 60 };
default: return { left: 60, right: 60, top: 60, bottom: 60 };
}
}
@@ -200,6 +212,7 @@ async function printPdf(
}
function calculateDimensions(
svg: SVGSVGElement,
svgWidth: number,
svgHeight: number,
pageDim: PageDimensions,
@@ -216,6 +229,9 @@ function calculateDimensions(
}[],
pages: number
} {
const viewBox = svg.getAttribute('viewBox')?.split(' ').map(Number) || [0, 0, svgWidth, svgHeight];
const [viewBoxX, viewBoxY] = viewBox;
const availableWidth = pageDim.width - margin.left - margin.right;
const availableHeight = pageDim.height - margin.top - margin.bottom;
@@ -259,7 +275,7 @@ function calculateDimensions(
return {
tiles: [{
viewBox: `0 0 ${svgWidth} ${svgHeight}`,
viewBox: `${viewBoxX} ${viewBoxY} ${svgWidth} ${svgHeight}`,
width: finalWidth,
height: finalHeight,
x: position.x,
@@ -270,35 +286,98 @@ function calculateDimensions(
}
// Content needs to be tiled
const tiles = [];
const cols = Math.ceil(finalWidth / availableWidth);
const rows = Math.ceil(finalHeight / availableHeight);
// Calculate total available space considering all margins
const totalAvailableWidth = cols * availableWidth;
const totalAvailableHeight = rows * availableHeight;
// Calculate global position in the total available space
const globalPosition = calculatePosition(
finalWidth,
finalHeight,
totalAvailableWidth,
totalAvailableHeight,
{
left: 0,
right: 0,
top: 0,
bottom: 0
},
alignment
);
const tiles = [];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const tileX = (col * availableWidth) / (scale.zoom || 1);
const tileY = (row * availableHeight) / (scale.zoom || 1);
const tileWidth = Math.min(svgWidth - tileX, availableWidth / (scale.zoom || 1));
const tileHeight = Math.min(svgHeight - tileY, availableHeight / (scale.zoom || 1));
const scaledTileWidth = tileWidth * (scale.zoom || 1);
const scaledTileHeight = tileHeight * (scale.zoom || 1);
// Calculate where this tile intersects with the image in global space
const tileGlobalX = col * availableWidth;
const tileGlobalY = row * availableHeight;
// Calculate the intersection of the tile with the image
const intersectX = Math.max(tileGlobalX, globalPosition.x);
const intersectY = Math.max(tileGlobalY, globalPosition.y);
const intersectRight = Math.min(tileGlobalX + availableWidth, globalPosition.x + finalWidth);
const intersectBottom = Math.min(tileGlobalY + availableHeight, globalPosition.y + finalHeight);
// Calculate position for each tile
const position = calculatePosition(
scaledTileWidth,
scaledTileHeight,
pageDim.width,
pageDim.height,
margin,
alignment
);
// Calculate actual tile dimensions
const scaledTileWidth = Math.max(0, intersectRight - intersectX);
const scaledTileHeight = Math.max(0, intersectBottom - intersectY);
if (scaledTileWidth <= 0 || scaledTileHeight <= 0) continue;
// Calculate viewBox coordinates
const tileX = (intersectX - globalPosition.x) / (scale.zoom || 1);
const tileY = (intersectY - globalPosition.y) / (scale.zoom || 1);
const tileWidth = scaledTileWidth / (scale.zoom || 1);
const tileHeight = scaledTileHeight / (scale.zoom || 1);
let x = margin.left;
let y = margin.top;
// Handle horizontal positioning
const widthRatio = scaledTileWidth / availableWidth;
if (widthRatio >= 0.99 && widthRatio <= 1.01) {
x = margin.left;
} else {
if (alignment === "center" || alignment === "top-center" || alignment === "bottom-center") {
if(col === 0) {
x = margin.left + (availableWidth - scaledTileWidth);
} else {
x = margin.left;
}
} else if (alignment.endsWith('right')) {
x = pageDim.width - margin.right - scaledTileWidth;
} else {
x = margin.left;
}
}
// Handle vertical positioning
const heightRatio = scaledTileHeight / availableHeight;
if (heightRatio >= 0.99 && heightRatio <= 1.01) {
y = margin.top;
} else {
if (alignment === "center" || alignment === "center-left" || alignment === "center-right") {
if(row === 0) {
y = margin.top + (availableHeight - scaledTileHeight);
} else {
y = margin.top;
}
} else if (alignment.startsWith('bottom')) {
y = pageDim.height - margin.bottom - scaledTileHeight;
} else {
y = margin.top;
}
}
tiles.push({
viewBox: `${tileX} ${tileY} ${tileWidth} ${tileHeight}`,
viewBox: `${tileX + viewBoxX} ${tileY + viewBoxY} ${tileWidth} ${tileHeight}`,
width: scaledTileWidth,
height: scaledTileHeight,
x: position.x,
y: position.y
x: x,
y: y
});
}
}
@@ -321,14 +400,14 @@ function calculatePosition(
let y = margin.top;
// Handle horizontal alignment
if (alignment.includes('center')) {
if (alignment === "center" || alignment === "top-center" || alignment === "bottom-center") {
x = margin.left + (availableWidth - svgWidth) / 2;
} else if (alignment.includes('right')) {
} else if (alignment.endsWith('right')) {
x = margin.left + availableWidth - svgWidth;
}
// Handle vertical alignment
if (alignment.startsWith('center')) {
if (alignment === "center" || alignment === "center-left" || alignment === "center-right") {
y = margin.top + (availableHeight - svgHeight) / 2;
} else if (alignment.startsWith('bottom')) {
y = margin.top + availableHeight - svgHeight;
@@ -361,12 +440,13 @@ export async function exportToPDF({
allPagesDiv.style.width = "100%";
allPagesDiv.style.height = "fit-content";
let j = 1;
let j = 0;
for (const svg of SVG) {
const svgWidth = parseFloat(svg.getAttribute('width') || '0');
const svgHeight = parseFloat(svg.getAttribute('height') || '0');
const {tiles} = calculateDimensions(
svg,
svgWidth,
svgHeight,
pageProps.dimensions,
@@ -375,7 +455,7 @@ export async function exportToPDF({
pageProps.alignment
);
let i = 1;
let i = 0;
for (const tile of tiles) {
const pageDiv = createDiv();
pageDiv.style.width = `${width}px`;
@@ -389,9 +469,9 @@ export async function exportToPDF({
clonedSVG.setAttribute('viewBox', tile.viewBox);
clonedSVG.style.width = `${tile.width}px`;
clonedSVG.style.height = `${tile.height}px`;
clonedSVG.style.position = 'relative';
clonedSVG.style.position = 'absolute';
clonedSVG.style.left = `${tile.x}px`;
clonedSVG.style.top = `${tile.y}px`;
clonedSVG.style.top = `${tile.y + (i+j)*height}px`;
pageDiv.appendChild(clonedSVG);
allPagesDiv.appendChild(pageDiv);

View File

@@ -307,7 +307,7 @@ export async function getSVG (
: {},
},
files: scene.files,
exportPadding: exportSettings.frameRendering ? 0 : padding,
exportPadding: exportSettings.frameRendering?.enabled ? 0 : padding,
exportingFrame: null,
renderEmbeddables: true,
skipInliningFonts: exportSettings.skipInliningFonts,
@@ -365,7 +365,7 @@ export async function getPNG (
: {},
},
files: filterFiles(scene.files),
exportPadding: exportSettings.frameRendering ? 0 : padding,
exportPadding: exportSettings.frameRendering?.enabled ? 0 : padding,
mimeType: "image/png",
getDimensions: (width: number, height: number) => ({
width: width * scale,

View File

@@ -153,6 +153,7 @@ import { DropManager } from "./managers/DropManager";
import { ImageInfo } from "src/types/excalidrawAutomateTypes";
import { exportToPDF, getMarginValue, getPageDimensions, PageOrientation, PageSize } from "src/utils/exportUtils";
import { create } from "domain";
import { FrameRenderingOptions } from "src/types/utilTypes";
const EMBEDDABLE_SEMAPHORE_TIMEOUT = 2000;
const PREVENT_RELOAD_TIMEOUT = 2000;
@@ -186,12 +187,7 @@ export interface ExportSettings {
withBackground: boolean;
withTheme: boolean;
isMask: boolean;
frameRendering?: { //optional, overrides relevant appState settings for rendering the frame
enabled: boolean;
name: boolean;
outline: boolean;
clip: boolean;
};
frameRendering?: FrameRenderingOptions; //optional, overrides relevant appState settings for rendering the frame
skipInliningFonts?: boolean;
}
@@ -475,36 +471,75 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
);
}
public getViewExportTheme(theme?:string):string {
if(theme) return theme;
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
}
const ed = this.exportDialog;
return ed ? ed.theme : getExportTheme(this.plugin, this.file, this.excalidrawAPI.getAppState().theme)
}
public getViewExportEmbedScene(embedScene?:boolean):boolean {
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
}
const ed = this.exportDialog;
return typeof embedScene === "undefined"
? (ed ? ed.embedScene : false)
: embedScene;
}
public getViewExportPadding(padding?: number): number {
if(typeof padding !== "undefined") return padding;
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
}
const ed = this.exportDialog;
return ed ? ed.padding : getExportPadding(this.plugin, this.file)
}
public getViewExportScale(scale?: number): number {
if(typeof scale !== "undefined") return scale;
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
}
const ed = this.exportDialog;
return ed ? ed.scale : getPNGScale(this.plugin, this.file);
}
public getViewExportWithBackground(withBackground?:boolean) {
if(typeof withBackground !== "undefined") return withBackground;
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
}
const ed = this.exportDialog;
return ed ? !ed.transparent : getWithBackground(this.plugin, this.file)
}
public async svg(scene: any, theme?:string, embedScene?: boolean, embedFont: boolean = false): Promise<SVGSVGElement> {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.svg, "ExcalidrawView.svg", scene, theme, embedScene);
const ed = this.exportDialog;
const exportSettings: ExportSettings = {
withBackground: ed ? !ed.transparent : getWithBackground(this.plugin, this.file),
withBackground: this.getViewExportWithBackground(),
withTheme: true,
isMask: isMaskFile(this.plugin, this.file),
skipInliningFonts: !embedFont,
};
if(typeof embedScene === "undefined") {
embedScene = shouldEmbedScene(this.plugin, this.file);
}
return await getSVG(
{
...scene,
...{
appState: {
...scene.appState,
theme: theme ?? (ed ? ed.theme : getExportTheme(this.plugin, this.file, scene.appState.theme)),
exportEmbedScene: typeof embedScene === "undefined"
? (ed ? ed.embedScene : false)
: embedScene,
theme: this.getViewExportTheme(theme),
exportEmbedScene: this.getViewExportEmbedScene(embedScene),
},
},
},
exportSettings,
ed ? ed.padding : getExportPadding(this.plugin, this.file),
this.getViewExportPadding(),
this.file,
);
}
@@ -567,7 +602,6 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
}
public async exportPDF(
toVault: boolean,
selectedOnly?: boolean,
pageSize: PageSize = "A4",
orientation: PageOrientation = "portrait"
@@ -605,34 +639,27 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
public async png(scene: any, theme?:string, embedScene?: boolean): Promise<Blob> {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.png, "ExcalidrawView.png", scene, theme, embedScene);
const ed = this.exportDialog;
const exportSettings: ExportSettings = {
withBackground: ed ? !ed.transparent : getWithBackground(this.plugin, this.file),
withBackground: this.getViewExportWithBackground(),
withTheme: true,
isMask: isMaskFile(this.plugin, this.file),
};
if(typeof embedScene === "undefined") {
embedScene = shouldEmbedScene(this.plugin, this.file);
}
return await getPNG(
{
...scene,
...{
appState: {
...scene.appState,
theme: theme ?? (ed ? ed.theme : getExportTheme(this.plugin, this.file, scene.appState.theme)),
exportEmbedScene: typeof embedScene === "undefined"
? (ed ? ed.embedScene : false)
: embedScene,
theme: this.getViewExportTheme(theme),
exportEmbedScene: this.getViewExportEmbedScene(embedScene),
},
},
},
exportSettings,
ed ? ed.padding : getExportPadding(this.plugin, this.file),
ed ? ed.scale : getPNGScale(this.plugin, this.file),
this.getViewExportPadding(),
this.getViewExportScale(),
);
}
@@ -3095,7 +3122,6 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
}
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
this.exportDialog.createForm();
}
this.exportDialog.open();
})
@@ -4892,7 +4918,6 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
private actionOpenExportImageDialog() {
if(!this.exportDialog) {
this.exportDialog = new ExportDialog(this.plugin, this,this.file);
this.exportDialog.createForm();
}
this.exportDialog.open();
}

View File

@@ -342,7 +342,9 @@ label.color-input-container > input {
overflow-y: auto;
}
.excalidraw .panelColumn {
.excalidraw .selected-shape-actions .panelColumn,
.excalidraw .App-mobile-menu .panelColumn
{
max-height: 70vh;
overflow-y: auto;
}
@@ -388,11 +390,14 @@ div.excalidraw-draginfo {
position: absolute !important;
}
/*Arrow Picker Popover Overflow*/
/*
.excalidraw .selected-shape-actions .Island.App-menu__left,
.excalidraw .selected-shape-actions .Island.App-menu__left .panelColumn,
.excalidraw .Island .App-mobile-menu,
.excalidraw .Island.App-menu__left {
/*Arrow Picker Popover Overflow*/
.excalidraw .Island .App-mobile-menu .panelColumn {
overflow: visible;
}
}*/
.excalidraw__embeddable-container .view-header {
display: none !important;
@@ -712,4 +717,21 @@ textarea.excalidraw-wysiwyg, .excalidraw input {
.excalidraw-release .nav-button.is-active {
border-bottom: 2px solid var(--interactive-accent);
margin-bottom: -2px;
}
.excalidraw .picker-content {
grid-gap: 0.2rem !important;
}
.excalidraw .picker-content button.picker-option{
width: 1.85rem !important;
height: 1.85rem !important;
}
.excalidraw .picker {
padding: 0.2rem !important;
}
.excalidraw .context-menu {
height: fit-content;
}