diff --git a/manifest-beta.json b/manifest-beta.json index 8fa937f..e896368 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "2.5.2", + "version": "2.5.3-beta-1", "minAppVersion": "1.1.6", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/package.json b/package.json index 1357e3f..c9c7248 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "license": "MIT", "dependencies": { "@popperjs/core": "^2.11.8", - "@zsviczian/excalidraw": "0.17.1-obsidian-57", + "@zsviczian/excalidraw": "0.17.6-2", "chroma-js": "^2.4.2", "clsx": "^2.0.0", "@zsviczian/colormaster": "^1.2.2", diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index f1f0855..748ee08 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -93,6 +93,7 @@ import { EXCALIDRAW_AUTOMATE_INFO, EXCALIDRAW_SCRIPTENGINE_INFO } from "./dialog import { addBackOfTheNoteCard, getFrameBasedOnFrameNameOrId } from "./utils/ExcalidrawViewUtils"; import { log } from "./utils/DebugHelper"; import { ExcalidrawLib } from "./ExcalidrawLib"; +import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types"; extendPlugins([ HarmonyPlugin, @@ -1402,8 +1403,8 @@ export class ExcalidrawAutomate { ): string { const box = getLineBox(points); id = id ?? nanoid(); - const startPoint = points[0]; - const endPoint = points[points.length - 1]; + const startPoint = points[0] as GlobalPoint; + const endPoint = points[points.length - 1] as GlobalPoint; this.elementsDict[id] = { points: normalizeLinePoints(points), lastCommittedPoint: null, @@ -1693,8 +1694,8 @@ export class ExcalidrawAutomate { if (!connectionA) { const intersect = intersectElementWithLine( elA, - [bCenterX, bCenterY], - [aCenterX, aCenterY], + [bCenterX, bCenterY] as GlobalPoint, + [aCenterX, aCenterY] as GlobalPoint, GAP, ); if (intersect.length === 0) { @@ -1707,8 +1708,8 @@ export class ExcalidrawAutomate { if (!connectionB) { const intersect = intersectElementWithLine( elB, - [aCenterX, aCenterY], - [bCenterX, bCenterY], + [aCenterX, aCenterY] as GlobalPoint, + [bCenterX, bCenterY] as GlobalPoint, GAP, ); if (intersect.length === 0) { @@ -2421,7 +2422,12 @@ export class ExcalidrawAutomate { b: readonly [number, number], gap?: number, ): Point[] { - return intersectElementWithLine(element, a, b, gap); + return intersectElementWithLine( + element, + a as GlobalPoint, + b as GlobalPoint, + gap + ); }; /** @@ -2878,11 +2884,11 @@ function getFontFamily(id: number):string { } export async function initFonts():Promise { - await excalidrawLib.registerFontsInCSS(); + /*await excalidrawLib.registerFontsInCSS(); const fonts = excalidrawLib.getFontFamilies(); for(let i=0;iel.isDeleted); this.scene.elements = this.scene.elements.filter((el:ExcalidrawElement)=>!el.isDeleted); + + const timer = window.setTimeout(()=>{ + const notice = new Notice(t("FONT_LOAD_SLOW"),15000); + notice.noticeEl.oncontextmenu = () => { + displayFontMessage(this.app); + } + },2000); + await loadSceneFonts(this.scene.elements); + clearTimeout(timer); if (!this.scene.files) { this.scene.files = {}; //loading legacy scenes that do not yet have the files attribute. diff --git a/src/ExcalidrawLib.d.ts b/src/ExcalidrawLib.d.ts index 95c9183..c193509 100644 --- a/src/ExcalidrawLib.d.ts +++ b/src/ExcalidrawLib.d.ts @@ -3,8 +3,9 @@ import { ImportedDataState } from "@zsviczian/excalidraw/types/excalidraw/data/t import { BoundingBox } from "@zsviczian/excalidraw/types/excalidraw/element/bounds"; import { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawFrameLikeElement, ExcalidrawTextContainer, ExcalidrawTextElement, FontFamilyValues, FontString, NonDeleted, NonDeletedExcalidrawElement, Theme } from "@zsviczian/excalidraw/types/excalidraw/element/types"; import { FontMetadata } from "@zsviczian/excalidraw/types/excalidraw/fonts/metadata"; -import { AppState, BinaryFiles, DataURL, GenerateDiagramToCode, Point, Zoom } from "@zsviczian/excalidraw/types/excalidraw/types"; +import { AppState, BinaryFiles, DataURL, GenerateDiagramToCode, Zoom } from "@zsviczian/excalidraw/types/excalidraw/types"; import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types"; +import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types"; type EmbeddedLink = | ({ @@ -75,16 +76,16 @@ declare namespace ExcalidrawLib { function determineFocusDistance( element: ExcalidrawBindableElement, - a: Point, - b: Point, + a: GlobalPoint, + b: GlobalPoint, ): number; function intersectElementWithLine( element: ExcalidrawBindableElement, - a: Point, - b: Point, + a: GlobalPoint, + b: GlobalPoint, gap?: number, - ): Point[]; + ): GlobalPoint[]; function getCommonBoundingBox( elements: ExcalidrawElement[] | readonly NonDeleted[], @@ -186,5 +187,6 @@ declare namespace ExcalidrawLib { separator?: string, ): string; function safelyParseJSON (json: string): Record | null; + function loadSceneFonts(elements: NonDeletedExcalidrawElement[]): Promise; } diff --git a/src/constants/constants.ts b/src/constants/constants.ts index df28820..a55a32d 100644 --- a/src/constants/constants.ts +++ b/src/constants/constants.ts @@ -103,6 +103,7 @@ export const { getContainerElement, refreshTextDimensions, getCSSFontDefinition, + loadSceneFonts, } = excalidrawLib; export const FONTS_STYLE_ID = "excalidraw-custom-fonts"; diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 6917334..91f1239 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -187,7 +187,7 @@ export default { BASIC_HEAD: "Basic", BASIC_DESC: `In the "Basic" settings, you can configure options such as displaying release notes after updates, receiving plugin update notifications, setting the default location for new drawings, specifying the Excalidraw folder for embedding drawings into active documents, defining an Excalidraw template file, and designating an Excalidraw Automate script folder for managing automation scripts.`, - FOLDER_NAME: "Excalidraw folder", + FOLDER_NAME: "Excalidraw folder (CAsE sEnsITive!)", FOLDER_DESC: "Default location for new drawings. If empty, drawings will be created in the Vault root.", CROP_PREFIX_NAME: "Crop file prefix", @@ -201,10 +201,10 @@ export default { ANNOTATE_PRESERVE_SIZE_NAME: "Preserve image size when annotating", ANNOTATE_PRESERVE_SIZE_DESC: "When annotating an image in markdown the replacment image link will include the width of the original image.", - CROP_FOLDER_NAME: "Crop file folder", + CROP_FOLDER_NAME: "Crop file folder (CaSE senSItive!)", CROP_FOLDER_DESC: "Default location for new drawings created when cropping an image. If empty, drawings will be created following the Vault attachments settings.", - ANNOTATE_FOLDER_NAME: "Image annotation file folder", + ANNOTATE_FOLDER_NAME: "Image annotation file folder (CaSe SeNSitIVe!)", ANNOTATE_FOLDER_DESC: "Default location for new drawings created when annotating an image. If empty, drawings will be created following the Vault attachments settings.", FOLDER_EMBED_NAME: @@ -213,7 +213,7 @@ export default { "Define which folder to place the newly inserted drawing into " + "when using the command palette action: 'Create a new drawing and embed into active document'.
" + "Toggle ON: Use Excalidraw folder
Toggle OFF: Use the attachments folder defined in Obsidian settings.", - TEMPLATE_NAME: "Excalidraw template file or folder", + TEMPLATE_NAME: "Excalidraw template file or folder (caSe SenSiTive!)", TEMPLATE_DESC: "Full filepath or folderpath to the Excalidraw template.
" + "Template File:E.g.: If your template is in the default Excalidraw folder and its name is " + @@ -229,6 +229,15 @@ export default { "You can access your scripts from Excalidraw via the Obsidian Command Palette. Assign " + "hotkeys to your favorite scripts just like to any other Obsidian command. " + "The folder may not be the root folder of your Vault. ", + ASSETS_FOLDER_NAME: "Local Font Assets Folder (cAsE sENsiTIvE!)", + ASSETS_FOLDER_DESC: `Since version 2.5.3, following the implementation of CJK font support, Excalidraw downloads fonts from the internet. + If you prefer to keep Excalidraw fully local, allowing it to work without internet access, or if your internet connection is slow + and you want to improve performance, you can download the necessary + font assets from GitHub. + After downloading, unzip the contents into a folder within your Vault.
+ You can specify the location of that folder here. For example, you may choose to place it under Excalidraw/FontAssets.

+ Important: Do not set this to the Vault root! Ensure that no other files are placed in this folder.

+ Note: If you're using Obsidian Sync and want to synchronize these font files across your devices, ensure that Obsidian Sync is set to synchronize "All other file types".`, AI_HEAD: "AI Settings - Experimental", AI_DESC: `In the "AI" settings, you can configure options for using OpenAI's GPT API. ` + `While the OpenAI API is in beta, its use is strictly limited — as such we require you use your own API key. ` + @@ -816,6 +825,36 @@ FILENAME_HEAD: "Filename", //ExcalidrawData.ts LOAD_FROM_BACKUP: "Excalidraw file was corrupted. Loading from backup file.", + FONT_LOAD_SLOW: "Loading Fonts...\n\n This is taking longer than expected. If this delay occurs regulary then you may download the fonts locally to your Vault. \n\n" + + "(click=dismiss, right-click=Info)", + FONT_INFO_TITLE: "Starting v2.5.3 fonts load from the Internet", + FONT_INFO_DETAILED: ` +

+ To improve Obsidian's startup time and manage the large CJK font family, + I've moved the fonts out of the plugin's main.js. Starting with version 2.5.3, + fonts will be loaded from the internet. This typically shouldn't cause issues as Obsidian caches + these files after first use. +

+

+ If you prefer to keep Obsidian 100% local or experience performance issues, you can download the font assets. +

+

Instructions:

+
    +
  1. Download the fonts from GitHub.
  2. +
  3. Unzip and copy files into a Vault folder (default: Excalidraw/FontAssets; folder names are cAse-senSITive).
  4. +
  5. DO NOT set this folder to the Vault root or mix with other local fonts.
  6. +
+

For Obsidian Sync Users:

+

+ Ensure Obsidian Sync is set to synchronize "All other file types" or download and unzip the file on all devices. +

+

Note:

+

+ If you find this process cumbersome, please submit a feature request to Obsidian.md for supporting assets in the plugin folder. + Currently, only a single main.js is supported, which leads to large files and slow startup times for complex plugins like Excalidraw. + I apologize for the inconvenience. +

+ `, //ObsidianMenu.tsx GOTO_FULLSCREEN: "Goto fullscreen mode", diff --git a/src/main.ts b/src/main.ts index 970fdb1..313768e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -313,6 +313,15 @@ export default class ExcalidrawPlugin extends Plugin { }; }*/ + public async loadFontFromFile(fontName: string): Promise { + const assetsFoler = "Fonts/"; + const file = this.app.vault.getAbstractFileByPath(assetsFoler + fontName); + if(!file || !(file instanceof TFile)) { + return; + } + return await this.app.vault.readBinary(file); + } + async onload() { initCompressionWorker(); this.loadTimestamp = Date.now(); diff --git a/src/settings.ts b/src/settings.ts index 77a88f5..88381a9 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -49,6 +49,7 @@ export interface ExcalidrawSettings { embedUseExcalidrawFolder: boolean; templateFilePath: string; scriptFolderPath: string; + fontAssetsPath: string; compress: boolean; decompressForMDView: boolean; onceOffCompressFlagReset: boolean; //used to reset compress to true in 2.2.0 @@ -220,6 +221,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = { embedUseExcalidrawFolder: false, templateFilePath: "Excalidraw/Template.excalidraw", scriptFolderPath: "Excalidraw/Scripts", + fontAssetsPath: "Excalidraw/FontAssets", compress: true, decompressForMDView: false, onceOffCompressFlagReset: false, @@ -720,6 +722,18 @@ export class ExcalidrawSettingTab extends PluginSettingTab { }), ); + new Setting(detailsEl) + .setName(t("ASSETS_FOLDER_NAME")) + .setDesc(fragWithHTML(t("ASSETS_FOLDER_DESC"))) + .addText((text) => + text + .setPlaceholder("e.g.: Excalidraw/FontAssets") + .setValue(this.plugin.settings.fontAssetsPath) + .onChange(async (value) => { + this.plugin.settings.fontAssetsPath = value; + this.applySettingsUpdate(); + }), + ); // ------------------------------------------------ // Saving @@ -2484,7 +2498,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab { d.addOption("Virgil", "Virgil"); this.app.vault .getFiles() - .filter((f) => ["ttf", "woff", "woff2", "otf"].contains(f.extension)) + .filter((f) => ["ttf", "woff", "woff2", "otf"].contains(f.extension) && !f.path.startsWith(this.plugin.settings.fontAssetsPath)) .forEach((f: TFile) => { d.addOption(f.path, f.name); }); diff --git a/src/utils/ExcalidrawViewUtils.ts b/src/utils/ExcalidrawViewUtils.ts index fbdfbe0..967b27f 100644 --- a/src/utils/ExcalidrawViewUtils.ts +++ b/src/utils/ExcalidrawViewUtils.ts @@ -1,6 +1,6 @@ import { MAX_IMAGE_SIZE, IMAGE_TYPES, ANIMATED_IMAGE_TYPES, MD_EX_SECTIONS } from "src/constants/constants"; -import { App, Notice, TFile, WorkspaceLeaf } from "obsidian"; +import { App, Modal, Notice, TFile, WorkspaceLeaf } from "obsidian"; import { ExcalidrawAutomate } from "src/ExcalidrawAutomate"; import { REGEX_LINK, REG_LINKINDEX_HYPERLINK, getExcalidrawMarkdownHeaderSection, REGEX_TAGS } from "src/ExcalidrawData"; import ExcalidrawView from "src/ExcalidrawView"; @@ -402,3 +402,19 @@ export function isTextImageTransclusion ( } return false; } + +export function displayFontMessage(app: App) { + const modal = new Modal(app); + + modal.onOpen = () => { + const contentEl = modal.contentEl; + contentEl.createEl("h2", { text: t("FONT_INFO_TITLE") }); + + const releaseNotesHTML = t("FONT_INFO_DETAILED"); + + const div = contentEl.createDiv({ cls: "release-notes" }); + div.innerHTML = releaseNotesHTML; + } + + modal.open(); +} \ No newline at end of file