svgMarkdownMVP

This commit is contained in:
Zsolt Viczian
2021-11-26 20:20:08 +01:00
parent 94c3011435
commit f7bbe2e446
3 changed files with 70 additions and 10 deletions

View File

@@ -1,9 +1,7 @@
import { file } from "@babel/types";
import { exportToBlob } from "@zsviczian/excalidraw";
import { FileId } from "@zsviczian/excalidraw/types/element/types";
import { BinaryFileData, DataURL } from "@zsviczian/excalidraw/types/types";
import { App, Notice, TFile } from "obsidian";
import { fileid, IMAGE_TYPES } from "./constants";
import { App, MarkdownRenderer, Notice, TFile } from "obsidian";
import { CASCADIA_FONT, fileid, FRONTMATTER_KEY_FONT, IMAGE_TYPES, VIRGIL_FONT } from "./constants";
import { ExcalidrawData } from "./ExcalidrawData";
import ExcalidrawView, { ExportSettings } from "./ExcalidrawView";
import { t } from "./lang/helpers";
@@ -111,8 +109,8 @@ export class EmbeddedFilesLoader {
this.processedFiles.set(file.path,count+1);
let hasSVGwithBitmap = false;
const app = this.plugin.app;
const isExcalidrawFile = this.plugin.ea.isExcalidrawFile(file);
if (!(IMAGE_TYPES.contains(file.extension) || isExcalidrawFile)) {
const isExcalidrawFile = this.plugin.isExcalidrawFile(file);
if (!(IMAGE_TYPES.contains(file.extension) || isExcalidrawFile || file.extension==="md")) {
return null;
}
const ab = await app.vault.readBinary(file);
@@ -151,12 +149,23 @@ export class EmbeddedFilesLoader {
case "jpeg":mimeType = "image/jpeg";break;
case "jpg": mimeType = "image/jpeg";break;
case "gif": mimeType = "image/gif";break;
case "svg": mimeType = "image/svg+xml";break;
case "svg":
case "md" : mimeType = "image/svg+xml";break;
default: mimeType = "application/octet-stream";
}
}
const dataURL = excalidrawSVG ?? (file.extension==="svg" ? await getSVGData(app,file) : await getDataURL(ab,mimeType));
const size = await getImageSize(excalidrawSVG??app.vault.getResourcePath(file));
const dataURL = excalidrawSVG
?? (file.extension==="svg"
? await getSVGData(app,file)
: (file.extension==="md"
? await convertMarkdownToSVG(this.plugin,file)
: await getDataURL(ab,mimeType)
));
const size = await getImageSize(excalidrawSVG
?? (file.extension==="md"
? dataURL
: app.vault.getResourcePath(file)
));
return {
mimeType,
fileId: await generateIdFromFile(ab),
@@ -241,6 +250,55 @@ const getSVGData = async (app: App, file: TFile): Promise<DataURL> => {
return svgToBase64(svg) as DataURL;
}
const mdSVGwidth = 640;
const mdSVGmaxHeight = 800;
const convertMarkdownToSVG = async (plugin: ExcalidrawPlugin, file: TFile): Promise<DataURL> => {
const text = await plugin.app.vault.cachedRead(file);
const fileCache = plugin.app.metadataCache.getFileCache(file);
let fontName = "Virgil";
let fontBase64 = VIRGIL_FONT;
if (fileCache?.frontmatter && fileCache.frontmatter[FRONTMATTER_KEY_FONT]!=null) {
const font = fileCache.frontmatter[FRONTMATTER_KEY_FONT];
switch(font){
case "Virgil": fontName = "Virgil";fontBase64 = VIRGIL_FONT; break;
case "Cascadia": fontName = "Cascadia";fontBase64 = CASCADIA_FONT; break;
default:
const f = plugin.app.metadataCache.getFirstLinkpathDest(font,file.path);
if(f) {
const ab = await plugin.app.vault.readBinary(f);
const mimeType="application/font-woff";
fontName = f.basename;
fontBase64 = ` @font-face {font-family: "${fontName}";src: url("${await getDataURL(ab,mimeType)}") format("${f.extension}");}`;
}
}
}
const span = createEl("span");
span.setAttribute("xmlns","http://www.w3.org/1999/xhtml");
span.setAttribute("style","font-family: "+fontName+";");
await MarkdownRenderer.renderMarkdown(text,span,file.path,plugin);
span.querySelectorAll(":scope > *[class^='frontmatter']").forEach((el)=>span.removeChild(el));
const xml = new XMLSerializer().serializeToString(span);
let svgStyle = ' width="'+mdSVGwidth+'px" height="100%"';
let foreignObjectStyle = ' width="'+mdSVGwidth+'px" height="100%"';
let svg= '<svg xmlns="http://www.w3.org/2000/svg"'+svgStyle+'><foreignObject x="0" y="0"'+foreignObjectStyle+'>' +
xml+'</foreignObject><defs><style>'+ fontBase64 +'</style></defs></svg>';
const parser = new DOMParser();
const doc = parser.parseFromString(svg,"image/svg+xml");
const svgEl = doc.firstElementChild;
const div = createDiv();
div.appendChild(svgEl);
document.body.appendChild(div);
const height = svgEl.firstElementChild.scrollHeight;
const svgHeight = height <= mdSVGmaxHeight ? height : mdSVGmaxHeight;
document.body.removeChild(div);
svgStyle = ' width="'+mdSVGwidth+'px" height="'+svgHeight+'px"';
foreignObjectStyle = ' width="'+mdSVGwidth+'px" height="'+svgHeight+'px"';
svg= '<svg xmlns="http://www.w3.org/2000/svg"'+svgStyle+'><foreignObject x="0" y="0"'+foreignObjectStyle+'>' +
xml+'</foreignObject><defs><style>'+ fontBase64 +'</style></defs></svg>';
return svgToBase64(svg) as DataURL;
}
const getDataURL = async (file: ArrayBuffer,mimeType: string): Promise<DataURL> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();

View File

@@ -348,6 +348,7 @@ export default class ExcalidrawView extends TextFileView {
this.addAction(DISK_ICON_NAME,t("FORCE_SAVE"),async (ev)=> {
await this.save(false);
this.plugin.triggerEmbedUpdates();
this.loadSceneFiles();
});
this.textIsRaw_Element = this.addAction(TEXT_DISPLAY_RAW_ICON_NAME,t("RAW"), (ev) => this.changeTextMode(TextMode.parsed));
@@ -1217,7 +1218,7 @@ export default class ExcalidrawView extends TextFileView {
if (!onDropHook("file",[draggable.file],null)) {
if(event[CTRL_OR_CMD] //.ctrlKey||event.metaKey)
&& (IMAGE_TYPES.contains(draggable.file.extension)
|| this.plugin.isExcalidrawFile(draggable.file))) {
|| draggable.file.extension==="md")) {//this.plugin.isExcalidrawFile(draggable.file)
const f = draggable.file;
const topX = currentPosition.x;
const topY = currentPosition.y;

View File

@@ -13,6 +13,7 @@ export const FRONTMATTER_KEY_CUSTOM_PREFIX = "excalidraw-link-prefix";
export const FRONTMATTER_KEY_CUSTOM_URL_PREFIX = "excalidraw-url-prefix";
export const FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS = "excalidraw-link-brackets";
export const FRONTMATTER_KEY_DEFAULT_MODE = "excalidraw-default-mode";
export const FRONTMATTER_KEY_FONT = "excalidraw-font";
export const VIEW_TYPE_EXCALIDRAW = "excalidraw";
export const ICON_NAME = "excalidraw-icon";
export const MAX_COLORS = 5;