edgarodriguez commited on
Commit
040cdee
·
verified ·
1 Parent(s): 1fc4cdd

Upload 2 files

Browse files
Files changed (2) hide show
  1. depth_interactive_map_alpha.R +130 -19
  2. styles.css +31 -0
depth_interactive_map_alpha.R CHANGED
@@ -917,12 +917,12 @@ WEB_SPEC <- list(
917
  list(id = "pop-choro", type = "fill", src = "src_pop_mun",
918
  geom = "polygon", color = "pop_qstep", value = "pobtot",
919
  opacity = 0.7, visible = FALSE),
920
- # patp-choro and pobreza-choro are also GRID-ONLY (joined into grid_unified)
921
- list(id = "patp-choro", type = "fill", src = NULL,
922
- geom = "grid_only", color = "patp_qstep", value = "t_part",
923
  opacity = 0.7, visible = FALSE, requires = "dim_patp_mun"),
924
- list(id = "pobreza-choro", type = "fill", src = NULL,
925
- geom = "grid_only", color = "pobreza_qstep", value = "pobreza_pct",
926
  opacity = 0.7, visible = FALSE, requires = "dim_pobreza_mun"),
927
  list(id = "fosas-choro", type = "fill", src = "src_fosas",
928
  geom = "polygon", color = "fosas_step", value = "fosas_total",
@@ -1021,8 +1021,14 @@ WEB_SPEC <- list(
1021
  legend = list(type = "cats", pal = "infra_cats", filterable = "infra")),
1022
  list(kind = "layer", value = "patp-choro",
1023
  label = "PATP-CONEVAL municipal indicators",
1024
- tooltip = "Multi-dimensional CONEVAL PATP indicators by municipality. Numeric sub-types render as a percentile choropleth; categorical sub-types (rural problem / crime focus) render with a fixed palette. Enable the grid view to see this layer.",
1025
- legend = list(type = "ramp", pal = "patp", unit = "")),
 
 
 
 
 
 
1026
  list(kind = "radios", group = "patp"),
1027
  list(kind = "layer", value = "pobreza-choro",
1028
  label = "Poverty (CONEVAL 2020)",
@@ -1353,14 +1359,59 @@ LUCIDE_JS <- tags$head(
1353
  });
1354
  // Sync legend visibility: use class so CSS controls display type per legend shape
1355
  document.querySelectorAll('.acc-item-wrap').forEach(function(wrap) {
1356
- var input = wrap.querySelector('.acc-toggle-input');
1357
- var legend = wrap.querySelector('.acc-legend');
1358
- if (legend) legend.classList.toggle('legend-visible', !!(input && input.checked));
 
 
 
 
 
1359
  });
 
 
1360
  if (typeof Shiny !== 'undefined')
1361
  Shiny.setInputValue('active_layers', checked, { priority: 'event' });
1362
  }
1363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1364
  function setCrimeType(type) {
1365
  if (typeof Shiny !== 'undefined')
1366
  Shiny.setInputValue('crime_type', type, { priority: 'event' });
@@ -1399,6 +1450,8 @@ LUCIDE_JS <- tags$head(
1399
  document.querySelectorAll('.patp-radio').forEach(function(r) {
1400
  r.classList.toggle('active', r.dataset.value === type);
1401
  });
 
 
1402
  }
1403
 
1404
  function setPobrezaType(type) {
@@ -1407,6 +1460,8 @@ LUCIDE_JS <- tags$head(
1407
  document.querySelectorAll('.pobreza-radio').forEach(function(r) {
1408
  r.classList.toggle('active', r.dataset.value === type);
1409
  });
 
 
1410
  }
1411
 
1412
  function toggleStylePicker() {
@@ -1809,7 +1864,8 @@ acc_group <- function(id, label, items_list, open = TRUE) {
1809
  )
1810
  }
1811
 
1812
- acc_layer <- function(value, label, tooltip = NULL, legend = NULL, checked = FALSE) {
 
1813
  div(class = "acc-item-wrap",
1814
  div(class = "acc-item",
1815
  tags$label(class = "acc-toggle-label",
@@ -1834,10 +1890,29 @@ acc_layer <- function(value, label, tooltip = NULL, legend = NULL, checked = FAL
1834
  HTML('<i data-lucide="info" style="width:12px;height:12px;stroke-width:2.5;color:var(--c-text-mid)"></i>')
1835
  )
1836
  ),
1837
- if (!is.null(legend)) legend
 
1838
  )
1839
  }
1840
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1841
  acc_legend_ramp <- function(pal, lo = "Low", hi = "High") {
1842
  stops <- paste(pal, collapse = ", ")
1843
  HTML(paste0(
@@ -2073,9 +2148,12 @@ render_accordion <- function() {
2073
  soon = acc_soon_item(it$label),
2074
  radios = acc_radios_from_spec(it$group),
2075
  layer = acc_layer(it$value, it$label,
2076
- tooltip = it$tooltip,
2077
- legend = acc_legend_from_spec(it$legend),
2078
- checked = isTRUE(it$checked))
 
 
 
2079
  )
2080
  })
2081
  acc_group(grp$id, grp$label, tagList(items), open = isTRUE(grp$open))
@@ -2614,7 +2692,7 @@ server <- function(input, output, session) {
2614
  state = FALSE, routes = FALSE, via = FALSE,
2615
  migrants = FALSE, graves = FALSE, infra = FALSE,
2616
  ocved = FALSE, ged = FALSE,
2617
- pop = FALSE,
2618
  grid4 = FALSE, grid5 = FALSE, grid6 = FALSE
2619
  )
2620
 
@@ -2802,9 +2880,8 @@ server <- function(input, output, session) {
2802
  "remesas-choro" = isTRUE(lazy_added$remesas),
2803
  "pam-choro" = isTRUE(lazy_added$pam),
2804
  "pop-choro" = isTRUE(lazy_added$pop),
2805
- # patp / pobreza remain grid-only -- no mun-level layer to gate.
2806
- "patp-choro" = FALSE,
2807
- "pobreza-choro" = FALSE,
2808
  "fosas-choro" = isTRUE(lazy_added$fosas),
2809
  "envipe-state" = isTRUE(lazy_added$state),
2810
  "routes-lines" = isTRUE(lazy_added$routes),
@@ -2863,6 +2940,23 @@ server <- function(input, output, session) {
2863
  )
2864
  }
2865
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2866
  for (lid in NON_GRID_LAYERS) {
2867
  if (!layer_ready(lid)) next
2868
  prx <- prx |> set_layout_property(
@@ -3524,6 +3618,23 @@ server <- function(input, output, session) {
3524
  "<br>Total pop (CPV): ", list("to-string", list("get","pobtot")),
3525
  "<br>Born abroad: ", list("to-string", list("get","pnacop")),
3526
  "<br>Resident abroad 2015: ", list("to-string", list("get","presop2015")))))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3527
  if (!grid_on && "fosas-choro" %in% active && has_fosas_tbl)
3528
  lazy_add_fill("fosas", "src_fosas", "fosas-choro", function(prx, d)
3529
  prx |> add_fill_layer("fosas-choro", source = d,
 
917
  list(id = "pop-choro", type = "fill", src = "src_pop_mun",
918
  geom = "polygon", color = "pop_qstep", value = "pobtot",
919
  opacity = 0.7, visible = FALSE),
920
+ # patp-choro and pobreza-choro paint in BOTH modes (mun-level + per-cell)
921
+ list(id = "patp-choro", type = "fill", src = "src_patp",
922
+ geom = "polygon", color = "patp_qstep", value = "t_part",
923
  opacity = 0.7, visible = FALSE, requires = "dim_patp_mun"),
924
+ list(id = "pobreza-choro", type = "fill", src = "src_pobreza",
925
+ geom = "polygon", color = "pobreza_qstep", value = "pobreza_pct",
926
  opacity = 0.7, visible = FALSE, requires = "dim_pobreza_mun"),
927
  list(id = "fosas-choro", type = "fill", src = "src_fosas",
928
  geom = "polygon", color = "fosas_step", value = "fosas_total",
 
1021
  legend = list(type = "cats", pal = "infra_cats", filterable = "infra")),
1022
  list(kind = "layer", value = "patp-choro",
1023
  label = "PATP-CONEVAL municipal indicators",
1024
+ tooltip = "Multi-dimensional CONEVAL PATP indicators. Numeric chips render as percentile choropleths; categorical chips (rural problem / crime focus) render with a fixed palette. Works both at municipal level and on the grid.",
1025
+ legend = list(type = "ramp", pal = "patp", unit = ""),
1026
+ # Variant legends shown when the matching categorical chip is active.
1027
+ # data-variant-key on each wrap is matched by setPATPType in JS.
1028
+ legend_extras = list(
1029
+ pr_pred_loc_rur = list(type = "cats", pal = "patp_rural"),
1030
+ delitos_fc_b_j_a = list(type = "cats", pal = "patp_delito")
1031
+ )),
1032
  list(kind = "radios", group = "patp"),
1033
  list(kind = "layer", value = "pobreza-choro",
1034
  label = "Poverty (CONEVAL 2020)",
 
1359
  });
1360
  // Sync legend visibility: use class so CSS controls display type per legend shape
1361
  document.querySelectorAll('.acc-item-wrap').forEach(function(wrap) {
1362
+ var input = wrap.querySelector('.acc-toggle-input');
1363
+ var isOn = !!(input && input.checked);
1364
+ var primary = wrap.querySelector(':scope > .acc-legend');
1365
+ if (primary) primary.classList.toggle('legend-visible', isOn);
1366
+ // Variant legends (categorical chips) -- gate visibility on toggle ON
1367
+ wrap.querySelectorAll(':scope > .acc-legend-extra').forEach(function(v) {
1368
+ v.classList.toggle('legend-visible', isOn);
1369
+ });
1370
  });
1371
+ // Re-apply the active-variant marker so the right extras stay visible.
1372
+ if (typeof refreshLegendVariants === 'function') refreshLegendVariants();
1373
  if (typeof Shiny !== 'undefined')
1374
  Shiny.setInputValue('active_layers', checked, { priority: 'event' });
1375
  }
1376
 
1377
+ // Selects which legend variant is visible for each layer family. Called
1378
+ // by setPATPType / setPobrezaType after they update window state, and
1379
+ // also by updateActiveLayers when the layer toggle flips.
1380
+ var _activeVariants = { patp: 'numeric', pobreza: 'numeric' };
1381
+ var PATP_NUMERIC = ['t_part','t_ocup','pr','ind_conec'];
1382
+ var POBREZA_NUMERIC = ['pobreza_pct','pobreza_ext_pct'];
1383
+
1384
+ function _variantKeyFor(group, type) {
1385
+ if (group === 'patp') return PATP_NUMERIC.indexOf(type) !== -1 ? 'numeric' : type;
1386
+ if (group === 'pobreza') return POBREZA_NUMERIC.indexOf(type) !== -1 ? 'numeric' : type;
1387
+ return type;
1388
+ }
1389
+
1390
+ function refreshLegendVariants() {
1391
+ ['patp','pobreza'].forEach(function(group) {
1392
+ var key = _activeVariants[group] || 'numeric';
1393
+ // Primary legend stays visible when the active key is 'numeric'.
1394
+ document.querySelectorAll(
1395
+ '.acc-item-wrap > .acc-legend:not(.acc-legend-extra)'
1396
+ ).forEach(function(primary) {
1397
+ var wrap = primary.parentElement;
1398
+ if (!wrap) return;
1399
+ var extras = wrap.querySelectorAll('.acc-legend-extra[data-variant-group=\"' + group + '\"]');
1400
+ if (!extras.length) return; // Not a variant-bearing layer
1401
+ primary.classList.toggle('acc-legend-hidden-by-variant', key !== 'numeric');
1402
+ });
1403
+ // Each extra is marked is-active-variant only if its key matches.
1404
+ document.querySelectorAll(
1405
+ '.acc-legend-extra[data-variant-group=\"' + group + '\"]'
1406
+ ).forEach(function(extra) {
1407
+ extra.classList.toggle(
1408
+ 'is-active-variant',
1409
+ extra.dataset.variantKey === key
1410
+ );
1411
+ });
1412
+ });
1413
+ }
1414
+
1415
  function setCrimeType(type) {
1416
  if (typeof Shiny !== 'undefined')
1417
  Shiny.setInputValue('crime_type', type, { priority: 'event' });
 
1450
  document.querySelectorAll('.patp-radio').forEach(function(r) {
1451
  r.classList.toggle('active', r.dataset.value === type);
1452
  });
1453
+ _activeVariants.patp = _variantKeyFor('patp', type);
1454
+ refreshLegendVariants();
1455
  }
1456
 
1457
  function setPobrezaType(type) {
 
1460
  document.querySelectorAll('.pobreza-radio').forEach(function(r) {
1461
  r.classList.toggle('active', r.dataset.value === type);
1462
  });
1463
+ _activeVariants.pobreza = _variantKeyFor('pobreza', type);
1464
+ refreshLegendVariants();
1465
  }
1466
 
1467
  function toggleStylePicker() {
 
1864
  )
1865
  }
1866
 
1867
+ acc_layer <- function(value, label, tooltip = NULL, legend = NULL, checked = FALSE,
1868
+ legend_extras = NULL) {
1869
  div(class = "acc-item-wrap",
1870
  div(class = "acc-item",
1871
  tags$label(class = "acc-toggle-label",
 
1890
  HTML('<i data-lucide="info" style="width:12px;height:12px;stroke-width:2.5;color:var(--c-text-mid)"></i>')
1891
  )
1892
  ),
1893
+ if (!is.null(legend)) legend,
1894
+ if (!is.null(legend_extras)) legend_extras
1895
  )
1896
  }
1897
 
1898
+ # Renders zero or more "variant" legends -- shown when a categorical sub-type
1899
+ # chip is active. Each wrapper carries data-variant-group (the layer family,
1900
+ # e.g. "patp") and data-variant-key (the sub-type identifier). The matching JS
1901
+ # setPATPType / setPobrezaType swaps which one is visible.
1902
+ acc_legend_extras_from_spec <- function(extras, group) {
1903
+ if (is.null(extras) || length(extras) == 0) return(NULL)
1904
+ tagList(lapply(names(extras), function(key) {
1905
+ inner <- acc_legend_from_spec(extras[[key]])
1906
+ if (is.null(inner)) return(NULL)
1907
+ tags$div(
1908
+ class = "acc-legend-extra",
1909
+ `data-variant-group` = group,
1910
+ `data-variant-key` = key,
1911
+ inner
1912
+ )
1913
+ }))
1914
+ }
1915
+
1916
  acc_legend_ramp <- function(pal, lo = "Low", hi = "High") {
1917
  stops <- paste(pal, collapse = ", ")
1918
  HTML(paste0(
 
2148
  soon = acc_soon_item(it$label),
2149
  radios = acc_radios_from_spec(it$group),
2150
  layer = acc_layer(it$value, it$label,
2151
+ tooltip = it$tooltip,
2152
+ legend = acc_legend_from_spec(it$legend),
2153
+ legend_extras = acc_legend_extras_from_spec(
2154
+ it$legend_extras,
2155
+ group = sub("-.*", "", it$value %||% "")),
2156
+ checked = isTRUE(it$checked))
2157
  )
2158
  })
2159
  acc_group(grp$id, grp$label, tagList(items), open = isTRUE(grp$open))
 
2692
  state = FALSE, routes = FALSE, via = FALSE,
2693
  migrants = FALSE, graves = FALSE, infra = FALSE,
2694
  ocved = FALSE, ged = FALSE,
2695
+ pop = FALSE, patp = FALSE, pobreza = FALSE,
2696
  grid4 = FALSE, grid5 = FALSE, grid6 = FALSE
2697
  )
2698
 
 
2880
  "remesas-choro" = isTRUE(lazy_added$remesas),
2881
  "pam-choro" = isTRUE(lazy_added$pam),
2882
  "pop-choro" = isTRUE(lazy_added$pop),
2883
+ "patp-choro" = isTRUE(lazy_added$patp),
2884
+ "pobreza-choro" = isTRUE(lazy_added$pobreza),
 
2885
  "fosas-choro" = isTRUE(lazy_added$fosas),
2886
  "envipe-state" = isTRUE(lazy_added$state),
2887
  "routes-lines" = isTRUE(lazy_added$routes),
 
2940
  )
2941
  }
2942
 
2943
+ # Sync patp fill color when grid is OFF. Mun-level src_patp has all 6
2944
+ # sub-type columns; patp_grid_expr picks step (numeric) or match (cat).
2945
+ if (!grid_on && "patp-choro" %in% active && layer_ready("patp-choro")) {
2946
+ prx <- prx |> set_paint_property(
2947
+ "patp-choro", "fill-color",
2948
+ patp_grid_expr(patp_type)
2949
+ )
2950
+ }
2951
+
2952
+ # Sync pobreza fill color when grid is OFF.
2953
+ if (!grid_on && "pobreza-choro" %in% active && layer_ready("pobreza-choro")) {
2954
+ prx <- prx |> set_paint_property(
2955
+ "pobreza-choro", "fill-color",
2956
+ pobreza_grid_expr(pobreza_type)
2957
+ )
2958
+ }
2959
+
2960
  for (lid in NON_GRID_LAYERS) {
2961
  if (!layer_ready(lid)) next
2962
  prx <- prx |> set_layout_property(
 
3618
  "<br>Total pop (CPV): ", list("to-string", list("get","pobtot")),
3619
  "<br>Born abroad: ", list("to-string", list("get","pnacop")),
3620
  "<br>Resident abroad 2015: ", list("to-string", list("get","presop2015")))))
