obsidian-excalidraw-plugin icon indicating copy to clipboard operation
obsidian-excalidraw-plugin copied to clipboard

FR: Setting to allow exporting internal links as relative file paths in SVG

Open Beilinson opened this issue 1 year ago • 4 comments

Is your feature request related to a problem? Please describe. I host my diagrams with my obsidian markdown files on a static website. I do this by enabling auto-export to SVG for the excalidraw files.

Currently the auto-export and regular save methods use the getSVG() with a file obviously and as such run the updateElementLinksToObsidianLinks() method, which cause the embedded links in the final svg to try opening the markdown in obsidian, rather than according to the existing relative path that I have.

Describe the solution you'd like Add a configurable setting that allows for exporting SVG with relative links, so for example the excalidraw drawing located in excalidraw/example which links to [[docs/example]] will have href="../docs/example.md"

Describe alternatives you've considered I tried running the createSVG method on ExcalidrawAutomate, but it just exports the links directly as the original [[wikilinks]], which isn't helpful

I also tried placing the relative url directly in excalidraw, but then I don't have all the fun features of hovering and seeing a preview or even able to jump to the file by ctrl+click

Any other ideas are welcome :D

Beilinson avatar Feb 22 '24 19:02 Beilinson

This is doable. I'll add a setting for this.

zsviczian avatar Feb 24 '24 06:02 zsviczian

In 2.0.23 I created a new Excalidraw hook: onUpdateElementLinkForExportHook. Feel free to edit the link however you like. When you are done with your function, please post it here for others to see it as a reference. Also let me know if you were able to solve your need with this solution.

You can access the startup script through plugin settings here: image

You can set this like this:

/**
* If set, this callback is triggered whenever a drawing is exported to SVG.
* The string returned will replace the link in the exported SVG.
* The hook is only executed if the link is to a file internal to Obsidian
* see: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1605
*  onUpdateElementLinkForExportHook: (data: {
*    originalLink: string,
*    obsidianLink: string,
*    linkedFile: TFile | null,
*    hostFile: TFile,
*  }) => string = null;
*/
//ea.onUpdateElementLinkForExportHook = (data) => {};

zsviczian avatar Feb 25 '24 14:02 zsviczian

Amazing! I added this to my startup scripts, the fact that it's a hook actually makes it really easy to switch it to pointing to the final html static files on my jekyll site.

/**
* If set, this callback is triggered whenever a drawing is exported to SVG.
* The string returned will replace the link in the exported SVG.
* The hook is only executed if the link is to a file internal to Obsidian
* see: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1605
*  onUpdateElementLinkForExportHook: (data: {
*    originalLink: string,
*    obsidianLink: string,
*    linkedFile: TFile | null,
*    hostFile: TFile,
*  }) => string = null;
*/
const path = require('path').posix;

ea.onUpdateElementLinkForExportHook = (data) => {
  if (!data.linkedFile?.path) return originalLink;

  return path.relative(data.hostFile.parent.path, data.linkedFile.path).replace('md', 'html');
};

Beilinson avatar Feb 26 '24 17:02 Beilinson

Here is my hook in case someone comes looking:

I wanted to be a bit more explicit, so I leverage the syntax for custom text. This works particularly nicely for object links as the custom text is not shown.

[[ObsidianLink|export-as:../MyCustomLink]]
/**
* If set, this callback is triggered whenever a drawing is exported to SVG.
* The string returned will replace the link in the exported SVG.
* The hook is only executed if the link is to a file internal to Obsidian
* see: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1605
*  onUpdateElementLinkForExportHook: (data: {
*    originalLink: string,
*    obsidianLink: string,
*    linkedFile: TFile | null,
*    hostFile: TFile,
*  }) => string = null;
*/
//ea.onUpdateElementLinkForExportHook = (data) => {
//  const decodedObsidianURI = decodeURIComponent(data.obsidianLink);
//};
ea.onUpdateElementLinkForExportHook = (data) => {
    var matches = data.originalLink.match(/.*\|export\-as:(.*)\]\]/)
    if (matches)
    {
      return matches[1];
    }

    const decodedObsidianURI = decodeURIComponent(data.obsidianLink);
    return decodedObsidianURI;
};

In case anyone is curious, my use-case is geared towards putting SVGs on Confluence, but also being able to navigate via Obsidian.

Edit: Any chance this hook could be made aware if the SVG is being generated as an embed into another obsidian document? My ideal scenario would be a custom link when exported as a file and obsidian link when exported as an embed.

bls220 avatar Mar 14 '24 00:03 bls220