maplibre-preview 1.3.10 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc25f7eb64dc27af2bdd7edcf81ee66c6bd4c6e02105be073a76d4385b9707e7
4
- data.tar.gz: b8820b6b86f59cb129bf9da0f2bf51c9f91df3dc6ee0082773b713ab2a8141e1
3
+ metadata.gz: a800d72c98751ed645b6c3e49dfcaa5d5560e258412d6d360cdf4ce85b747384
4
+ data.tar.gz: 555af4aac0846b6e50aea699bab368cb4ab9585ade0d2e2510d209af8aa892ae
5
5
  SHA512:
6
- metadata.gz: 49fca224b36b60c97bfa7d532b101b41f8d52c02af3eb2f5eb952b214263c93554a744f330f1af2f98caa9fc332f309a7fde5830be41d6973559de557c3fd6db
7
- data.tar.gz: 9f11842ece6fe33acacae31de1d7152e2047e9b74bea0dc29bf268e775476a302a4af27aea3f14c64455f21aacdee763616fce66bafcd9bc41d588fcfb650d4d
6
+ metadata.gz: e2052b52a76ca7071c52bb989f80d52c153bae0fd0ba9bf4d1ca4c8cc8705795c0784e8949b2f320bb9d826210a6ce58f1f4e78684ac30923fc1a999efedc7c2
7
+ data.tar.gz: 1c4560519a20b975f31796394ab36d0213eb5b94596ccfdc37772943f40733eeb0a95a662797963c2010b89886504e7466188ea562c9c3ea27b51cc02ba45604
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.0] - 2025-12-04
4
+
5
+ ### Added
6
+ - **Tile Grid visualization** - TileGridManager class for displaying tile boundaries and statistics
7
+ - **Tile count tracking** - real-time count of loaded tiles with fallback estimation
8
+ - **Tile Grid panel** - UI panel showing number of loaded tiles with toggle for tile borders
9
+ - **Tile Grid button** - control button in layer controls to show/hide tile grid visualization
10
+
11
+ ### Technical Changes
12
+ - **tilegrid.js** - new JavaScript module for tile grid management
13
+ - **MapLibre showTileBoundaries integration** - uses native debug feature for tile boundary visualization
14
+ - **Internal API tile counting** - attempts to count tiles via sourceCaches with fallback estimation
15
+
3
16
  ## [1.3.10] - 2025-11-19
4
17
 
5
18
  ### Changed
