Skip to content

Instantly share code, notes, and snippets.

@dimfeld
Last active November 13, 2020 18:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimfeld/e95a7ccf86dbd0d9c918a7a1951f2ad8 to your computer and use it in GitHub Desktop.
Save dimfeld/e95a7ccf86dbd0d9c918a7a1951f2ad8 to your computer and use it in GitHub Desktop.

The "each Leaflet object as a Svelte component" thing wasn't the first I tried. My first attempt manages the state manually with a process similar to what I described here: https://imfeld.dev/writing/leaflet_with_svelte#syncing-local-state-to-the-map-through-reactive-statements. Essentially I had some code blocks that keep track of which objects I had created in Leaflet, and manually reconciled that with the declarative state from the reactive statements, adding or removing markers/lines/etc. I had a code block like this for each type of object that the app used.

// A Map containing all the markers that we have created.
let markers = new Map();
let allLocations = {...};

// Create the markers.
for (let [id, data] of Object.entries(allLocations)) {
  let marker = L.marker(data.location, { icon: data.icon });
  markers.set(id, marker);
}

// Pretend this is a complicated set of logic to recalculate what is visible.
$: enabledIds = new Set(findRelationships(currentCity, activeCities));

function syncMarkers(markersMap, includedSet) {
  for (let [id, marker] of markersMap.entries()) {
    if (includedSet.has(id)) {
      map.addLayer(marker);
    } else {
      map.removeLayer(marker);
    }
  }
}

$: if(map) syncMarkers(markers, enabledIds);

At the time I realized that this is basically the same thing that Svelte's #each loop does to convert the "declarative" state of an array into the imperative "do stuff in the DOM and/or make components" that the compiler generates, but it was a month or so ago that I realized I could actually take advantage of this. I saw a snippet of a React app based around the Google Maps API that did something like this: <GoogleMaps>{circles.map((circle) => <Circle center={circle.center} />}</GoogleMaps> (or whatever, I don't really know JSX but it was kind of like that)

And while I didn't see the underlying implementation it gave me the idea that I could get the same thing working in Svelte by making components that didn't make any DOM elements but just interacted with the Leaflet map in onMount and onDestroy. So I decided to give it a try for the presentation demo app, and it turned out to be much easier. All the "non-Sveltey" code is encapsulated in small, easy-to-manage components, which is great both for working within the app and for making things easier to use on my next mapping project.

<Leaflet>
  {#each lines as line}
    <Polyline latLngs={line.latLngs} color={line.color} />
  {/each}
</Leaflet>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment