1 OSM.HistoryChangesetBboxLayer = L.FeatureGroup.extend({
 
   2   getLayerId: function (layer) {
 
   6   addChangesetLayer: function (changeset) {
 
   7     const style = this._getChangesetStyle(changeset);
 
   8     const rectangle = L.rectangle(changeset.bounds, {
 
  12         text: OSM.i18n.t("javascripts.context.scroll_to_changeset"),
 
  14           this.fire("requestscrolltochangeset", { id: changeset.id }, true);
 
  22     rectangle.id = changeset.id;
 
  23     return this.addLayer(rectangle);
 
  26   updateChangesetLayerBounds: function (changeset) {
 
  27     this.getLayer(changeset.id)?.setBounds(changeset.bounds);
 
  30   _getSidebarRelativeClassName: function ({ sidebarRelativePosition }) {
 
  31     if (sidebarRelativePosition > 0) {
 
  32       return "changeset-above-sidebar-viewport";
 
  33     } else if (sidebarRelativePosition < 0) {
 
  34       return "changeset-below-sidebar-viewport";
 
  36       return "changeset-in-sidebar-viewport";
 
  41 OSM.HistoryChangesetBboxAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
 
  42   _getChangesetStyle: function (changeset) {
 
  46       className: this._getSidebarRelativeClassName(changeset)
 
  51 OSM.HistoryChangesetBboxOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
 
  52   _getChangesetStyle: function (changeset) {
 
  55       color: "var(--changeset-outline-color)",
 
  57       className: this._getSidebarRelativeClassName(changeset)
 
  62 OSM.HistoryChangesetBboxBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
 
  63   _getChangesetStyle: function (changeset) {
 
  66       color: "var(--changeset-border-color)",
 
  68       className: this._getSidebarRelativeClassName(changeset)
 
  73 OSM.HistoryChangesetBboxHighlightAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
 
  74   _getChangesetStyle: function (changeset) {
 
  78       fillColor: "var(--changeset-fill-color)",
 
  80       className: this._getSidebarRelativeClassName(changeset)
 
  85 OSM.HistoryChangesetBboxHighlightOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
 
  86   _getChangesetStyle: function (changeset) {
 
  89       weight: changeset.sidebarRelativePosition === 0 ? 8 : 6,
 
  90       color: "var(--changeset-outline-color)",
 
  92       className: this._getSidebarRelativeClassName(changeset) + " changeset-highlight-outline"
 
  97 OSM.HistoryChangesetBboxHighlightBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
 
  98   _getChangesetStyle: function (changeset) {
 
 102       color: "var(--changeset-border-color)",
 
 104       className: this._getSidebarRelativeClassName(changeset)
 
 109 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
 
 110   updateChangesets: function (map, changesets) {
 
 111     this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
 
 112     this.updateChangesetsGeometry(map);
 
 115   updateChangesetsGeometry: function (map) {
 
 116     const changesetSizeLowerBound = 20, // Min width/height of changeset in pixels
 
 117           mapViewExpansion = 2; // Half of bbox border+outline width in pixels
 
 119     const mapViewCenterLng = map.getCenter().lng,
 
 120           mapViewPixelBounds = map.getPixelBounds();
 
 122     mapViewPixelBounds.min.x -= mapViewExpansion;
 
 123     mapViewPixelBounds.min.y -= mapViewExpansion;
 
 124     mapViewPixelBounds.max.x += mapViewExpansion;
 
 125     mapViewPixelBounds.max.y += mapViewExpansion;
 
 127     for (const changeset of this._changesets.values()) {
 
 128       const changesetNorthWestLatLng = L.latLng(changeset.bbox.maxlat, changeset.bbox.minlon),
 
 129             changesetSouthEastLatLng = L.latLng(changeset.bbox.minlat, changeset.bbox.maxlon),
 
 130             changesetCenterLng = (changesetNorthWestLatLng.lng + changesetSouthEastLatLng.lng) / 2,
 
 131             shiftInWorldCircumferences = Math.round((changesetCenterLng - mapViewCenterLng) / 360);
 
 133       if (shiftInWorldCircumferences) {
 
 134         changesetNorthWestLatLng.lng -= shiftInWorldCircumferences * 360;
 
 135         changesetSouthEastLatLng.lng -= shiftInWorldCircumferences * 360;
 
 138       const changesetMinCorner = map.project(changesetNorthWestLatLng),
 
 139             changesetMaxCorner = map.project(changesetSouthEastLatLng),
 
 140             changesetSizeX = changesetMaxCorner.x - changesetMinCorner.x,
 
 141             changesetSizeY = changesetMaxCorner.y - changesetMinCorner.y;
 
 143       if (changesetSizeX < changesetSizeLowerBound) {
 
 144         changesetMinCorner.x -= (changesetSizeLowerBound - changesetSizeX) / 2;
 
 145         changesetMaxCorner.x += (changesetSizeLowerBound - changesetSizeX) / 2;
 
 148       if (changesetSizeY < changesetSizeLowerBound) {
 
 149         changesetMinCorner.y -= (changesetSizeLowerBound - changesetSizeY) / 2;
 
 150         changesetMaxCorner.y += (changesetSizeLowerBound - changesetSizeY) / 2;
 
 153       changeset.bounds = L.latLngBounds(map.unproject(changesetMinCorner),
 
 154                                         map.unproject(changesetMaxCorner));
 
 156       const changesetPixelBounds = L.bounds(changesetMinCorner, changesetMaxCorner);
 
 158       changeset.hasEdgesInMapView = changesetPixelBounds.overlaps(mapViewPixelBounds) &&
 
 159                                     !changesetPixelBounds.contains(mapViewPixelBounds);
 
 162     this.updateChangesetsOrder();
 
 165   updateChangesetsOrder: function () {
 
 166     const changesetEntries = [...this._changesets];
 
 167     changesetEntries.sort(([, a], [, b]) => b.bounds.getSize() - a.bounds.getSize());
 
 168     this._changesets = new Map(changesetEntries);
 
 170     for (const layer of this._bboxLayers) {
 
 174     for (const changeset of this._changesets.values()) {
 
 175       if (changeset.sidebarRelativePosition !== 0 && changeset.hasEdgesInMapView) {
 
 176         this._areaLayer.addChangesetLayer(changeset);
 
 180     for (const changeset of this._changesets.values()) {
 
 181       if (changeset.sidebarRelativePosition === 0 && changeset.hasEdgesInMapView) {
 
 182         this._areaLayer.addChangesetLayer(changeset);
 
 186     for (const changeset of this._changesets.values()) {
 
 187       if (changeset.sidebarRelativePosition !== 0) {
 
 188         this._borderLayer.addChangesetLayer(changeset);
 
 192     for (const changeset of this._changesets.values()) {
 
 193       if (changeset.sidebarRelativePosition === 0) {
 
 194         this._outlineLayer.addChangesetLayer(changeset);
 
 198     for (const changeset of this._changesets.values()) {
 
 199       if (changeset.sidebarRelativePosition === 0) {
 
 200         this._borderLayer.addChangesetLayer(changeset);
 
 205   toggleChangesetHighlight: function (id, state) {
 
 206     const changeset = this._changesets.get(id);
 
 207     if (!changeset) return;
 
 209     this._highlightAreaLayer.clearLayers();
 
 210     this._highlightOutlineLayer.clearLayers();
 
 211     this._highlightBorderLayer.clearLayers();
 
 214       this._highlightAreaLayer.addChangesetLayer(changeset);
 
 215       this._highlightOutlineLayer.addChangesetLayer(changeset);
 
 216       this._highlightBorderLayer.addChangesetLayer(changeset);
 
 220   setChangesetSidebarRelativePosition: function (id, state) {
 
 221     const changeset = this._changesets.get(id);
 
 222     if (!changeset) return;
 
 223     changeset.sidebarRelativePosition = state;
 
 227 OSM.HistoryChangesetsLayer.addInitHook(function () {
 
 228   this._changesets = new Map;
 
 231     this._areaLayer = new OSM.HistoryChangesetBboxAreaLayer().addTo(this),
 
 232     this._outlineLayer = new OSM.HistoryChangesetBboxOutlineLayer().addTo(this),
 
 233     this._borderLayer = new OSM.HistoryChangesetBboxBorderLayer().addTo(this),
 
 234     this._highlightAreaLayer = new OSM.HistoryChangesetBboxHighlightAreaLayer().addTo(this),
 
 235     this._highlightOutlineLayer = new OSM.HistoryChangesetBboxHighlightOutlineLayer().addTo(this),
 
 236     this._highlightBorderLayer = new OSM.HistoryChangesetBboxHighlightBorderLayer().addTo(this)