@@ -0,0 +1,174 @@
1
+ /**
2
+ * TileGridManager - manages tile boundaries visualization and tile statistics
3
+ */
4
+ class TileGridManager {
5
+ constructor(options) {
6
+ this.map = options.map;
7
+ this.panelContainer = null;
8
+ this.isVisible = false;
9
+ this.showBorders = true;
10
+ this.tilesLoaded = 0;
11
+ this.updateInterval = null;
12
+ }
13
+
14
+ init() {
15
+ if (!this.map) return;
16
+
17
+ this.createPanel();
18
+ this.setupEventListeners();
19
+ this.startTileTracking();
20
+ }
21
+
22
+ createPanel() {
23
+ this.panelContainer = document.createElement('div');
24
+ this.panelContainer.id = 'tilegrid-panel';
25
+ this.panelContainer.className = 'tilegrid-panel';
26
+ this.panelContainer.style.display = 'none';
27
+
28
+ this.panelContainer.innerHTML = `
29
+ <div class="tilegrid-header">
30
+ <span class="tilegrid-title">Tile Grid</span>
31
+ <button class="tilegrid-close" onclick="tileGridManager.toggle()">×</button>
32
+ </div>
33
+ <div class="tilegrid-stats">
34
+ <div class="tilegrid-stat-label">NO. OF TILES LOADED</div>
35
+ <div class="tilegrid-stat-value" id="tilegrid-count">0</div>
36
+ </div>
37
+ <div class="tilegrid-controls">
38
+ <label class="tilegrid-checkbox-label">
39
+ <span>Show tile borders</span>
40
+ <input type="checkbox" id="tilegrid-borders-checkbox" checked onchange="tileGridManager.toggleBorders(this.checked)">
41
+ <span class="tilegrid-checkbox-custom"></span>
42
+ </label>
43
+ </div>
44
+ `;
45
+
46
+ document.getElementById('map-container').appendChild(this.panelContainer);
47
+ }
48
+
49
+ setupEventListeners() {
50
+ this.map.on('sourcedata', () => this.updateTileCount());
51
+ this.map.on('data', () => this.updateTileCount());
52
+ this.map.on('moveend', () => this.updateTileCount());
53
+ this.map.on('zoomend', () => this.updateTileCount());
54
+ }
55
+
56
+ startTileTracking() {
57
+ this.updateInterval = setInterval(() => {
58
+ if (this.isVisible) {
59
+ this.updateTileCount();
60
+ }
61
+ }, 1000);
62
+ }
63
+
64
+ updateTileCount() {
65
+ if (!this.map || !this.isVisible) return;
66
+
67
+ try {
68
+ const style = this.map.getStyle();
69
+ if (!style || !style.sources) return;
70
+
71
+ let totalTiles = 0;
72
+
73
+ // Count tiles from all raster and vector sources
74
+ Object.keys(style.sources).forEach(sourceName => {
75
+ const sourceCache = this.map.style?.sourceCaches?.[sourceName];
76
+ if (sourceCache) {
77
+ const tiles = sourceCache.getVisibleCoordinates?.() || [];
78
+ totalTiles += tiles.length;
79
+ }
80
+ });
81
+
82
+ // Fallback: estimate tiles based on zoom and viewport
83
+ if (totalTiles === 0) {
84
+ totalTiles = this.estimateTileCount();
85
+ }
86
+
87
+ this.tilesLoaded = totalTiles;
88
+ const countElement = document.getElementById('tilegrid-count');
89
+ if (countElement) {
90
+ countElement.textContent = this.tilesLoaded;
91
+ }
92
+ } catch (e) {
93
+ console.warn('TileGridManager: could not count tiles', e);
94
+ }
95
+ }
96
+
97
+ estimateTileCount() {
98
+ const bounds = this.map.getBounds();
99
+ const nw = this.map.project(bounds.getNorthWest());
100
+ const se = this.map.project(bounds.getSouthEast());
101
+
102
+ const viewportWidth = Math.abs(se.x - nw.x);
103
+ const viewportHeight = Math.abs(se.y - nw.y);
104
+
105
+ // Fallback estimation, assume standard 256px tiles
106
+ const tilesX = Math.ceil(viewportWidth / 256) + 1;
107
+ const tilesY = Math.ceil(viewportHeight / 256) + 1;
108
+
109
+ return tilesX * tilesY;
110
+ }
111
+
112
+ toggle() {
113
+ this.isVisible = !this.isVisible;
114
+
115
+ if (this.panelContainer) {
116
+ this.panelContainer.style.display = this.isVisible ? 'block' : 'none';
117
+ }
118
+
119
+ const btn = document.getElementById('tilegrid-mode-btn');
120
+ if (btn) {
121
+ btn.textContent = this.isVisible ? 'Hide Tile Grid' : 'Tile Grid';
122
+ btn.className = `control-button ${this.isVisible ? 'active' : ''}`;
123
+ }
124
+
125
+ if (this.isVisible) {
126
+ this.updateTileCount();
127
+ this.toggleBorders(true);
128
+ } else {
129
+ this.toggleBorders(false);
130
+ }
131
+ }
132
+
133
+ toggleBorders(show) {
134
+ this.showBorders = show;
135
+
136
+ if (this.map) {
137
+ this.map.showTileBoundaries = show;
138
+ }
139
+
140
+ // Update checkbox state
141
+ const checkbox = document.getElementById('tilegrid-borders-checkbox');
142
+ if (checkbox && checkbox.checked !== show) {
143
+ checkbox.checked = show;
144
+ }
145
+ }
146
+
147
+ show() {
148
+ if (!this.isVisible) {
149
+ this.toggle();
150
+ }
151
+ }
152
+
153
+ hide() {
154
+ if (this.isVisible) {
155
+ this.toggle();
156
+ }
157
+ }
158
+
159
+ cleanup() {
160
+ if (this.updateInterval) {
161
+ clearInterval(this.updateInterval);
162
+ this.updateInterval = null;
163
+ }
164
+
165
+ if (this.panelContainer && this.panelContainer.parentNode) {
166
+ this.panelContainer.parentNode.removeChild(this.panelContainer);
167
+ }
168
+
169
+ if (this.map) {
170
+ this.map.showTileBoundaries = false;
171
+ }
172
+ }
173
+ }
174
+
@@ -1,3 +1,3 @@
1
1
  module MapLibrePreview
2
- VERSION = '1.3.10'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -11,6 +11,7 @@ html
11
11
  script[src="https://d3js.org/d3.v#{MapLibrePreview::D3_VERSION}.min.js"]
12
12
  script[src='/js/filters.js']
13
13
  script[src='/js/contour.js']
14
+ script[src='/js/tilegrid.js']
14
15
  style
15
16
  | * { margin: 0; padding: 0; box-sizing: border-box; }
16
17
  | html { height: 100%; }
@@ -385,6 +386,62 @@ html
385
386
  | .version-info-version:hover {
386
387
  | color: #a9b7c6; text-decoration: none;
387
388
  | }
