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

D3v4响应式图例适配问题:窗口缩小时调整行间距

Fix Responsive Legend Spacing in D3 v4 Map Visualization

Got it, let's solve that legend spacing issue you're facing! The problem here is that your current row spacing (i * 20) is hardcoded to a fixed pixel value, so it doesn't adjust when the window resizes. We need to make that spacing dynamic and update it whenever the window changes size.

Here's a step-by-step solution:

1. Wrap Legend Logic in a Reusable Update Function

First, we'll create a function that calculates the dynamic spacing and updates the legend's transform attribute. This way, we can call it both on initialization and whenever the window resizes. You can choose from a few flexible approaches:

Option 1: Threshold-Based Spacing

Switch between spacing values when the window crosses a height threshold (e.g., 600px):

function updateLegend() {
  // Adjust spacing based on window height
  const windowHeight = window.innerHeight;
  const rowSpacing = windowHeight < 600 ? 15 : 20; // Smaller spacing for compact windows

  // Update position of each legend group
  d3.select(".legend")
    .selectAll("g")
    .attr("transform", function(d, i) {
      return `translate(0, ${i * rowSpacing})`;
    });
}

Option 2: Viewport Unit Scaling

Use CSS viewport units for seamless, proportional scaling with window size:

function updateLegend() {
  // Spacing scales with viewport width (1.2% of window width)
  const rowSpacing = 1.2;

  d3.select(".legend")
    .selectAll("g")
    .attr("transform", function(d, i) {
      return `translate(0, ${i * rowSpacing}vw)`;
    });
}

Option 3: Fit to Container Height

Calculate spacing to make the legend perfectly fill its parent container:

function updateLegend() {
  const legendContainer = document.getElementById("legendecontainer");
  const containerHeight = legendContainer.offsetHeight;
  const itemCount = color.domain().length;
  
  // Subtract padding (20px total) from container height
  const availableHeight = containerHeight - 20;
  // Spacing between items (n items have n-1 gaps)
  const rowSpacing = availableHeight / (itemCount - 1);

  d3.select(".legend")
    .selectAll("g")
    .attr("transform", function(d, i) {
      return `translate(0, ${i * rowSpacing})`;
    });
}

2. Initialize and Attach Resize Listener

Update your original code to call the updateLegend function on load, and add a listener to trigger it when the window resizes:

// Initialize legend container and groups
var legend = d3.select("#legendecontainer").append("svg")
  .attr("class", "legend")
  .selectAll("g")
  .data(color.domain())
  .enter().append("g");

// Add legend rectangles (your existing code)
legend.append("rect")
  .attr("width", "1em")
  .attr("height", "1em")
  .style("fill", color);

// Add legend text (your existing code)
legend.append("text")
  .data(legendText)
  .attr("x", "1.8em")
  .attr("y", ".5em")
  .attr("dy", ".35em")
  .text(function(d) { return d; });

// Set initial spacing
updateLegend();

// Update spacing automatically on window resize
window.addEventListener("resize", updateLegend);

3. Bonus: Make SVG Container Responsive

To ensure the legend SVG fits its container fully, add this to the updateLegend function (adjust padding as needed):

function updateLegend() {
  // ... existing spacing calculation code ...

  // Update SVG dimensions to fit all legend items
  const svgHeight = (color.domain().length * rowSpacing) + 10; // Add 10px bottom padding
  d3.select(".legend")
    .attr("height", svgHeight)
    .attr("width", "100%"); // Fill container width
}

The core fix here is moving from a one-time fixed spacing calculation to a dynamic, reusable function that updates whenever the window changes size. This keeps your legend properly aligned and adapted to available space.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:07:43