From b9305f50529e862df1359a46641bf8b0280c5b49 Mon Sep 17 00:00:00 2001 From: Nathan Date: Wed, 28 Jun 2023 23:51:54 -0400 Subject: [PATCH] feat: Define custom marker types in json files (#400) * feat: allow loading marker types from a local json file * fix: correct marker types import path * refactor: wait for map to be built before trying to access it * fix: get marker data from map rather than plugin data * fix: ensure local icons can never be empty when getting marker types for map * doc: document addition of local marker types --- README.md | 6 +++++- src/layer/marker.ts | 11 +++++------ src/main.ts | 21 +++++++++++++++++++-- src/map/map.ts | 2 +- src/modals/context.ts | 6 ++---- src/renderer/renderer.ts | 17 ++++++++++++++--- types/map.d.ts | 2 ++ types/marker.d.ts | 2 +- 8 files changed, 49 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b6c9e9c..19d8e14 100644 --- a/README.md +++ b/README.md @@ -323,7 +323,7 @@ On real-world maps, only `unit: ` is required. It will attempt to scale the meas New markers can be added to the map by right clicking. -If any additional marker types have been created in the settings, a list will appear to choose from. +If any additional marker types have been created in plugin settings or a `markers.json` file in the same directory, a list will appear to choose from. Once a marker has been created, it can be dragged to a different location. @@ -872,6 +872,10 @@ Adding a new marker displays a new window, where the new marker parameters can b If layer icon is on, the icon be moved around the base icon by clicking and dragging, to customize where the icon is layered. If Shift is held while moving the icon, it will snap to the midlines. +#### Creating local marker types + +New markers can also be defined in a `markers.json` file. These marker types will be available to any notes in the same directory as the json file. The json file should contain an array of Icon objects, See the [Icon interface](https://github.com/javalent/obsidian-leaflet/blob/1fa4c237deceff1def883872fdad3822f9bff560/types/saved.d.ts#L7) for details. + #### Using an Image as a Marker Icon When creating an additional marker, an image may be uploaded to use as the marker icon instead of selecting a Font Awesome icon. diff --git a/src/layer/marker.ts b/src/layer/marker.ts index 8f62318..1873137 100644 --- a/src/layer/marker.ts +++ b/src/layer/marker.ts @@ -204,8 +204,8 @@ export class Marker extends Layer { ) { super(); - const marker = this.map.plugin.getIconForType(type); - if (!marker) { + const markerIcon = this.map.markerIcons.get(type) ?? this.map.markerIcons.get('default'); + if (!markerIcon) { new Notice( t( "Leaflet: Could not create icon for %1 - does this type exist in settings?", @@ -214,6 +214,7 @@ export class Marker extends Layer { ); return; } + const marker = markerIcon.markerIcon; const icon = markerDivIcon(this.map.plugin.parseIcon(marker)); this.leafletInstance = divIconMarker( loc, @@ -251,10 +252,8 @@ export class Marker extends Layer { this.link = link; - const markerIcon = this.map.plugin.getIconForType(this.type); - - this.minZoom = minZoom ?? markerIcon?.minZoom ?? null; - this.maxZoom = maxZoom ?? markerIcon?.maxZoom ?? null; + this.minZoom = minZoom ?? marker?.minZoom ?? null; + this.maxZoom = maxZoom ?? marker?.maxZoom ?? null; this.checkAndAddToMap(); diff --git a/src/main.ts b/src/main.ts index 8a9a1bf..0e2ded6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -332,8 +332,8 @@ export default class ObsidianLeaflet extends Plugin { params, source ); - const map = renderer.map; - + + const map = await renderer.getMap(); this.registerMapEvents(map); ctx.addChild(renderer); @@ -636,6 +636,7 @@ export default class ObsidianLeaflet extends Plugin { markerIcon: icon }; } + public generateMarkerMarkup( markers: Icon[] = this.data.markerIcons ): MarkerIcon[] { @@ -663,6 +664,22 @@ export default class ObsidianLeaflet extends Plugin { return ret; } + public async getLocalFileMarkers(file: TFile, markerFileName = "markers.json"): Promise { + const markerFilePath = `${file.parent.path}/${markerFileName}`; + const markerFile = this.app.vault.getAbstractFileByPath(markerFilePath); + const markers: MarkerIcon[] = []; + if (markerFile instanceof TFile) { + const markerJson = await this.app.vault.read(markerFile); + try { + const icons = JSON.parse(markerJson); + markers.push(...icons.map((i: Icon) => this.parseIcon(i))) + } catch { + console.error(`Badly formatted marker file ${markerFilePath}`); + } + } + return markers; + } + public getIconForTag(tags: Set) { return this.data.markerIcons.find((icon) => ( diff --git a/src/map/map.ts b/src/map/map.ts index fcf4333..3b72eff 100644 --- a/src/map/map.ts +++ b/src/map/map.ts @@ -321,7 +321,7 @@ export abstract class BaseMap extends Events implements BaseMapDefinition { mapLayers: LayerGroup[] = []; get markerIcons(): Map { return new Map( - this.plugin.markerIcons.map((markerIcon) => [ + [...this.plugin.markerIcons, ...(this.options.localMarkerTypes ?? [])].map((markerIcon) => [ markerIcon.type, markerIcon ]) diff --git a/src/modals/context.ts b/src/modals/context.ts index 1d8ab98..66ff729 100644 --- a/src/modals/context.ts +++ b/src/modals/context.ts @@ -5,7 +5,7 @@ import type { Marker, TooltipDisplay, BaseMapType -} from "../types"; +} from "../../types"; import { PathSuggestionModal } from "./path"; import { CommandSuggestionModal } from "./command"; @@ -60,9 +60,7 @@ export class MarkerContextModal extends Modal { let newMarker = value == "default" ? this.map.data.defaultMarker - : this.map.data.markerIcons.find( - (m) => m.type == value - ); + : this.map.markerIcons.get(value); this.tempMarker.type = newMarker.type; }); }); diff --git a/src/renderer/renderer.ts b/src/renderer/renderer.ts index 2328063..7ae710a 100644 --- a/src/renderer/renderer.ts +++ b/src/renderer/renderer.ts @@ -75,6 +75,7 @@ export class LeafletRenderer extends MarkdownRenderChild { loader: Loader = new Loader(this.plugin.app); resize: ResizeObserver; map: BaseMapType; + private mapBuilt: Promise; verbose: boolean; parentEl: HTMLElement; options: LeafletMapOptions; @@ -194,8 +195,7 @@ export class LeafletRenderer extends MarkdownRenderChild { this.map.leafletInstance.invalidateSize(); } }); - - this.buildMap(); + this.mapBuilt = this.buildMap(); this.resize.observe(this.containerEl); } @@ -254,7 +254,17 @@ export class LeafletRenderer extends MarkdownRenderChild { this.map.leafletInstance.invalidateSize(); } - async buildMap() { + /** + * Use this to get the map instance instead of renderer.map when it might not be defined yet + */ + async getMap(): Promise { + await this.mapBuilt; + return this.map; + } + + async buildMap(): Promise { + this.options.localMarkerTypes = await this.plugin.getLocalFileMarkers(this.file); + if (this.options.type === "real") { this.map = new RealMap(this, this.options); } else { @@ -339,6 +349,7 @@ export class LeafletRenderer extends MarkdownRenderChild { } async onload() { + await this.mapBuilt; this.map.log("MarkdownRenderChild loaded. Appending map."); this.containerEl.appendChild(this.map.contentEl); diff --git a/types/map.d.ts b/types/map.d.ts index 850b428..5ccea87 100644 --- a/types/map.d.ts +++ b/types/map.d.ts @@ -68,6 +68,8 @@ export interface LeafletMapOptions { geojsonColor?: string; gpxColor?: string; + localMarkerTypes?: MarkerIcon[]; + hasAdditional?: boolean; height?: string; width?: string; diff --git a/types/marker.d.ts b/types/marker.d.ts index f2ab7a1..4793c89 100644 --- a/types/marker.d.ts +++ b/types/marker.d.ts @@ -1,6 +1,6 @@ import { Icon, TooltipDisplay } from "."; import { MarkerDivIcon } from "./map"; -import type { Marker as MarkerDefinition } from "../layer/marker"; +import type { Marker as MarkerDefinition } from "../src/layer/marker"; export type Marker = MarkerDefinition; export interface MarkerIcon {