edgarodriguez commited on
Commit
1a1c877
·
verified ·
1 Parent(s): 1b84e66

Upload 2 files

Browse files
Files changed (2) hide show
  1. depth_interactive_map_alpha.R +116 -4
  2. styles.css +40 -0
depth_interactive_map_alpha.R CHANGED
@@ -864,6 +864,11 @@ WEB_SPEC <- list(
864
  # --- Lucide icons + JS helpers --------------------------------------------------
865
  LUCIDE_JS <- tags$head(
866
  tags$script(src = "https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"),
 
 
 
 
 
867
  tags$script(HTML("
868
  // gridMenuOpen = is the N4-N8 resolution menu visible (purely visual);
869
  // gridActive = is the grid overlay currently shown on the map.
@@ -910,6 +915,13 @@ LUCIDE_JS <- tags$head(
910
  Shiny.setInputValue('grid_nivel', '6', { priority: 'event' });
911
  }, 300);
912
 
 
 
 
 
 
 
 
913
  // Hook up the native draw buttons so our custom ones can mirror their
914
  // active state. Retries until mapgl has mounted the draw control.
915
  var navTries = 0;
@@ -955,6 +967,99 @@ LUCIDE_JS <- tags$head(
955
  if (tip) tip.style.display = 'none';
956
  }
957
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
958
  function clearDrawing() {
959
  var btn = document.getElementById('clear_btn');
960
  if (btn) btn.click();
@@ -1862,10 +1967,10 @@ ui <- page_fillable(
1862
  class = "grid-nivel-item",
1863
  `data-nivel` = nv,
1864
  onclick = paste0("setGridNivel('", nv, "')"),
1865
- `aria-label` = paste0("Set grid to ", info$name, ", ", info$size, " squared, ", info$desc),
1866
  div(class = "grid-nivel-item-row",
1867
  span(class = "grid-nivel-item-name", paste0("N", nv, " ", info$name)),
1868
- span(class = "grid-nivel-item-size", paste0(info$size, "²"))),
1869
  div(class = "grid-nivel-item-desc", info$desc)
1870
  )
1871
  })
@@ -1876,7 +1981,7 @@ ui <- page_fillable(
1876
  title = "Coming soon",
1877
  div(class = "grid-nivel-item-row",
1878
  span(class = "grid-nivel-item-name", paste0("N", nv)),
1879
- span(class = "grid-nivel-item-size", "~0.8 km²")),
1880
  div(class = "grid-nivel-item-desc", "High resolution")))
1881
  )
1882
  ),
@@ -1907,7 +2012,14 @@ ui <- page_fillable(
1907
  actionButton("toggle_3d", class = "nav-btn",
1908
  `aria-label` = "Toggle 2D / 3D view",
1909
  title = "Toggle 2D / 3D",
1910
- HTML('<i data-lucide="box" style="width:16px;height:16px;stroke-width:2"></i>'))
 
 
 
 
 
 
 
1911
  ),
1912
 
1913
  div(class = "nav-divider"),
 
864
  # --- Lucide icons + JS helpers --------------------------------------------------
865
  LUCIDE_JS <- tags$head(
866
  tags$script(src = "https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"),
867
+ # Driver.js -- guided spotlight tour (MIT). unpkg matches Lucide's origin so
868
+ # the same CSP allowlist covers it. Drives existing DOM elements; no R logic.
869
+ tags$link(rel = "stylesheet",
870
+ href = "https://unpkg.com/driver.js@1.3.1/dist/driver.css"),
871
+ tags$script(src = "https://unpkg.com/driver.js@1.3.1/dist/driver.js.iife.js"),
872
  tags$script(HTML("
873
  // gridMenuOpen = is the N4-N8 resolution menu visible (purely visual);
874
  // gridActive = is the grid overlay currently shown on the map.
 
915
  Shiny.setInputValue('grid_nivel', '6', { priority: 'event' });
916
  }, 300);
917
 
918
+ // First-visit auto-tour: wait for the map to settle, then run once.
919
+ try {
920
+ if (!localStorage.getItem('depth_tour_seen')) {
921
+ setTimeout(function() { if (window.startTour) window.startTour(); }, 1200);
922
+ }
923
+ } catch (e) {}
924
+
925
  // Hook up the native draw buttons so our custom ones can mirror their
926
  // active state. Retries until mapgl has mounted the draw control.
927
  var navTries = 0;
 
967
  if (tip) tip.style.display = 'none';
968
  }
