mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
PDF export: HD Screen and Martch Image + disable double click text create
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@zsviczian/excalidraw": "0.18.0-8",
|
||||
"@zsviczian/excalidraw": "0.18.0-9",
|
||||
"chroma-js": "^2.4.2",
|
||||
"clsx": "^2.0.0",
|
||||
"@zsviczian/colormaster": "^1.2.2",
|
||||
|
||||
@@ -46,6 +46,7 @@ import { PDFExportSettingsComponent, PDFExportSettings } from "src/shared/Dialog
|
||||
import de from "src/lang/locale/de";
|
||||
|
||||
export interface ExcalidrawSettings {
|
||||
disableDoubleClickTextEditing: boolean;
|
||||
folder: string;
|
||||
cropFolder: string;
|
||||
annotateFolder: string;
|
||||
@@ -228,6 +229,7 @@ export interface ExcalidrawSettings {
|
||||
declare const PLUGIN_VERSION:string;
|
||||
|
||||
export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
disableDoubleClickTextEditing: false,
|
||||
folder: "Excalidraw",
|
||||
cropFolder: "",
|
||||
annotateFolder: "",
|
||||
@@ -684,6 +686,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("TOGGLE_SPLASHSCREEN"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showSplashscreen)
|
||||
.onChange((value)=> {
|
||||
this.plugin.settings.showSplashscreen = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
)
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("FOLDER_NAME"))
|
||||
.setDesc(fragWithHTML(t("FOLDER_DESC")))
|
||||
@@ -1094,6 +1107,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
cls: "excalidraw-setting-h1",
|
||||
});
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(!this.plugin.settings.disableDoubleClickTextEditing)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.disableDoubleClickTextEditing = !value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
const readingModeEl = new Setting(detailsEl)
|
||||
.setName(t("SHOW_DRAWING_OR_MD_IN_READING_MODE_NAME"))
|
||||
.setDesc(fragWithHTML(t("SHOW_DRAWING_OR_MD_IN_READING_MODE_DESC")))
|
||||
@@ -1136,17 +1160,6 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
);
|
||||
addIframe(detailsEl, "H8Njp7ZXYag",999);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("TOGGLE_SPLASHSCREEN"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showSplashscreen)
|
||||
.onChange((value)=> {
|
||||
this.plugin.settings.showSplashscreen = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
)
|
||||
|
||||
detailsEl = displayDetailsEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("HOTKEY_OVERRIDE_HEAD"),
|
||||
|
||||
@@ -371,6 +371,7 @@ FILENAME_HEAD: "Filename",
|
||||
DEFAULT_PEN_MODE_NAME: "Pen mode",
|
||||
DEFAULT_PEN_MODE_DESC:
|
||||
"Should pen mode be automatically enabled when opening Excalidraw?",
|
||||
ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME: "Enable double-click text create",
|
||||
DISABLE_DOUBLE_TAP_ERASER_NAME: "Enable double-tap eraser in pen mode",
|
||||
DISABLE_SINGLE_FINGER_PANNING_NAME: "Enable single-finger panning in pen mode",
|
||||
SHOW_PEN_MODE_FREEDRAW_CROSSHAIR_NAME: "Show (+) crosshair in pen mode",
|
||||
|
||||
@@ -43,6 +43,7 @@ export class ExportDialog extends Modal {
|
||||
public customPaperColor: string = "#ffffff";
|
||||
public alignment: PDFPageAlignment = "center";
|
||||
public margin: PDFPageMarginString = "normal";
|
||||
private scaleSetting:Setting;
|
||||
|
||||
constructor(
|
||||
private plugin: ExcalidrawPlugin,
|
||||
@@ -85,6 +86,17 @@ export class ExportDialog extends Modal {
|
||||
this.selectedOnlySetting = null;
|
||||
this.containerEl.remove();
|
||||
}
|
||||
|
||||
updateBoundingBox() {
|
||||
if(this.hasSelectedElements && this.exportSelectedOnly) {
|
||||
this.boundingBox = this.ea.getBoundingBox(this.view.getViewSelectedElements());
|
||||
} else {
|
||||
this.boundingBox = this.ea.getBoundingBox(this.ea.getViewElements());
|
||||
}
|
||||
if(this.scaleSetting) {
|
||||
this.scaleSetting.setDesc(this.size());
|
||||
}
|
||||
}
|
||||
|
||||
onOpen(): void {
|
||||
this.containerEl.classList.add("excalidraw-release");
|
||||
@@ -92,6 +104,7 @@ export class ExportDialog extends Modal {
|
||||
this.hasSelectedElements = this.view.getViewSelectedElements().length > 0;
|
||||
//@ts-ignore
|
||||
this.selectedOnlySetting.setVisibility(this.hasSelectedElements);
|
||||
this.updateBoundingBox();
|
||||
}
|
||||
|
||||
async onClose() {
|
||||
@@ -167,9 +180,14 @@ export class ExportDialog extends Modal {
|
||||
this.createPDFButton();
|
||||
}
|
||||
}
|
||||
|
||||
private size ():DocumentFragment {
|
||||
const width = Math.round(this.scale*this.boundingBox.width + this.padding*2);
|
||||
const height = Math.round(this.scale*this.boundingBox.height + this.padding*2);
|
||||
return fragWithHTML(`${t("EXPORTDIALOG_SIZE_DESC")}<br>${t("EXPORTDIALOG_SCALE_VALUE")} <b>${this.scale}</b><br>${t("EXPORTDIALOG_IMAGE_SIZE")} <b>${width}x${height}</b>`);
|
||||
}
|
||||
|
||||
private createImageSettings() {
|
||||
let scaleSetting:Setting;
|
||||
let paddingSetting: Setting;
|
||||
|
||||
this.contentContainer.createEl("h1",{text: t("EXPORTDIALOG_IMAGE_SETTINGS")});
|
||||
@@ -177,12 +195,6 @@ export class ExportDialog extends Modal {
|
||||
|
||||
this.createSaveSettingsDropdown();
|
||||
|
||||
const size = ():DocumentFragment => {
|
||||
const width = Math.round(this.scale*this.boundingBox.width + this.padding*2);
|
||||
const height = Math.round(this.scale*this.boundingBox.height + this.padding*2);
|
||||
return fragWithHTML(`${t("EXPORTDIALOG_SIZE_DESC")}<br>${t("EXPORTDIALOG_SCALE_VALUE")} <b>${this.scale}</b><br>${t("EXPORTDIALOG_IMAGE_SIZE")} <b>${width}x${height}</b>`);
|
||||
}
|
||||
|
||||
const padding = ():DocumentFragment => {
|
||||
return fragWithHTML(`${t("EXPORTDIALOG_CURRENT_PADDING")} <b>${this.padding}</b>`);
|
||||
}
|
||||
@@ -196,21 +208,21 @@ export class ExportDialog extends Modal {
|
||||
.setValue(this.padding)
|
||||
.onChange(value => {
|
||||
this.padding = value;
|
||||
scaleSetting.setDesc(size());
|
||||
this.scaleSetting.setDesc(this.size());
|
||||
paddingSetting.setDesc(padding());
|
||||
})
|
||||
})
|
||||
|
||||
scaleSetting = new Setting(this.contentContainer)
|
||||
this.scaleSetting = new Setting(this.contentContainer)
|
||||
.setName(t("EXPORTDIALOG_SCALE"))
|
||||
.setDesc(size())
|
||||
.setDesc(this.size())
|
||||
.addSlider(slider =>
|
||||
slider
|
||||
.setLimits(0.2,7,0.1)
|
||||
.setValue(this.scale)
|
||||
.onChange(value => {
|
||||
this.scale = value;
|
||||
scaleSetting.setDesc(size());
|
||||
this.scaleSetting.setDesc(this.size());
|
||||
})
|
||||
)
|
||||
|
||||
@@ -247,6 +259,7 @@ export class ExportDialog extends Modal {
|
||||
.setValue(this.exportSelectedOnly?"selected":"all")
|
||||
.onChange(value => {
|
||||
this.exportSelectedOnly = value === "selected";
|
||||
this.updateBoundingBox();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export class InsertPDFModal extends Modal {
|
||||
this.setImageSizeMessage = null;
|
||||
}
|
||||
|
||||
private async getPageDimensions (pdfDoc: any) {
|
||||
private async getPDFPageDimensions (pdfDoc: any) {
|
||||
try {
|
||||
const scale = this.plugin.settings.pdfScale;
|
||||
const canvas = createEl("canvas");
|
||||
@@ -197,7 +197,7 @@ export class InsertPDFModal extends Modal {
|
||||
rangeOnChange(`1-${numPages}`);
|
||||
importButtonMessages();
|
||||
numPagesMessages();
|
||||
this.getPageDimensions(this.pdfDoc);
|
||||
this.getPDFPageDimensions(this.pdfDoc);
|
||||
} else {
|
||||
importButton.setDisabled(true);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ I build this plugin in my free time, as a labor of love. Curious about the philo
|
||||
|
||||
## New
|
||||
- Expose parameter in plugin settings to disable AI functionality [#2325](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2325)
|
||||
- Enable double-click text editing option in Excalidraw appearance and behavior (based on request on Discord)
|
||||
- Added two new PDF export sizes: "Match image", "HD Screen".
|
||||
|
||||
## Fixed in the plugin
|
||||
- Scaling multiple embeddables at once did not work. [#2276](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2276)
|
||||
|
||||
@@ -21,6 +21,10 @@ export class PDFExportSettingsComponent {
|
||||
if (!update) this.update = () => {};
|
||||
}
|
||||
|
||||
isOrientationAndTilingVisible() {
|
||||
return !(this.settings.pageSize === "HD Screen" || this.settings.pageSize === "MATCH IMAGE");
|
||||
}
|
||||
|
||||
render() {
|
||||
const pageSizeOptions: Record<string, string> = Object.keys(STANDARD_PAGE_SIZES)
|
||||
.reduce((acc, key) => ({
|
||||
@@ -28,6 +32,8 @@ export class PDFExportSettingsComponent {
|
||||
[key]: key
|
||||
}), {});
|
||||
|
||||
let div: HTMLDivElement;
|
||||
|
||||
new Setting(this.contentEl)
|
||||
.setName(t("EXPORTDIALOG_PAGE_SIZE"))
|
||||
.addDropdown(dropdown =>
|
||||
@@ -36,11 +42,15 @@ export class PDFExportSettingsComponent {
|
||||
.setValue(this.settings.pageSize)
|
||||
.onChange(value => {
|
||||
this.settings.pageSize = value as PageSize;
|
||||
div.style.display = this.isOrientationAndTilingVisible() ? "block" : "none";
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(this.contentEl)
|
||||
div = this.contentEl.createDiv();
|
||||
div.style.display = this.isOrientationAndTilingVisible() ? "block" : "none";
|
||||
|
||||
new Setting(div)
|
||||
.setName(t("EXPORTDIALOG_PAGE_ORIENTATION"))
|
||||
.addDropdown(dropdown =>
|
||||
dropdown
|
||||
@@ -55,7 +65,7 @@ export class PDFExportSettingsComponent {
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(this.contentEl)
|
||||
new Setting(div)
|
||||
.setName(t("EXPORTDIALOG_PDF_FIT_TO_PAGE"))
|
||||
.addDropdown(dropdown =>
|
||||
dropdown
|
||||
|
||||
@@ -54,7 +54,9 @@ export const STANDARD_PAGE_SIZES = {
|
||||
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
|
||||
Ledger: { width: 1632, height: 1056 }, // 17 × 11 inches
|
||||
"HD Screen": { width: 1920, height: 1080 },// 16:9 aspect ratio
|
||||
"MATCH IMAGE": { width: 0, height: 0 }, // 0 means use the current screen size
|
||||
} as const;
|
||||
|
||||
export type PageSize = keyof typeof STANDARD_PAGE_SIZES;
|
||||
@@ -69,9 +71,15 @@ export function getMarginValue(margin:PDFPageMarginString): PDFMargin {
|
||||
}
|
||||
}
|
||||
|
||||
export function getPageDimensions(pageSize: PageSize, orientation: PageOrientation): PageDimensions {
|
||||
const dimensions = STANDARD_PAGE_SIZES[pageSize];
|
||||
return orientation === "portrait"
|
||||
export function getPageDimensions(pageSize: PageSize, orientation: PageOrientation, dims?: {width: number, height: number}): PageDimensions {
|
||||
let dimensions:{width: number, height: number};
|
||||
dimensions = STANDARD_PAGE_SIZES[pageSize];
|
||||
|
||||
if (dims && dimensions.width === 0 && dimensions.height === 0) {
|
||||
dimensions = { width: dims.width, height: dims.height };
|
||||
}
|
||||
|
||||
return orientation === "portrait" || pageSize === "MATCH IMAGE" || pageSize === "HD Screen"
|
||||
? { width: dimensions.width, height: dimensions.height }
|
||||
: { width: dimensions.height, height: dimensions.width };
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ import {
|
||||
getExcalidrawMarkdownHeaderSection,
|
||||
} from "../shared/ExcalidrawData";
|
||||
import {
|
||||
arrayBufferToBase64,
|
||||
checkAndCreateFolder,
|
||||
createOrOverwriteFile,
|
||||
download,
|
||||
@@ -155,7 +154,6 @@ import { ImageInfo } from "src/types/excalidrawAutomateTypes";
|
||||
import { exportToPDF, getMarginValue, getPageDimensions, PageOrientation, PageSize } from "src/utils/exportUtils";
|
||||
import { FrameRenderingOptions } from "src/types/utilTypes";
|
||||
import { CaptureUpdateAction } from "src/constants/constants";
|
||||
import { FlipHorizontal } from "lucide-react";
|
||||
|
||||
const EMBEDDABLE_SEMAPHORE_TIMEOUT = 2000;
|
||||
const PREVENT_RELOAD_TIMEOUT = 2000;
|
||||
@@ -612,8 +610,10 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
return;
|
||||
}
|
||||
|
||||
const scene = this.getScene(selectedOnly);
|
||||
|
||||
const svg = await this.svg(
|
||||
this.getScene(selectedOnly),
|
||||
scene,
|
||||
undefined,
|
||||
false,
|
||||
true
|
||||
@@ -622,20 +622,26 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
|
||||
if (!svg) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const boundingBox = this.plugin.ea.getBoundingBox(scene.elements);
|
||||
const margin = getMarginValue(this.exportDialog.margin);
|
||||
const [width, height] = [boundingBox.width, boundingBox.height];
|
||||
|
||||
exportToPDF({
|
||||
SVG: [svg],
|
||||
scale: {
|
||||
zoom: this.exportDialog.scale,
|
||||
fitToPage: this.exportDialog.fitToPage
|
||||
fitToPage: pageSize === "MATCH IMAGE" || pageSize === "HD Screen"
|
||||
? 1
|
||||
: this.exportDialog.fitToPage
|
||||
},
|
||||
pageProps: {
|
||||
dimensions: getPageDimensions(pageSize, orientation),
|
||||
dimensions: getPageDimensions(pageSize, orientation, {width, height}),
|
||||
backgroundColor: this.exportDialog.getPaperColor(),
|
||||
margin: getMarginValue(this.exportDialog.margin),
|
||||
margin,
|
||||
alignment: this.exportDialog.alignment,
|
||||
},
|
||||
filename: this.file.basename,
|
||||
filename: this.file.basename+".pdf",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user