Skip to content

Commit

Permalink
Merge pull request #35 from mo-analameira/feature/add-marker-cluster-…
Browse files Browse the repository at this point in the history
…group

First iteration of l-marker-cluster-group
  • Loading branch information
andrewgryan authored Jul 22, 2024
2 parents d8a8f2b + 9d144f9 commit 5d08368
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 2 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"vitest": "^1.6.0"
},
"dependencies": {
"leaflet": "^1.9.4"
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3"
}
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import LTooltip from "./l-tooltip.js";
import LPane from "./l-pane.js";
import generator from "./generator.js";
import { circle, polyline, polygon, rectangle } from "leaflet";
import LMarkerClusterGroup from "./l-marker-cluster-group.js";

const init = (() => {
// Custom elements (order of definition is important)
Expand All @@ -27,6 +28,7 @@ const init = (() => {
customElements.define("l-overlay-layers", LOverlayLayers);
customElements.define("l-layer-group", LLayerGroup);
customElements.define("l-tile-layer", LTileLayer);
customElements.define("l-marker-cluster-group", LMarkerClusterGroup);
customElements.define("l-marker", LMarker);
customElements.define("l-popup", LPopup);
customElements.define("l-lat-lng-bounds", LLatLngBounds);
Expand Down
2 changes: 1 addition & 1 deletion src/l-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class LMap extends HTMLElement {

this.addEventListener(layerConnected, (ev) => {
const layer = ev.detail.layer;
layer.addTo(this.map);
this.map.addLayer(layer);
});

this.addEventListener(layerRemoved, (ev) => {
Expand Down
63 changes: 63 additions & 0 deletions src/l-marker-cluster-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// @ts-check
import "leaflet.markercluster";
import { layerConnected } from "./events.js";
import LLayer from "./l-layer.js";

class LMarkerClusterGroup extends LLayer {
static observedAttributes = [
"show-coverage-on-hover",
"icon-options"
];

constructor() {
super();
this.layer = null;
}

connectedCallback() {
const name = this.getAttribute("name");
const iconOptions = this.getAttribute("icon-options");
this.layer = L.markerClusterGroup({
showCoverageOnHover: this.hasAttribute("show-coverage-on-hover"),
iconCreateFunction: this._createIconCreateFunction(iconOptions)
});

const event = new CustomEvent(layerConnected, {
cancelable: true,
bubbles: true,
detail: {
layer: this.layer,
name
}
});
this.dispatchEvent(event);

this.addEventListener(layerConnected, (ev) => {
ev.stopPropagation();
this.layer.addLayer(ev.detail.layer);
});
}

_createIconCreateFunction(iconOptions) {
if (iconOptions) {
let { size, content, className } = JSON.parse(iconOptions);

return (cluster) => {
const resolvedSize = this._callClusterFunction(cluster, size);
const resolvedContent = this._callClusterFunction(cluster, content);

return L.divIcon({
html: resolvedContent,
className: className,
iconSize: new L.Point(resolvedSize, resolvedSize)
});
};
}
}

_callClusterFunction(cluster, body) {
return Function("cluster", `"use strict";return (${body})`)(cluster);
}
}

export default LMarkerClusterGroup;
85 changes: 85 additions & 0 deletions src/l-marker-cluster-group.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// @vitest-environment happy-dom
import "leaflet";
import "leaflet.markercluster";
import { it, expect } from "vitest";
import { layerConnected } from "./events";
import "./index";

it("should cover l-marker-cluster-group", async () => {
const el = document.createElement("l-marker-cluster-group");
el.setAttribute("name", "Marker Cluster");
el.setAttribute("show-coverage-on-hover", "true");

let promise = new Promise((resolve) => {
el.addEventListener(layerConnected, (ev) => {
resolve(ev.detail);
});
});
document.body.appendChild(el);

const actual = await promise;
const expected = {
name: "Marker Cluster",
layer: L.markerClusterGroup({ showCoverageOnHover: true })
};

expect(_removePropertiesToIgnore(actual)).toEqual(_removePropertiesToIgnore(expected));
});

it("should register layers", async () => {
const el = document.createElement("l-marker-cluster-group");
const marker = document.createElement("l-marker");
marker.setAttribute("lat-lng", "[0,0]");
el.appendChild(marker);

let promise = new Promise((resolve) => {
el.addEventListener(layerConnected, (ev) => {
resolve(ev.detail);
});
});
document.body.appendChild(el);

const actual = await promise;
const expected = {
name: null,
layer: L.markerClusterGroup({ showCoverageOnHover: false }).addLayer(L.marker(new L.LatLng(0, 0)))
};

expect(_removePropertiesToIgnore(actual)).toEqual(_removePropertiesToIgnore(expected));
});

it("should create icon function using icon-options", async () => {
const el = document.createElement("l-marker-cluster-group");
const iconOptions = {
"size": "Math.max(40, cluster.getChildCount() / 2)",
"content": "\"<div>\" + cluster.getChildCount() + \"</div>\"",
"className": "mavis-marker-cluster"
};
el.setAttribute("icon-options", JSON.stringify(iconOptions));

let promise = new Promise((resolve) => {
el.addEventListener(layerConnected, (ev) => {
resolve(ev.detail);
});
});
document.body.appendChild(el);

const mockCluster = { getChildCount: () => 100 };
const actual = await promise;
const expectedClusterIcon = L.divIcon({
html: "<div>100</div>",
className: "mavis-marker-cluster",
iconSize: new L.Point(50, 50)
});

expect(actual.layer.options.iconCreateFunction(mockCluster)).toEqual(expectedClusterIcon);
});

function _removePropertiesToIgnore(element) {
element.layer._leaflet_id = null;
element.layer._featureGroup._eventParents = null;
element.layer._nonPointGroup._eventParents = null;
element.layer._needsClustering.forEach(e => e._leaflet_id = null)

return element;
}

0 comments on commit 5d08368

Please sign in to comment.