389
+ | /* TileGrid Panel Styles */
390
+ | .tilegrid-panel {
391
+ | position: fixed; top: 50%; right: 10px; transform: translateY(-50%); z-index: 1000;
392
+ | background: rgba(60, 63, 65, 0.95); border: 1px solid #555555;
393
+ | border-radius: 4px; padding: 12px; width: 200px;
394
+ | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
395
+ | }
396
+ | .tilegrid-header {
397
+ | display: flex; justify-content: space-between; align-items: center;
398
+ | margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid #555555;
399
+ | }
400
+ | .tilegrid-title {
401
+ | color: #ffc66d; font-weight: bold; font-size: 12px;
402
+ | }
403
+ | .tilegrid-close {
404
+ | background: none; border: none; color: #808080; cursor: pointer;
405
+ | font-size: 14px; padding: 0; width: 16px; height: 16px;
406
+ | display: flex; align-items: center; justify-content: center;
407
+ | border-radius: 2px; transition: all 0.2s ease;
408
+ | }
409
+ | .tilegrid-close:hover {
410
+ | background: #4b4d4f; color: #a9b7c6;
411
+ | }
412
+ | .tilegrid-stats {
413
+ | margin-bottom: 12px; padding: 10px; background: #313335; border-radius: 3px;
414
+ | border: 1px solid #464749;
415
+ | }
416
+ | .tilegrid-stat-label {
417
+ | color: #808080; font-size: 10px; font-weight: 500; letter-spacing: 0.5px;
418
+ | text-transform: uppercase; margin-bottom: 4px;
419
+ | }
420
+ | .tilegrid-stat-value {
421
+ | color: #6897bb; font-size: 28px; font-weight: bold; line-height: 1;
422
+ | font-family: 'Courier New', monospace;
423
+ | }
424
+ | .tilegrid-controls {
425
+ | padding-top: 8px; border-top: 1px solid #555555;
426
+ | }
427
+ | .tilegrid-checkbox-label {
428
+ | display: flex; align-items: center; justify-content: space-between;
429
+ | cursor: pointer; user-select: none; color: #a9b7c6; font-size: 11px;
430
+ | }
431
+ | .tilegrid-checkbox-label input[type="checkbox"] {
432
+ | display: none;
433
+ | }
434
+ | .tilegrid-checkbox-custom {
435
+ | width: 16px; height: 16px; border: 1px solid #555555; border-radius: 2px;
436
+ | display: flex; align-items: center; justify-content: center;
437
+ | transition: all 0.2s ease; background: #3c3f41;
438
+ | }
439
+ | .tilegrid-checkbox-label input[type="checkbox"]:checked + .tilegrid-checkbox-custom {
440
+ | background: #6a9955; border-color: #7bb366;
441
+ | }
442
+ | .tilegrid-checkbox-label input[type="checkbox"]:checked + .tilegrid-checkbox-custom::after {
443
+ | content: '✓'; color: white; font-size: 10px; font-weight: bold;
444
+ | }
388
445
  body
389
446
  .container
390
447
  == yield
@@ -18,6 +18,7 @@ ruby:
18
18
  button.control-button onclick="toggleHoverMode()" id="hover-mode-btn" Hover Mode
19
19
  button.control-button onclick="toggleProfileMode()" id="profile-mode-btn" style="display: none;" Elevation Profile
20
20
  button.control-button onclick="toggleAntialias()" id="antialias-btn" Antialias
21
+ button.control-button onclick="toggleTileGrid()" id="tilegrid-mode-btn" Tile Grid
21
22
 
22
23
  #filters-panel.control-panel.active
23
24
  .control-panel-header
@@ -91,6 +92,7 @@ javascript:
91
92
  let profileLine = null;
92
93
  let currentProfile = null;
93
94
  let contourManager = null;
95
+ let tileGridManager = null;
94
96
 
95
97
  const toDomId = (prefix, id) => `${prefix}-${String(id).replace(/[^a-zA-Z0-9_-]/g, '_')}`;
96
98
 
@@ -305,6 +307,16 @@ javascript:
305
307
  contourManager.init();
306
308
  };
307
309
 
310
+ const initializeTileGridManager = () => {
311
+ tileGridManager = new TileGridManager({map});
312
+ tileGridManager.init();
313
+ window.tileGridManager = tileGridManager;
314
+ };
315
+
316
+ const toggleTileGrid = () => {
317
+ tileGridManager?.toggle();
318
+ };
319
+
308
320
  const onStyleReady = () => {
309
321
  const hasTerrain = currentStyle?.terrain;
310
322
  const projectionType = hasTerrain ? 'mercator' : 'globe';
@@ -330,6 +342,7 @@ javascript:
330
342
  initializeContourManager();
331
343
  }
332
344
 
345
+ initializeTileGridManager();
333
346
  updateTerrainIndicator();
334
347
  };
335
348
 
@@ -880,5 +893,7 @@ javascript:
880
893
  window.toggleAntialias = toggleAntialias;
881
894
  window.toggleLayerControls = toggleLayerControls;
882
895
  window.hideProfile = hideProfile;
896
+ window.toggleTileGrid = toggleTileGrid;
897
+ window.tileGridManager = null;
883
898
 
884
899
  initializeMap();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maplibre-preview
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.10
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Ludov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-20 00:00:00.000000000 Z
11
+ date: 2025-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -183,6 +183,7 @@ files:
183
183
  - lib/maplibre-preview.rb
184
184
  - lib/maplibre-preview/public/js/contour.js
185
185
  - lib/maplibre-preview/public/js/filters.js
186
+ - lib/maplibre-preview/public/js/tilegrid.js
186
187
  - lib/maplibre-preview/version.rb
187
188
  - lib/maplibre-preview/views/maplibre_layout.slim
188
189
  - lib/maplibre-preview/views/maplibre_map.slim