pretix-map 0.1.8__py3-none-any.whl → 0.1.9__py3-none-any.whl
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.
- {pretix_map-0.1.8.dist-info → pretix_map-0.1.9.dist-info}/METADATA +1 -1
- {pretix_map-0.1.8.dist-info → pretix_map-0.1.9.dist-info}/RECORD +9 -9
- pretix_mapplugin/__init__.py +1 -1
- pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js +28 -92
- pretix_mapplugin/templates/pretix_mapplugin/map_page.html +2 -2
- {pretix_map-0.1.8.dist-info → pretix_map-0.1.9.dist-info}/WHEEL +0 -0
- {pretix_map-0.1.8.dist-info → pretix_map-0.1.9.dist-info}/entry_points.txt +0 -0
- {pretix_map-0.1.8.dist-info → pretix_map-0.1.9.dist-info}/licenses/LICENSE +0 -0
- {pretix_map-0.1.8.dist-info → pretix_map-0.1.9.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pretix-map
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: An overview map of the catchment area of previous orders. Measured by postcode
|
|
5
5
|
Author-email: MarkenJaden <jjsch1410@gmail.com>
|
|
6
6
|
Maintainer-email: MarkenJaden <jjsch1410@gmail.com>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
pretix_map-0.1.
|
|
2
|
-
pretix_mapplugin/__init__.py,sha256=
|
|
1
|
+
pretix_map-0.1.9.dist-info/licenses/LICENSE,sha256=MNMHjIJIjeQzQboYGsgFSRTBUHctF603DDa8MgCNyAg,554
|
|
2
|
+
pretix_mapplugin/__init__.py,sha256=XIaxbMbyiP-L3kguR1GhxirFblTXiHR1lMfDVITvHUI,22
|
|
3
3
|
pretix_mapplugin/apps.py,sha256=QOo53Z6zX0yB-Rz6I92tAu051sP38hM2iJlP9sk2JEg,802
|
|
4
4
|
pretix_mapplugin/geocoding.py,sha256=N_JyjYU_JBouwE3oaL3G1wI5jAyezZzS5IBMgI_GdWQ,6053
|
|
5
5
|
pretix_mapplugin/models.py,sha256=u_px4eaKWbh1hnUb7bdBEIuJUnvsts1AJ5CMoWLeQO8,2677
|
|
@@ -22,7 +22,7 @@ pretix_mapplugin/migrations/0004_ordergeocodedata_success_level.py,sha256=Skl-dB
|
|
|
22
22
|
pretix_mapplugin/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
pretix_mapplugin/static/pretix_mapplugin/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
pretix_mapplugin/static/pretix_mapplugin/css/salesmap.css,sha256=HgKozvQjWTzxJV4ua1hT9PiDzrvUSWrMnYRUvTTj4aI,1870
|
|
25
|
-
pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js,sha256=
|
|
25
|
+
pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js,sha256=PhUEaF1JKzX0UDe2kafE1pc1WmM3yv9S_v4UkxaBw6g,32539
|
|
26
26
|
pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.Default.css,sha256=YSWCMtmNZNwqex4CEw1nQhvFub2lmU7vcCKP-XVwwXA,1287
|
|
27
27
|
pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.css,sha256=YU3qCpj_P06tdPBJGPax0bm6Q1wltfwjsho5TR4-TYc,872
|
|
28
28
|
pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-heat.js,sha256=65UqrlgGoRAnKfKRuriH3eeDrOhZgZo1SCenduc-SGo,5158
|
|
@@ -41,10 +41,10 @@ pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/marker-ic
|
|
|
41
41
|
pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/marker-icon.png,sha256=V0w6XMqF9BFAhbaEFZbWLwDXyJLHsD8oy_owHesdxDc,1466
|
|
42
42
|
pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/marker-shadow.png,sha256=Jk9cZAM58ELdcpBiz8BMF_jqDymIK1OOOEjtjxDttNo,618
|
|
43
43
|
pretix_mapplugin/templates/pretix_mapplugin/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
-
pretix_mapplugin/templates/pretix_mapplugin/map_page.html,sha256=
|
|
44
|
+
pretix_mapplugin/templates/pretix_mapplugin/map_page.html,sha256=Sl82ULQ6qtLgI2d0OtQEX83mCs4mODsDZjIp3_3-DTc,12566
|
|
45
45
|
pretix_mapplugin/templates/pretix_mapplugin/milestones.html,sha256=KamdrYmSmKgsy2-Pn-ChrYZf2Gel-iEA_vzOxRfR2sg,3080
|
|
46
|
-
pretix_map-0.1.
|
|
47
|
-
pretix_map-0.1.
|
|
48
|
-
pretix_map-0.1.
|
|
49
|
-
pretix_map-0.1.
|
|
50
|
-
pretix_map-0.1.
|
|
46
|
+
pretix_map-0.1.9.dist-info/METADATA,sha256=WFXQJiHPDUP5j7A1hQ_R0mE3hBfI_mzd5uGJwuZHu3E,3575
|
|
47
|
+
pretix_map-0.1.9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
48
|
+
pretix_map-0.1.9.dist-info/entry_points.txt,sha256=C3NAjeZHoCekafkLMCJynPcABRTK8AUprtQv7sUNDZs,137
|
|
49
|
+
pretix_map-0.1.9.dist-info/top_level.txt,sha256=CAtEnkgA73zE9Gadm5mjt1SpXHBPOS-QWP0dQVoNToE,17
|
|
50
|
+
pretix_map-0.1.9.dist-info/RECORD,,
|
pretix_mapplugin/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.9"
|
|
@@ -53,6 +53,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
53
53
|
compareLabel: document.getElementById('compare-map-label'),
|
|
54
54
|
mainLabel: document.getElementById('main-map-label'),
|
|
55
55
|
heatmapReset: document.getElementById('heatmap-reset-btn'),
|
|
56
|
+
timelineContainer: document.getElementById('timeline-controls'),
|
|
56
57
|
timeSlider: document.getElementById('timeline-slider'),
|
|
57
58
|
timeDisplay: document.getElementById('timeline-date-display'),
|
|
58
59
|
timePlayBtn: document.getElementById('timeline-play-btn'),
|
|
@@ -152,22 +153,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
152
153
|
sel.blurVal.textContent = sel.blurIn.value;
|
|
153
154
|
sel.maxZoomVal.textContent = sel.maxZoomIn.value;
|
|
154
155
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (heatmapLayerComp) {
|
|
164
|
-
heatmapLayerComp.setOptions({
|
|
165
|
-
radius: parseInt(sel.radiusIn.value),
|
|
166
|
-
blur: parseInt(sel.blurIn.value),
|
|
167
|
-
maxZoom: parseInt(sel.maxZoomIn.value),
|
|
168
|
-
minOpacity: 0.4
|
|
169
|
-
});
|
|
170
|
-
}
|
|
156
|
+
const opt = {
|
|
157
|
+
radius: parseInt(sel.radiusIn.value),
|
|
158
|
+
blur: parseInt(sel.blurIn.value),
|
|
159
|
+
maxZoom: parseInt(sel.maxZoomIn.value),
|
|
160
|
+
minOpacity: 0.4
|
|
161
|
+
};
|
|
162
|
+
if (heatmapLayer) heatmapLayer.setOptions(opt);
|
|
163
|
+
if (heatmapLayerComp) heatmapLayerComp.setOptions(opt);
|
|
171
164
|
};
|
|
172
165
|
[sel.radiusIn, sel.blurIn, sel.maxZoomIn].forEach(i => i.oninput = updateHeat);
|
|
173
166
|
sel.heatmapReset.onclick = () => {
|
|
@@ -180,8 +173,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
180
173
|
|
|
181
174
|
function switchDisplayMode(mode) {
|
|
182
175
|
currentDisplayMode = mode;
|
|
183
|
-
|
|
184
|
-
sel.
|
|
176
|
+
const isMap = (mode === 'map');
|
|
177
|
+
sel.map.style.display = isMap ? 'block' : 'none';
|
|
178
|
+
sel.mapSplitRoot.style.display = isMap ? 'flex' : 'none';
|
|
179
|
+
sel.timelineContainer.style.display = isMap ? 'block' : 'none';
|
|
185
180
|
sel.failedContainer.style.display = (mode === 'list' ? 'block' : 'none');
|
|
186
181
|
sel.analyticsView.style.display = (mode === 'stats' ? 'block' : 'none');
|
|
187
182
|
|
|
@@ -190,9 +185,11 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
190
185
|
sel.listToggle.textContent = (mode === 'list' ? 'Show Map' : 'Failed Orders');
|
|
191
186
|
sel.statsToggle.textContent = (mode === 'stats' ? 'Show Map' : 'Analytics View');
|
|
192
187
|
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
|
|
188
|
+
if (isMap) {
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
map.invalidateSize();
|
|
191
|
+
if (mapCompare) mapCompare.invalidateSize();
|
|
192
|
+
}, 50);
|
|
196
193
|
}
|
|
197
194
|
}
|
|
198
195
|
|
|
@@ -266,7 +263,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
266
263
|
const ctx = sel.timelineChart.getContext('2d');
|
|
267
264
|
if (charts.timeline) charts.timeline.destroy();
|
|
268
265
|
|
|
269
|
-
// Calculate counts per step from filteredData
|
|
270
266
|
const stepCounts = steps.map(ts => {
|
|
271
267
|
const nextTsIndex = steps.indexOf(ts) + 1;
|
|
272
268
|
const nextTs = nextTsIndex < steps.length ? steps[nextTsIndex] : Infinity;
|
|
@@ -289,10 +285,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
289
285
|
responsive: true,
|
|
290
286
|
maintainAspectRatio: false,
|
|
291
287
|
plugins: { legend: { display: false }, tooltip: { enabled: false } },
|
|
292
|
-
scales: {
|
|
293
|
-
x: { display: false },
|
|
294
|
-
y: { display: false, beginAtZero: true }
|
|
295
|
-
}
|
|
288
|
+
scales: { x: { display: false }, y: { display: false, beginAtZero: true } }
|
|
296
289
|
}
|
|
297
290
|
});
|
|
298
291
|
}
|
|
@@ -300,20 +293,13 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
300
293
|
function renderMilestoneMarkers(steps) {
|
|
301
294
|
if (!sel.timelineMarkers || !steps || steps.length === 0) return;
|
|
302
295
|
sel.timelineMarkers.innerHTML = '';
|
|
303
|
-
|
|
304
296
|
milestones.forEach(m => {
|
|
305
|
-
|
|
306
|
-
let closestIdx = -1;
|
|
307
|
-
let minDiff = Infinity;
|
|
297
|
+
let closestIdx = -1, minDiff = Infinity;
|
|
308
298
|
steps.forEach((ts, idx) => {
|
|
309
299
|
const diff = Math.abs(ts - m.ts);
|
|
310
|
-
if (diff < minDiff) {
|
|
311
|
-
minDiff = diff;
|
|
312
|
-
closestIdx = idx;
|
|
313
|
-
}
|
|
300
|
+
if (diff < minDiff) { minDiff = diff; closestIdx = idx; }
|
|
314
301
|
});
|
|
315
|
-
|
|
316
|
-
if (closestIdx !== -1 && minDiff < 86400000 * 2) { // Only show if close enough (2 days)
|
|
302
|
+
if (closestIdx !== -1 && minDiff < 86400000 * 2) {
|
|
317
303
|
const percent = (closestIdx / (steps.length - 1)) * 100;
|
|
318
304
|
const marker = document.createElement('div');
|
|
319
305
|
marker.className = 'timeline-milestone-marker';
|
|
@@ -324,7 +310,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
324
310
|
marker.style.height = '100%';
|
|
325
311
|
marker.style.background = '#d9534f';
|
|
326
312
|
marker.style.zIndex = '2';
|
|
327
|
-
|
|
328
313
|
const label = document.createElement('span');
|
|
329
314
|
label.textContent = m.label;
|
|
330
315
|
label.style.position = 'absolute';
|
|
@@ -334,7 +319,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
334
319
|
label.style.whiteSpace = 'nowrap';
|
|
335
320
|
label.style.background = 'rgba(255,255,255,0.7)';
|
|
336
321
|
label.style.padding = '0 2px';
|
|
337
|
-
|
|
338
322
|
marker.appendChild(label);
|
|
339
323
|
sel.timelineMarkers.appendChild(marker);
|
|
340
324
|
}
|
|
@@ -344,10 +328,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
344
328
|
function renderItemAvailability(steps) {
|
|
345
329
|
if (!sel.itemAvailList || !steps || steps.length === 0) return;
|
|
346
330
|
sel.itemAvailList.innerHTML = '';
|
|
347
|
-
|
|
348
|
-
const minTs = steps[0];
|
|
349
|
-
const maxTs = steps[steps.length - 1];
|
|
350
|
-
const range = maxTs - minTs;
|
|
331
|
+
const minTs = steps[0], maxTs = steps[steps.length - 1], range = maxTs - minTs;
|
|
351
332
|
|
|
352
333
|
Object.keys(itemAvailData).forEach(itemName => {
|
|
353
334
|
const d = itemAvailData[itemName];
|
|
@@ -379,7 +360,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
379
360
|
barContainer.style.borderRadius = '3px';
|
|
380
361
|
row.appendChild(barContainer);
|
|
381
362
|
|
|
382
|
-
// Planned availability (light grey bar)
|
|
383
363
|
if (availFrom || availUntil) {
|
|
384
364
|
const start = availFrom ? Math.max(availFrom, minTs) : minTs;
|
|
385
365
|
const end = availUntil ? Math.min(availUntil, maxTs) : maxTs;
|
|
@@ -393,12 +373,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
393
373
|
bar.style.height = '100%';
|
|
394
374
|
bar.style.background = '#ddd';
|
|
395
375
|
bar.style.borderRadius = '3px';
|
|
396
|
-
bar.title = `${itemName} (Configured Availability)`;
|
|
397
376
|
barContainer.appendChild(bar);
|
|
398
377
|
}
|
|
399
378
|
}
|
|
400
379
|
|
|
401
|
-
// Actual sales period (blue bar)
|
|
402
380
|
if (firstTs && lastTs) {
|
|
403
381
|
const start = Math.max(firstTs, minTs);
|
|
404
382
|
const end = Math.min(lastTs, maxTs);
|
|
@@ -413,11 +391,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
413
391
|
bar.style.background = '#36A2EB';
|
|
414
392
|
bar.style.borderRadius = '3px';
|
|
415
393
|
bar.style.zIndex = '1';
|
|
416
|
-
bar.title = `${itemName} (Actual Sales)`;
|
|
417
394
|
barContainer.appendChild(bar);
|
|
418
395
|
}
|
|
419
396
|
}
|
|
420
|
-
|
|
421
397
|
sel.itemAvailList.appendChild(row);
|
|
422
398
|
});
|
|
423
399
|
}
|
|
@@ -455,14 +431,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
455
431
|
function refreshLayers() {
|
|
456
432
|
if (!map) return;
|
|
457
433
|
|
|
458
|
-
// Remove old layers from both maps
|
|
459
434
|
[pinLayer, heatmapLayer, gridLayer].forEach(l => { if (l && map.hasLayer(l)) map.removeLayer(l); });
|
|
460
435
|
if (mapCompare) {
|
|
461
436
|
[pinLayerComp, heatmapLayerComp, gridLayerComp, eventMarkerLayerComp].forEach(l => { if (l && mapCompare.hasLayer(l)) mapCompare.removeLayer(l); });
|
|
462
437
|
}
|
|
463
438
|
if (comparisonLayer && map.hasLayer(comparisonLayer)) map.removeLayer(comparisonLayer);
|
|
464
439
|
|
|
465
|
-
// Check if split mode is needed (Comparison selected AND heatmap/grid view)
|
|
466
440
|
const isSplitNeeded = currentCompareSlug && (currentView === 'heatmap' || currentView === 'grid');
|
|
467
441
|
|
|
468
442
|
if (isSplitNeeded) {
|
|
@@ -477,14 +451,11 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
477
451
|
setTimeout(() => { map.invalidateSize(); }, 50);
|
|
478
452
|
}
|
|
479
453
|
|
|
480
|
-
// Create layers for main map
|
|
481
454
|
createPinLayer(); createHeatmapLayer(); createGridLayer();
|
|
482
455
|
|
|
483
|
-
// Create layers for comparison map if in split mode
|
|
484
456
|
if (isSplitNeeded) {
|
|
485
457
|
createPinLayer(true); createHeatmapLayer(true); createGridLayer(true);
|
|
486
458
|
} else if (currentCompareSlug && currentView === 'pins') {
|
|
487
|
-
// Pins comparison: Dots on the main map
|
|
488
459
|
const dots = compareData.map(l => l.lat ? L.circleMarker([l.lat, l.lon], { radius: 4, color: '#888', fillOpacity: 0.5 }).bindTooltip("Comparison Order") : null).filter(l => l);
|
|
489
460
|
comparisonLayer = L.layerGroup(dots);
|
|
490
461
|
}
|
|
@@ -495,7 +466,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
495
466
|
function createPinLayer(isCompare = false) {
|
|
496
467
|
const data = isCompare ? compareDisplayData : displayData;
|
|
497
468
|
if (data.length === 0) { if(isCompare) pinLayerComp = null; else pinLayer = null; return; }
|
|
498
|
-
|
|
499
469
|
const markers = data.map(loc => {
|
|
500
470
|
if (loc.lat == null) return null;
|
|
501
471
|
let icon = icons.blue;
|
|
@@ -506,7 +476,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
506
476
|
if (loc.order_url) m.on('click', () => window.open(loc.order_url, '_blank'));
|
|
507
477
|
return m;
|
|
508
478
|
}).filter(m => m !== null);
|
|
509
|
-
|
|
510
479
|
const layer = isClustering ? L.markerClusterGroup().addLayers(markers) : L.layerGroup(markers);
|
|
511
480
|
if (isCompare) pinLayerComp = layer; else pinLayer = layer;
|
|
512
481
|
}
|
|
@@ -514,7 +483,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
514
483
|
function createHeatmapLayer(isCompare = false) {
|
|
515
484
|
const data = isCompare ? compareDisplayData : displayData;
|
|
516
485
|
if (data.length === 0) { if(isCompare) heatmapLayerComp = null; else heatmapLayer = null; return; }
|
|
517
|
-
|
|
518
486
|
let maxRev = Math.max(...data.map(d => d.revenue || 0), 1);
|
|
519
487
|
const points = data.map(l => [l.lat, l.lon, isWeighted ? (l.revenue || 0) / maxRev : 1.0]);
|
|
520
488
|
const layer = L.heatLayer(points, {
|
|
@@ -529,11 +497,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
529
497
|
function createGridLayer(isCompare = false) {
|
|
530
498
|
const data = isCompare ? compareDisplayData : displayData;
|
|
531
499
|
if (data.length === 0) { if(isCompare) gridLayerComp = null; else gridLayer = null; return; }
|
|
532
|
-
|
|
533
500
|
const rawVal = parseInt(sel.gridSizeSlider.value);
|
|
534
501
|
const gridSize = 0.4 * Math.pow(rawVal / 100, 2);
|
|
535
502
|
sel.gridSizeVal.textContent = gridSize.toFixed(3);
|
|
536
|
-
|
|
537
503
|
const bins = {}; let maxVal = 0;
|
|
538
504
|
data.forEach(l => {
|
|
539
505
|
if (l.lat == null) return;
|
|
@@ -553,24 +519,16 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
553
519
|
|
|
554
520
|
function showCurrentView() {
|
|
555
521
|
if (!map) return;
|
|
556
|
-
|
|
557
|
-
// Main map view
|
|
558
522
|
if (currentView === 'pins' && pinLayer) map.addLayer(pinLayer);
|
|
559
523
|
else if (currentView === 'heatmap' && heatmapLayer) map.addLayer(heatmapLayer);
|
|
560
524
|
else if (currentView === 'grid' && gridLayer) map.addLayer(gridLayer);
|
|
561
|
-
|
|
562
|
-
// Control panel updates
|
|
563
525
|
sel.heatmapPanel.style.display = (currentView === 'heatmap' || currentView === 'grid' ? 'block' : 'none');
|
|
564
526
|
sel.heatmapControls.style.display = (currentView === 'heatmap' ? 'block' : 'none');
|
|
565
527
|
sel.gridControls.style.display = (currentView === 'grid' ? 'block' : 'none');
|
|
566
|
-
|
|
567
528
|
if (sel.clusterToggle) sel.clusterToggle.style.display = (currentView === 'pins' ? 'inline-block' : 'none');
|
|
568
529
|
if (eventMarkerLayer) map.addLayer(eventMarkerLayer);
|
|
569
|
-
|
|
570
|
-
// Dot comparison on main map
|
|
571
530
|
if (comparisonLayer && currentView === 'pins') map.addLayer(comparisonLayer);
|
|
572
531
|
|
|
573
|
-
// Comparison map view (Split mode)
|
|
574
532
|
if (mapCompare && sel.mapSplitRoot.classList.contains('map-split-active')) {
|
|
575
533
|
if (currentView === 'pins' && pinLayerComp) mapCompare.addLayer(pinLayerComp);
|
|
576
534
|
else if (currentView === 'heatmap' && heatmapLayerComp) mapCompare.addLayer(heatmapLayerComp);
|
|
@@ -582,10 +540,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
582
540
|
function renderEventMarker(em, isCompare = false) {
|
|
583
541
|
const layer = L.marker([em.lat, em.lon], { icon: icons.red, zIndexOffset: 2000 }).bindTooltip(`<strong>EVENT: ${em.name}</strong><br>${em.location}`);
|
|
584
542
|
if (isCompare) {
|
|
585
|
-
if (eventMarkerLayerComp
|
|
543
|
+
if (eventMarkerLayerComp) mapCompare.removeLayer(eventMarkerLayerComp);
|
|
586
544
|
eventMarkerLayerComp = layer.addTo(mapCompare);
|
|
587
545
|
} else {
|
|
588
|
-
if (eventMarkerLayer
|
|
546
|
+
if (eventMarkerLayer) map.removeLayer(eventMarkerLayer);
|
|
589
547
|
eventMarkerLayer = layer.addTo(map);
|
|
590
548
|
}
|
|
591
549
|
}
|
|
@@ -597,18 +555,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
597
555
|
sel.compareLabel.textContent = "";
|
|
598
556
|
refreshLayers(); return;
|
|
599
557
|
}
|
|
600
|
-
|
|
601
558
|
const option = sel.compareSelect.options[sel.compareSelect.selectedIndex];
|
|
602
559
|
sel.compareLabel.textContent = option.text;
|
|
603
|
-
|
|
604
560
|
const newUrl = sel.map.dataset.dataUrl.replace(/\/event\/([^\/]+)\/([^\/]+)\//, `/event/$1/${slug}/`);
|
|
605
561
|
fetch(newUrl).then(r => r.json()).then(data => {
|
|
606
562
|
compareData = (data.locations || []).map(loc => { loc.ts = loc.date ? new Date(loc.date).getTime() : 0; return loc; }).sort((a, b) => a.ts - b.ts);
|
|
607
|
-
|
|
608
|
-
// Handle event marker for comparison map
|
|
609
563
|
if (data.event_marker) renderEventMarker(data.event_marker, true);
|
|
610
|
-
|
|
611
|
-
// Sync filters for comparison data
|
|
612
564
|
applyFilters();
|
|
613
565
|
});
|
|
614
566
|
}
|
|
@@ -626,12 +578,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
626
578
|
function applyFilters() {
|
|
627
579
|
showCanceled = sel.showCanceledCheck.checked;
|
|
628
580
|
const filterFn = loc => (loc.items.length === 0 || loc.items.some(i => selectedItems.has(i))) && (showCanceled || loc.status !== 'canceled');
|
|
629
|
-
|
|
630
581
|
filteredData = allData.filter(filterFn);
|
|
631
|
-
if (compareData.length > 0)
|
|
632
|
-
compareFilteredData = compareData.filter(filterFn);
|
|
633
|
-
}
|
|
634
|
-
|
|
582
|
+
if (compareData.length > 0) compareFilteredData = compareData.filter(filterFn);
|
|
635
583
|
updateTimelineSlider();
|
|
636
584
|
}
|
|
637
585
|
|
|
@@ -641,20 +589,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
641
589
|
let statusBadge = `<span class="label label-danger">Failed</span>`;
|
|
642
590
|
if (o.success_level === 'city') statusBadge = `<span class="label label-warning">Only City</span>`;
|
|
643
591
|
else if (o.success_level === 'zip') statusBadge = `<span class="label label-info">Only Zip</span>`;
|
|
644
|
-
|
|
645
|
-
return `<tr>
|
|
646
|
-
<td><code>${o.code}</code></td>
|
|
647
|
-
<td>${o.address}</td>
|
|
648
|
-
<td>${statusBadge}</td>
|
|
649
|
-
<td>
|
|
650
|
-
<div class="btn-group">
|
|
651
|
-
<a href="${o.url}" target="_blank" class="btn btn-default btn-xs">View</a>
|
|
652
|
-
<button class="btn btn-warning btn-xs retry-btn" data-url="${o.retry_url}">Retry</button>
|
|
653
|
-
</div>
|
|
654
|
-
</td>
|
|
655
|
-
</tr>`;
|
|
592
|
+
return `<tr><td><code>${o.code}</code></td><td>${o.address}</td><td>${statusBadge}</td><td><div class="btn-group"><a href="${o.url}" target="_blank" class="btn btn-default btn-xs">View</a><button class="btn btn-warning btn-xs retry-btn" data-url="${o.retry_url}">Retry</button></div></td></tr>`;
|
|
656
593
|
}).join('') || '<tr><td colspan="4">None</td></tr>';
|
|
657
|
-
|
|
658
594
|
sel.failedTbody.querySelectorAll('.retry-btn').forEach(btn => btn.onclick = () => {
|
|
659
595
|
btn.disabled = true; btn.innerHTML = '...';
|
|
660
596
|
fetch(btn.dataset.url, { method: 'POST', headers: { 'X-CSRFToken': csrfToken } }).then(r => r.json()).then(d => { if(d.success) { btn.className = 'btn btn-success btn-xs'; btn.innerHTML = '✔'; setTimeout(() => fetchData(sel.map.dataset.dataUrl), 1000); } });
|
|
@@ -662,4 +598,4 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
|
662
598
|
}
|
|
663
599
|
|
|
664
600
|
init();
|
|
665
|
-
});
|
|
601
|
+
});
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
</div>
|
|
152
152
|
</div>
|
|
153
153
|
|
|
154
|
-
<div id="timeline-controls" style="margin-top: 10px; padding: 15px; background: #f5f5f5; border-radius: 4px; border: 1px solid #ddd; position: relative;">
|
|
154
|
+
<div id="timeline-controls" style="margin-top: 10px; padding: 15px; background: #f5f5f5; border-radius: 4px; border: 1px solid #ddd; position: relative; flex-shrink: 0;">
|
|
155
155
|
<div id="timeline-chart-container" style="position: relative; height: 50px; margin-bottom: 10px; background: white; border: 1px solid #eee; overflow: hidden;">
|
|
156
156
|
<canvas id="timeline-volume-chart" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
|
157
157
|
<div id="timeline-milestone-markers" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;"></div>
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
</div>
|
|
165
165
|
</div>
|
|
166
166
|
|
|
167
|
-
<div id="timeline-item-availability" style="margin-top: 10px; background: white; border: 1px solid #eee; padding: 10px 0;">
|
|
167
|
+
<div id="timeline-item-availability" style="margin-top: 10px; background: white; border: 1px solid #eee; padding: 10px 0; max-height: 150px; overflow-y: auto;">
|
|
168
168
|
<div id="item-availability-list" style="position: relative; padding: 0 5px;"></div>
|
|
169
169
|
</div>
|
|
170
170
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|