1 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
2 _getSidebarRelativeClassName: function ({ sidebarRelativePosition }) {
3 if (sidebarRelativePosition > 0) {
4 return "changeset-above-sidebar-viewport";
5 } else if (sidebarRelativePosition < 0) {
6 return "changeset-below-sidebar-viewport";
8 return "changeset-in-sidebar-viewport";
12 _getInteractiveStyle: function (changeset) {
15 color: "var(--changeset-border-color)",
17 className: this._getSidebarRelativeClassName(changeset)
21 _getHighlightStyle: function (changeset) {
25 color: "var(--changeset-border-color)",
26 fillColor: "var(--changeset-fill-color)",
28 className: this._getSidebarRelativeClassName(changeset) + " changeset-highlighted"
32 updateChangesets: function (map, changesets) {
33 this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
34 this.updateChangesetShapes(map);
37 updateChangesetShapes: function (map) {
38 for (const changeset of this._changesets.values()) {
39 const bottomLeft = map.project(L.latLng(changeset.bbox.minlat, changeset.bbox.minlon)),
40 topRight = map.project(L.latLng(changeset.bbox.maxlat, changeset.bbox.maxlon)),
41 width = topRight.x - bottomLeft.x,
42 height = bottomLeft.y - topRight.y,
43 minSize = 20; // Min width/height of changeset in pixels
45 if (width < minSize) {
46 bottomLeft.x -= ((minSize - width) / 2);
47 topRight.x += ((minSize - width) / 2);
50 if (height < minSize) {
51 bottomLeft.y += ((minSize - height) / 2);
52 topRight.y -= ((minSize - height) / 2);
55 changeset.bounds = L.latLngBounds(map.unproject(bottomLeft),
56 map.unproject(topRight));
59 this.updateChangesetLocations(map);
60 this.reorderChangesets();
63 updateChangesetLocations: function (map) {
64 const mapCenterLng = map.getCenter().lng;
66 for (const changeset of this._changesets.values()) {
67 const changesetSouthWest = changeset.bounds.getSouthWest();
68 const changesetNorthEast = changeset.bounds.getNorthEast();
69 const changesetCenterLng = (changesetSouthWest.lng + changesetNorthEast.lng) / 2;
70 const shiftInWorldCircumferences = Math.round((changesetCenterLng - mapCenterLng) / 360);
72 if (shiftInWorldCircumferences) {
73 changesetSouthWest.lng -= shiftInWorldCircumferences * 360;
74 changesetNorthEast.lng -= shiftInWorldCircumferences * 360;
76 this._interactiveLayer.getLayer(changeset.id)?.setBounds(changeset.bounds);
77 this._highlightLayer.getLayer(changeset.id)?.setBounds(changeset.bounds);
82 reorderChangesets: function () {
83 const changesetEntries = [...this._changesets];
84 changesetEntries.sort(([, a], [, b]) => {
85 const aInViewport = !a.sidebarRelativePosition;
86 const bInViewport = !b.sidebarRelativePosition;
87 if (aInViewport !== bInViewport) return aInViewport - bInViewport;
88 return b.bounds.getSize() - a.bounds.getSize();
90 this._changesets = new Map(changesetEntries);
92 this._interactiveLayer.clearLayers();
93 this._highlightLayer.clearLayers();
95 for (const changeset of this._changesets.values()) {
96 const rect = L.rectangle(changeset.bounds, this._getInteractiveStyle(changeset));
97 rect.id = changeset.id;
98 rect.addTo(this._interactiveLayer);
102 toggleChangesetHighlight: function (id, state) {
103 const changeset = this._changesets.get(id);
104 if (!changeset) return;
106 let highlightRect = this._highlightLayer.getLayer(id);
107 if (!state && highlightRect) {
108 this._highlightLayer.removeLayer(highlightRect);
110 if (state && !highlightRect) {
111 highlightRect = L.rectangle(changeset.bounds, this._getHighlightStyle(changeset));
112 highlightRect.id = id;
113 this._highlightLayer.addLayer(highlightRect);
117 setChangesetSidebarRelativePosition: function (id, state) {
118 const changeset = this._changesets.get(id);
119 if (!changeset) return;
120 changeset.sidebarRelativePosition = state;
124 OSM.HistoryChangesetsLayer.addInitHook(function () {
125 this._changesets = new Map;
127 this._interactiveLayer = L.featureGroup();
128 this._highlightLayer = L.featureGroup();
130 this._interactiveLayer.getLayerId = this._highlightLayer.getLayerId = (layer) => layer.id;
131 this.addLayer(this._interactiveLayer).addLayer(this._highlightLayer);