969
 
970
+ // -- Guided spotlight tour (Driver.js) --------------------------------------
971
+ // Highlights the real controls one step at a time. Auto-runs once on first
972
+ // visit (localStorage flag); the nav '?' button replays it on demand.
973
+ // Some targets live in collapsed panels, so steps open them on enter and
974
+ // restore them on leave; onDestroyed guarantees nothing is left open.
975
+ var _tourLayersOpened = false;
976
+
977
+ function _isLayersOpen() {
978
+ var body = document.getElementById('layer-ctrl-body');
979
+ return !!(body && body.style.display !== 'none');
980
+ }
981
+ function _restoreLayers() {
982
+ if (_tourLayersOpened && _isLayersOpen()) toggleLayerPanel();
983
+ _tourLayersOpened = false;
984
+ }
985
+
986
+ function startTour() {
987
+ if (!window.driver || !window.driver.js) return;
988
+ var driver = window.driver.js.driver;
989
+
990
+ var d = driver({
991
+ showProgress: true,
992
+ allowClose: true,
993
+ overlayOpacity: 0.6,
994
+ nextBtnText: 'Next',
995
+ prevBtnText: 'Back',
996
+ doneBtnText: 'Done',
997
+ onDestroyed: function() {
998
+ _restoreLayers();
999
+ try { localStorage.setItem('depth_tour_seen', '1'); } catch (e) {}
1000
+ },
1001
+ steps: [
1002
+ { popover: {
1003
+ title: 'Welcome to DEPTH',
1004
+ description: 'An interactive map of migration risk in Mexico. This quick tour points out what each control does -- about 60 seconds. Use Next, or close it any time.'
1005
+ }},
1006
+ { element: '#nav-search-wrap', popover: {
1007
+ title: 'Search',
1008
+ description: 'Jump to a place, municipality, or exact coordinates (e.g. \"19.43,-99.13\").',
1009
+ side: 'bottom', align: 'start'
1010
+ }},
1011
+ { element: '#home_btn', popover: {
1012
+ title: 'Overview',
1013
+ description: 'Reset the map back to the full view of Mexico at any point.',
1014
+ side: 'bottom', align: 'end'
1015
+ }},
1016
+ { element: '#nav-tools-select', popover: {
1017
+ title: 'Select an area to analyse',
1018
+ description: 'Draw a lasso, box, circle or line -- or click a single municipality. The sidebar then summarises every indicator inside your selection.',
1019
+ side: 'bottom', align: 'center'
1020
+ }},
1021
+ { element: '#btn_state_filter', popover: {
1022
+ title: 'Filter by state',
1023
+ description: 'Restrict the analysis to one Mexican state.',
1024
+ side: 'bottom', align: 'center'
1025
+ }},
1026
+ { element: '#grid-icon-btn', popover: {
1027
+ title: 'Spatial grid',
1028
+ description: 'Overlay an equal-cell grid and switch resolution from N4 (national overview) to N7 (local detail). Grid colours follow the active layer.',
1029
+ side: 'bottom', align: 'center'
1030
+ }},
1031
+ { element: '.style-btn-wrap', popover: {
1032
+ title: 'Basemap',
1033
+ description: 'Switch the background map between light, dark, and a labelled style.',
1034
+ side: 'bottom', align: 'center'
1035
+ }},
1036
+ { element: '#toggle_3d', popover: {
1037
+ title: '2D / 3D',
1038
+ description: 'Tilt the map into a 3D perspective view.',
1039
+ side: 'bottom', align: 'end'
1040
+ }},
1041
+ { element: '#layer-ctrl-body', popover: {
1042
+ title: 'Data layers',
1043
+ description: 'Turn indicators on and off here. They are grouped into Hazards, Exposure and Vulnerability. Each layer has a short description and its own legend.',
1044
+ side: 'right', align: 'start'
1045
+ },
1046
+ onHighlightStarted: function() {
1047
+ if (!_isLayersOpen()) { toggleLayerPanel(); _tourLayersOpened = true; }
1048
+ },
1049
+ onDeselected: function() { _restoreLayers(); }
1050
+ },
1051
+ { element: '#panel-tmri', popover: {
1052
+ title: 'Analysis sidebar',
1053
+ description: 'Live totals, charts over time, and breakdowns for whatever you have selected -- plus a button to download the selection as an .xlsx spreadsheet.',
1054
+ side: 'left', align: 'start'
1055
+ }}
1056
+ ]
1057
+ });
1058
+
1059
+ d.drive();
1060
+ }
1061
+ window.startTour = startTour;
1062
+
1063
  function clearDrawing() {
1064
  var btn = document.getElementById('clear_btn');
1065
  if (btn) btn.click();
 
1967
  class = "grid-nivel-item",
1968
  `data-nivel` = nv,
1969
  onclick = paste0("setGridNivel('", nv, "')"),
1970
+ `aria-label` = paste0("Set grid to ", info$name, ", ", info$size, ", ", info$desc),
1971
  div(class = "grid-nivel-item-row",
1972
  span(class = "grid-nivel-item-name", paste0("N", nv, " ", info$name)),
1973
+ span(class = "grid-nivel-item-size", info$size)),
1974
  div(class = "grid-nivel-item-desc", info$desc)
1975
  )
