preserveAspectRatio、viewBox和layout.size()的问题

Issues with preserveAspectRatio, viewBox and layout.size()

本文关键字:问题 size layout viewBox preserveAspectRatio      更新时间:2023-09-26

我已经编写了以下代码,旨在显示d3js树布局,但在尝试让生成的svg根据其纵横比调整大小时遇到了一些困难。我能够(在所附的演示中)让svg按照我想要的方式进行扩展,但我编写的代码受到const ASPECT_RATIO的限制,如下所示:

canvas.attr("viewBox", " 0 0 " + window.innerWidth + " " + (window.innerWidth * ASPECT_RATIO));

再往下看,这里是

layout.size([(window.innerWidth * ASPECT_RATIO), window.innerWidth - 128]);

有办法绕过这一点吗?我不希望每次svg的纵横比发生变化时(也就是说,任何时候添加新内容时)都必须手动更改此值。

问候,

Brian


tl;博士:帮我消除const ASPECT_RATIO


代码:

/// <reference path="d3.d.ts" />
"use strict";
/* (c) brianjenkins94 | brianjenkins94.me | MIT licensed */
// Get JSON, impose synchronicity
d3.json("js/data.json", function(error, treeData) {
  if (!error) {
// Instantiate canvas
var canvas = d3.select("#canvas");
// Aspect ratio nonsense
const ASPECT_RATIO = 1.89260808926;
canvas.attr("viewBox", " 0 0 " + window.innerWidth + " " + (window.innerWidth * ASPECT_RATIO));
canvas.attr("preserveAspectRatio", "xMinYMin slice");
// Update
update();
function update() {
  // Add an SVG group element
  canvas.append("g");
  // Instantiate group
  var group = canvas.select("g");
  // Translate group right
  group.attr("transform", "translate(64, 0)");
  // Instantiate layout tree
  var layout = d3.layout.tree();
  // Initialize layout dimensions
  layout.size([(window.innerWidth * ASPECT_RATIO), window.innerWidth - 128]);
  // Instantiate rotation diagonal
  var diagonal = d3.svg.diagonal();
  // Rotate projection 90 degrees about the diagonal
  diagonal.projection(function(d) { return [d.y, d.x]; });
  // Initialize node array
  var nodes = layout.nodes(treeData);
  // Initialize link array
  var links = layout.links(nodes);
  // Select all paths in group
  group.selectAll("path")
    // For each link, create a path
    .data(links).enter().append("path")
    // Provide the specific diagonal
    .attr("d", diagonal);
  // Select all groups in group
  var node = group.selectAll("g")
    // For each node, create a group
    .data(nodes).enter().append("g")
    // Translate accordingly
    .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
  // Add a circle at every node
  node.append("circle")
    .attr("r", 3);
  // Add label
  node.append("text")
    // To the left if the node has children, otherwise right
    .attr("dx", function(d) { return d.children ? -8 : 8; })
    .attr("dy", 0)
    // Branch if the node has children
    .attr("text-anchor", function(d) { return d.children ? "end" : "start"; })
    .text(function(d) { return d.name; });
    }
  } else {
    console.log("There was a connection error of some sort.");
  }
});

演示:

  • https://rawgit.com/brianjenkins94/html5tree/master/index.html

以下是我学到的:

  • 虽然svg可以是"无量纲的",但它不能是"无纵横比的"。必须有一些核心纵横比来控制大小调整
  • tree.size()和tree.nodeSize()函数创建了一个"不受屏幕坐标限制"的"任意坐标系"
  • 纵横比是什么,取决于开发者,可以表示为"任意坐标",或者根据响应设计,可以表达为相对论测量

我的解决方案如下:

// Viewbox & preserveAspectRatio
canvas.attr("viewBox", " 0 0 " + window.innerWidth + " " + (2 * window.innerWidth));
canvas.attr("preserveAspectRatio", "xMinYMin slice");
...
// Initialize layout dimensions
layout.size([(2 * window.innerWidth), (window.innerWidth - 128)]);

从而消除了对const ASPECT_RATIO的依赖,有利于基于浏览器尺寸的相对测量。

这可能(几乎肯定会)导致多个视口之间的渲染不一致,但可以通过在渲染前查询视口并进行外观调整来相应地处理。