3621
+ if (!grid_on && "patp-choro" %in% active && has_patp_tbl)
3622
+ lazy_add_fill("patp", "src_patp", "patp-choro", function(prx, d)
3623
+ prx |> add_fill_layer("patp-choro", source = d,
3624
+ fill_color = patp_grid_expr("t_part"), fill_opacity = 0.7,
3625
+ tooltip = list("concat", "<b>", list("get","municipio"), "</b>",
3626
+ "<br>Participation: ", list("to-string", list("get","t_part")), "%",
3627
+ "<br>Occupation: ", list("to-string", list("get","t_ocup")), "%",
3628
+ "<br>Connectivity: ", list("to-string", list("get","ind_conec")),
3629
+ "<br>Rural problem: ", list("get","pr_pred_loc_rur"),
3630
+ "<br>Crime focus: ", list("get","delitos_fc_b_j_a"))))
3631
+ if (!grid_on && "pobreza-choro" %in% active && has_pobreza_tbl)
3632
+ lazy_add_fill("pobreza", "src_pobreza", "pobreza-choro", function(prx, d)
3633
+ prx |> add_fill_layer("pobreza-choro", source = d,
3634
+ fill_color = pobreza_grid_expr("pobreza_pct"), fill_opacity = 0.7,
3635
+ tooltip = list("concat", "<b>", list("get","municipio"), "</b>",
3636
+ "<br>Poverty: ", list("to-string", list("get","pobreza_pct")), "%",
3637
+ "<br>Extreme poverty: ", list("to-string", list("get","pobreza_ext_pct")), "%")))
3638
  if (!grid_on && "fosas-choro" %in% active && has_fosas_tbl)