1976
  })
 
1981
  title = "Coming soon",
1982
  div(class = "grid-nivel-item-row",
1983
  span(class = "grid-nivel-item-name", paste0("N", nv)),
1984
+ span(class = "grid-nivel-item-size", "~1.3 km cell length")),
1985
  div(class = "grid-nivel-item-desc", "High resolution")))
1986
  )
1987
  ),
 
2012
  actionButton("toggle_3d", class = "nav-btn",
2013
  `aria-label` = "Toggle 2D / 3D view",
2014
  title = "Toggle 2D / 3D",
2015
+ HTML('<i data-lucide="box" style="width:16px;height:16px;stroke-width:2"></i>')),
2016
+
2017
+ # Guided tour replay
2018
+ tags$button(class = "nav-btn", type = "button",
2019
+ onclick = "startTour()",
2020
+ `aria-label` = "Take a guided tour",
2021
+ title = "Take a guided tour",
2022
+ HTML('<i data-lucide="circle-help" style="width:16px;height:16px;stroke-width:2"></i>'))
2023
  ),
2024
 
2025
  div(class = "nav-divider"),
styles.css CHANGED
@@ -2389,3 +2389,43 @@ button.mapbox-gl-draw_uncombine { display: none !important; }
2389
  color: var(--c-text);
2390
  letter-spacing: -0.01em;
2391
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2389
  color: var(--c-text);
2390
  letter-spacing: -0.01em;
2391
  }
2392
+
2393
+ /* --- Guided tour (Driver.js) -------------------------------------------------
2394
+ Theme the spotlight popover to the DEPTH brand. Driver.js sets its own high
2395
+ z-index on the overlay/popover; we keep it above the maplibre canvas. */
2396
+ .driver-popover.depth-popover,
2397
+ .driver-popover {
2398
+ background: #fff;
2399
+ color: var(--c-text);
2400
+ border: 1px solid var(--c-border-str);
2401
+ border-radius: 10px;
2402
+ box-shadow: 0 10px 30px rgba(3, 36, 37, 0.18);
2403
+ max-width: 320px;
2404
+ }
2405
+ .driver-popover .driver-popover-title {
2406
+ font-weight: 700;
2407
+ color: var(--c-text);
2408
+ }
2409
+ .driver-popover .driver-popover-description {
2410
+ color: var(--c-text-mid);
2411
+ line-height: 1.45;
2412
+ }
2413
+ .driver-popover .driver-popover-progress-text {
2414
+ color: var(--c-text-dim);
2415
+ }
2416
+ .driver-popover .driver-popover-navigation-btns button {
2417
+ background: var(--c-accent);
2418
+ color: #fff;
2419
+ text-shadow: none;
2420
+ border: none;
2421
+ border-radius: 6px;
2422
+ font-weight: 600;
2423
+ }
2424
+ .driver-popover .driver-popover-navigation-btns button.driver-popover-prev-btn {
2425
+ background: transparent;
2426
+ color: var(--c-text-mid);
2427
+ border: 1px solid var(--c-border);
2428
+ }
2429
+ .driver-popover .driver-popover-close-btn {
2430
+ color: var(--c-text-dim);
2431
+ }