You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让gvisGeoChart标注在不同屏幕尺寸下位置固定

解决gvisGeoChart颜色条标注位置固定问题

核心思路

gvisGeoChart生成的Google Charts颜色条(colorAxis)位置是动态计算的,纯CSS绝对定位无法适配所有屏幕。通过监听图表加载完成事件,用JavaScript获取colorAxis的实际DOM位置,动态调整标注坐标,同时监听窗口resize事件实时更新,就能让标注始终固定在颜色条上方。

具体修改要点

  1. 调整CSS结构:给图表和标注添加容器,以相对定位作为基准,初始隐藏标注避免偏移
  2. 添加JS定位逻辑:
    • 监听图表ready事件,获取colorAxis的DOM元素
    • 计算颜色条中心位置,将标注对齐到其上方
    • 监听窗口尺寸变化,实时重新计算位置
  3. 隐藏颜色条数字:在colorAxis配置中添加ticks: [],直接移除两侧刻度数字

修改后的完整代码

library(shiny)
library(googleVis)
library(dplyr)
library(DT)

# 加载数据
combined_vul_data <- 
  structure(list(ISO3 = c("AF", "AL", "DZ", "AD", "AO", "AG", "AR", 
                          "AM", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", "BY", "BE", "BZ", 
                          "BJ", "BT"), Name = c("Afghanistan", "Albania", "Algeria", "Andorra", 
                                                "Angola", "Antigua and Barbuda", "Argentina", "Armenia", "Australia", 
                                                "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", 
                                                "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bhutan"
                          ), vul_capacity_Rank_2021 = c(0.709035449, 0.511126182, 0.523332101, 
                                                        NA, 0.740026186, 0.621133795, 0.446088596, 0.462491218, 0.296565054, 
                                                        0.26689445, 0.47917568, NA, 0.453936004, 0.649876424, 0.398904506, 
                                                        0.386808093, 0.27763708, 0.547525366, 0.763503499, 0.635633065
                          )), class = "data.frame", row.names = c(NA, -20L))


# UI定义
ui <- fluidPage(
  tags$head(
    tags$style(HTML("
      .color-scale-label {
        position: absolute;
        background: rgba(255, 255, 255, 0.8);
        padding: 5px 10px;
        border-radius: 4px;
        z-index: 1000;
        pointer-events: none;
        opacity: 0; /* 初始隐藏,JS定位后显示 */
      }
      #map-container {
        position: relative;
        width: 100%;
        height: 500px;
      }
      @media (max-width: 768px) {
        .shiny-input-container {
          width: 100%;
        }
        .main-panel, .content {
          height: calc(100vh - 56px) !important;
          overflow: auto;
        }
        .main-panel {
          height: 100vh;
        }
      }
    "))
  ),
  titlePanel(div(span("Country Rankings"), style={'padding-top: 15px'})),
  tabsetPanel(
    tabPanel("Vulnerability Map",
             sidebarLayout(
               sidebarPanel(
                 selectInput("year", "Select Year", choices = 2021, selected = 2021),
                 selectInput("category", "Select Category", 
                             choices = list("Adaptive Capacity" = "vul_capacity"), selected = "vul_vulnerability")
               ),
               mainPanel(
                 tags$div(id = "map-container",
                          tags$div(class="color-scale-label", "Least to Most Vulnerable"),
                          htmlOutput("map")
                 ),
                 # 定位逻辑脚本
                 tags$script(HTML("
                   function alignColorLabel() {
                     // 获取颜色条DOM元素
                     const colorAxis = document.querySelector('#map svg g:nth-child(2) g:nth-child(2)');
                     if (!colorAxis) return;
                     
                     const label = document.querySelector('.color-scale-label');
                     const container = document.querySelector('#map-container');
                     
                     // 计算位置:对齐颜色条中心上方30px
                     const axisRect = colorAxis.getBoundingClientRect();
                     const containerRect = container.getBoundingClientRect();
                     const labelLeft = (axisRect.left - containerRect.left) + (axisRect.width / 2) - (label.offsetWidth / 2);
                     const labelTop = (axisRect.top - containerRect.top) - 30;
                     
                     // 设置位置并显示
                     label.style.left = labelLeft + 'px';
                     label.style.top = labelTop + 'px';
                     label.style.opacity = '1';
                   }
                   
                   // 图表加载完成后执行定位
                   google.charts.setOnLoadCallback(function() {
                     const chartWrapper = document.getElementById('map').querySelector('div.google-visualization-chart');
                     if (chartWrapper) {
                       google.visualization.events.addListener(chartWrapper.chart, 'ready', alignColorLabel);
                     }
                     // 窗口变化时重新定位
                     window.addEventListener('resize', alignColorLabel);
                   });
                 "))
               )
             )
    )
  )
)

# 服务器逻辑
server <- function(input, output) {
  output$map <- renderGvis({
    year <- input$year
    category <- input$category
    
    rank_column <- paste(category, "_Rank_", year, sep = "")
    
    map_data <- combined_vul_data %>%
      select(ISO3, Name, Rank = !!sym(rank_column)) %>%
      mutate(Tooltip = ifelse(is.na(Rank), paste(Name, "- Insufficient data"), paste(Name))) %>%
      mutate(Location = ifelse(Name %in% c("Congo (Brazzaville)", "Congo (Kinshasa)"), ISO3, Name))
    
    min_rank <- min(map_data$Rank, na.rm = TRUE)
    max_rank <- max(map_data$Rank, na.rm = TRUE)
    
    gvisGeoChart(map_data, locationvar = "Location", colorvar = "Rank",
                 hovervar = "Tooltip",  
                 options = list(colorAxis = paste0("{minValue:", min_rank, ", maxValue:", max_rank, ", colors:['#00FF00', '#FFFF00', '#FF0000'], ticks: []}"),
                                backgroundColor = '#81d4fa', datalessRegionColor = '#f5f5f5',
                                defaultColor = '#f5f5f5',
                                tooltip = "{isHtml: true}",
                                width = "100%",
                                height = "500px"))  
  })
  
}

shinyApp(ui = ui, server = server)

效果说明

  • 标注会自动对齐到颜色条正上方,无论屏幕尺寸如何变化都保持位置一致
  • 通过ticks: []直接隐藏了颜色条两侧的数字,无需额外处理
  • 半透明背景保证标注不会遮挡地图内容

内容的提问来源于stack exchange,提问作者hks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 03:00:55