3639
  lazy_add_fill("fosas", "src_fosas", "fosas-choro", function(prx, d)
3640
  prx |> add_fill_layer("fosas-choro", source = d,
styles.css CHANGED
@@ -2432,3 +2432,34 @@ button.mapbox-gl-draw_uncombine { display: none !important; }
2432
 
2433
  /* Tooltip toggle: hide maplibre popups when body.tooltips-off is set */
2434
  body.tooltips-off .maplibregl-popup { display: none !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2432
 
2433
  /* Tooltip toggle: hide maplibre popups when body.tooltips-off is set */
2434
  body.tooltips-off .maplibregl-popup { display: none !important; }
2435
+
2436
+ /* =========================================================================
2437
+ Categorical legend variants (patp: rural problem / crime focus)
2438
+ ========================================================================= */
2439
+
2440
+ /* Variant wrappers hidden by default; shown only when the matching chip is
2441
+ active (is-active-variant) AND the layer toggle is on (legend-visible). */
2442
+ .acc-legend-extra {
2443
+ display: none;
2444
+ padding: 2px var(--space-3) 6px calc(var(--space-3) + 34px);
2445
+ }
2446
+ .acc-legend-extra.is-active-variant.legend-visible {
2447
+ display: block;
2448
+ }
2449
+ .acc-legend-extra.is-active-variant.legend-visible .acc-legend-cats {
2450
+ display: flex;
2451
+ }
2452
+ /* The inner legend re-renders the standard .acc-legend stack, so override the
2453
+ nested margin/padding it gets from being inside a wrapper. */
2454
+ .acc-legend-extra .acc-legend {
2455
+ padding: 0;
2456
+ display: block;
2457
+ }
2458
+ .acc-legend-extra .acc-legend.acc-legend-cats {
2459
+ display: flex;
2460
+ }
2461
+
2462
+ /* When an extra is active, hide the primary ramp legend for the same layer. */
2463
+ .acc-legend.acc-legend-hidden-by-variant {
2464
+ display: none !important;
2465
+ }