Skip to content

Instantly share code, notes, and snippets.

@zsviczian
Last active January 20, 2024 06:53
Show Gist options
  • Save zsviczian/33ff695d5b990de1ebe8b82e541c26ad to your computer and use it in GitHub Desktop.
Save zsviczian/33ff695d5b990de1ebe8b82e541c26ad to your computer and use it in GitHub Desktop.
Excalidraw Icon Library

<%* /*

*/
s = await navigator.clipboard.readText();
navigator.clipboard.writeText(s.replaceAll("\n","").replaceAll(/\s{2,}/g," "));
%>

/*

FILENAME_FILTER=/^icon -/i;
KEYWORD_GRABBER=/(?:icon -)?([^-]*)-?/i;
COLS=22;
HEIGHT=180;
WIDTH=180;
TEXTHEIGHT=40;
PADDING=50;
const api = ea.getExcalidrawAPI();
const f=ea.targetView.file;
icons=app.vault.getFiles().filter(f=>(f.extension!=='md'||ea.isExcalidrawFile(f))&&f.basename.toLowerCase().match(FILENAME_FILTER)).sort((a,b)=>a.basename.toLowerCase()<b.basename.toLowerCase()?-1:1);
const {
  zenModeEnabled,
  viewModeEnabled,
  linkOpacity,
  trayModeEnabled,
  penMode,
  penDetected,
  allowPinchZoom,
  allowWheelZoom,
  pinnedScripts,
  customPens
} = api.getAppState();
api.resetScene();
api.updateScene({appState: {
  zenModeEnabled,
  viewModeEnabled,
  linkOpacity,
  trayModeEnabled,
  penMode,
  penDetected,
  allowPinchZoom,
  allowWheelZoom,
  pinnedScripts,
  customPens
}});
col=0;
row=0;
for(icon of icons) {
  id=await ea.addImage(col*(WIDTH+PADDING),row*(HEIGHT+PADDING+TEXTHEIGHT),icon);
  if(f!==ea.targetView.file && ea.targetView?.getViewType?.()!=='excalidraw') return;
  if(!id) continue;
  keywords=icon.basename.match(KEYWORD_GRABBER)[1].trim();
  ea.style.verticalAlign='top';
  ea.style.textAlign='center';
  ea.style.fontSize=12;  
  el=ea.getElement(id);
  ratio=el.width/WIDTH;
  if(el.height/ratio>HEIGHT) ratio=el.height/HEIGHT;
  el.width=el.width/ratio;
  el.height=el.height/ratio;
  ea.style.strokeColor='black';
  boxID=ea.addText(col*(WIDTH+PADDING)-PADDING/2+10,row*(HEIGHT+PADDING+TEXTHEIGHT)+HEIGHT+PADDING/2-10,keywords,{
    width:WIDTH+PADDING-20,
    height:TEXTHEIGHT-20,
    boxPadding:10,
    textAlign:'center',
    textVerticalAlign:'top',
    boxStrokeColor:'transparent',
    box:'box'
  });		
  if(++col===COLS) {
    row++;
    col=0;
    await ea.addElementsToView(false,false,false);
    ea.targetView.clearDirty();
    ea.clear();
  }
}
await ea.addElementsToView(false,false,false);
ea.targetView.clearDirty();
api.zoomToFit();
api.updateContainerSize(ea.getViewElements().filter(el=>el.type==='rectangle'));
api.setActiveTool({type: 'hand'});
excalidraw-plugin excalidraw-onload-script
parsed
FILENAME_FILTER=/^icon -/i;KEYWORD_GRABBER=/(?:icon -)?([^-]*)-?/i;COLS=22;HEIGHT=180;WIDTH=180;TEXTHEIGHT=40;PADDING=50;const api = ea.getExcalidrawAPI();const f=ea.targetView.file;icons=app.vault.getFiles().filter(f=>(f.extension!=='md'||ea.isExcalidrawFile(f))&&f.basename.toLowerCase().match(FILENAME_FILTER)).sort((a,b)=>a.basename.toLowerCase()<b.basename.toLowerCase()?-1:1);const { zenModeEnabled, viewModeEnabled, linkOpacity, trayModeEnabled, penMode, penDetected, allowPinchZoom, allowWheelZoom, pinnedScripts, customPens} = api.getAppState();api.resetScene();api.updateScene({appState: { zenModeEnabled, viewModeEnabled, linkOpacity, trayModeEnabled, penMode, penDetected, allowPinchZoom, allowWheelZoom, pinnedScripts, customPens}});col=0;row=0;for(icon of icons) { id=await ea.addImage(col*(WIDTH+PADDING),row*(HEIGHT+PADDING+TEXTHEIGHT),icon); if(f!==ea.targetView.file && ea.targetView?.getViewType?.()!=='excalidraw') return; if(!id) continue; keywords=icon.basename.match(KEYWORD_GRABBER)[1].trim(); ea.style.verticalAlign='top'; ea.style.textAlign='center'; ea.style.fontSize=12; el=ea.getElement(id); ratio=el.width/WIDTH; if(el.height/ratio>HEIGHT) ratio=el.height/HEIGHT; el.width=el.width/ratio; el.height=el.height/ratio; ea.style.strokeColor='black'; boxID=ea.addText(col*(WIDTH+PADDING)-PADDING/2+10,row*(HEIGHT+PADDING+TEXTHEIGHT)+HEIGHT+PADDING/2-10,keywords,{ width:WIDTH+PADDING-20, height:TEXTHEIGHT-20, boxPadding:10, textAlign:'center', textVerticalAlign:'top', boxStrokeColor:'transparent', box:'box' }); if(++col===COLS) { row++; col=0; await ea.addElementsToView(false,false,false); ea.targetView.clearDirty(); ea.clear(); }}await ea.addElementsToView(false,false,false);ea.targetView.clearDirty();api.zoomToFit();api.updateContainerSize(ea.getViewElements().filter(el=>el.type==='rectangle'));api.setActiveTool({type: 'hand'});

#exclude

Text Elements

%%

Drawing

{
	"type": "excalidraw",
	"version": 2,
	"source": "https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/2.0.17",
	"elements": [],
	"appState": {
		"theme": "light",
		"viewBackgroundColor": "#ffffff",
		"currentItemStrokeColor": "#1e1e1e",
		"currentItemBackgroundColor": "transparent",
		"currentItemFillStyle": "solid",
		"currentItemStrokeWidth": 2,
		"currentItemStrokeStyle": "solid",
		"currentItemRoughness": 1,
		"currentItemOpacity": 100,
		"currentItemFontFamily": 1,
		"currentItemFontSize": 20,
		"currentItemTextAlign": "left",
		"currentItemStartArrowhead": null,
		"currentItemEndArrowhead": "arrow",
		"scrollX": 0,
		"scrollY": 0,
		"zoom": {
			"value": 1
		},
		"currentItemRoundness": "round",
		"gridSize": null,
		"gridColor": {
			"Bold": "#C9C9C9FF",
			"Regular": "#EDEDEDFF"
		},
		"currentStrokeOptions": null,
		"previousGridSize": null,
		"frameRendering": {
			"enabled": true,
			"clip": true,
			"name": true,
			"outline": true
		}
	},
	"files": {}
}

%%

@Stefan-59
Copy link

Thanks a lot for these great ideas and scripts!!
When I use the 'Icon Library Script.md' (copied RAW from above), only 18 icons are added to the drawing.
The 'excalidraw-onload-script' works fine.
Am I doing soemthing wrong?

@zsviczian
Copy link
Author

Well, it depends on how many Icon files you have in your Vault. The script looks for image files with "Icon" in the name.

@Stefan-59
Copy link

Sure. But why does the script (in the same vault) return all (90) icons when run from within the drawing and only 18 when run as user-script?

@zsviczian
Copy link
Author

you'll need to do some debugging to figure out. are all the 90 files image files like PNG or JPG? or you have others as well. Are you using exactly the same filter in both cases? e.g. comparing filenames using lowercase in both cases?

@Stefan-59
Copy link

unfortunately, I am not able (yet) to do the debugging. Is simple copied the code from the above examples and the results are different. In both cases, it's the same vault, the same images (all image-xyz.png) in the same folder.
So again: it IS working with the code embedded in the drawing, so all good. BUT I'm just wondering why the standalone script would deliver different results. Sorry if I can't figure it out myself (yet), I'm just beginning to wrap my head around jacasript and the possibilities to debug with the console. If you have any tip for some recommended beginners (with the prospect of using js in Obsidian) guide, I'd be happy!

@Stefan-59
Copy link

unfortunately, I am not able (yet) to do the debugging with the console 🤷‍♂️.
I simply copied the code from the above examples and the results are different. In both cases, it's the same vault, the same images (all image-xyz.png) in the same folder.
So again: it IS working with the code embedded in the drawing, so all good. BUT I'm just wondering why the standalone script would deliver different results. Sorry if I can't figure it out myself (yet), I'm just beginning to wrap my head around JavaScript and the possibilities to debug with the console. If you have any tip for some recommended beginners guide (with the prospect of using js in Obsidian) , I'd be happy!

@zsviczian
Copy link
Author

so in both cases you see an Excalidraw drawing, but one has 18 images and the other 90?

did you modify the filter at the beginning of the code?

regarding learning Obsidian.js, I think small projects like this one are the best way.

one easy way to debug is to insert console.log(variable_name); at key points to see the value of variables.

another approach is to insert debugger; command in the code. doing this the script execution will stop when the program gets to that point (but only if developer console is open).

@Stefan-59
Copy link

Ok, now that's kind of weird. I inserted ' console.log(icons);' after the first command, now it works fine and I can see the (correct) number of icons in the console AND in the drawing.
Removed the console.log command and it still works perfectly.
I have no idea, what went wrong in my first attempts. And I promise, I didn't change anything (at least not knowingly). 🙈

So, thank you for your effort to help out and again 1.000++ thanks for your great plugins and videos!!! 🙏

@JuergenKaettnis
Copy link

Thank you for your great video and script. As always, I am on my Samsung tablet with Android. I put the script in the Script folder and I copied the file into my vault. Then I added the word 'Icon' just to a few images and the imported file loaded a library of the images. Then I renamed altogether around 30 files. After that I always get a message and button "Scroll back to content", but the canvas remains white. I cannot debug, because I just have the tablet and cannot start the developer console. And I am also not a programmer, just know very roughly how to debug. Any suggestions? Is the functionality limited on Android devices?

Because the script wasn't working, I moved most images to another folder, but the script still didn't work. I reinstalled the script and I recreated the file from the original source, but still didn't change for the better.

But knowledge discovery via Icons is something I were totally missing before and is quite interesting. And the icons add an additional input to remember and connect the information anyway.

@JuergenKaettnis
Copy link

JuergenKaettnis commented Jul 16, 2022

Update: I activated the script 'Zoom to fit selected elements' and there was my Icon library again. When the script wasn't showing anything, zoom factor display some strange symbols as well. Probably, the adding of the many icons lead to a kind of confusion.

I counted 24 files with 'icon' in file name (using Obsidian search) and most of them are displayed in the Icon Library, but not all.

By the way, in your video you opened the Icon Library in a kind of side pane. My Icon Library is more like a normal excalidraw file with icons in it. Am I doing s.th. wrong here? Or, again, is the functionality limited on Android devices?

@TheHuntyBadger
Copy link

Is there a filter option to point the script to a specific directory? I migrated from Joplin to Obsidian and I noticed it catches file with icon in the name. Even after changing it to "icon-"

@OXiOSDev
Copy link

Thank you very much for the icon library and the script.
The icon library works fine but I have some questions about the display of the icon library on your video:

  1. the name "Icon Library" does not display the ".excalibrain" as on mine (number 1)
  2. the excalidraw or image icons is on the left of the panel (number 2 and 3)
  3. on your panel, in the video, we also see, on the right of the "Icon Library", a number (number 4 and 5) and two opposite arrows (number 6 and 7).
    Display

I assume this is only a setting in Obsidian or in the Excalidraw setting but I can't find it.

Thanks for your work !!!!

@zsviczian
Copy link
Author

I did not notice these comments here:

  • The filter is now set for files beginning with "Icon -" or "icon -". You can change the filter by changing the FILENAME_FILTER=/^icon -/i; regular expression at the beginning of the script
  • @OXiOSDev: "Icon Library" vs. "Icon Library.excalidraw" is just a difference in filenames. Simply delete the ".excalidraw" part of the filename. It is not needed. You can set the default file naming in Excalidraw settings.
  • @JuergenKaettnis My library is also just an excalidraw file. You can drag any file (markdown, excalidraw, anything) to the side pane and pin it there.
  • @OXiOSDev regarding #3: I think those come from the PaneRelief plugin.

@OXiOSDev
Copy link

OXiOSDev commented Apr 2, 2023

@zsviczian Thank you very much for your answers

@LEEJOOPIL
Copy link

whein i install this script its not working.
so i debug my console, the line below

if(f!==ea.targetView.file && ea.targetView?.getViewType?.()!=="excalidraw") return;

at this line code error said return is not defined.

do you know what meaning is?

@zsviczian
Copy link
Author

@LEEJOOPIL
Did you download the .md file following this link? Icon Library.excalidraw.md

@zsviczian
Copy link
Author

I think the error message says return is not defined.

@LEEJOOPIL
Copy link

I used lcon library.excalidraw.md but still not working...
still return is not defined..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment