preserveAspectRatio,viewBox和layout.size()

时间:2015-12-31 00:02:22

标签: javascript d3.js svg viewport viewbox

我编写了以下用于显示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的宽高比改变时(即,每次添加新内容时)都不需要手动更改此值。

此致

布赖恩

tl; dr:帮我消除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.");
  }
});

演示:

1 个答案:

答案 0 :(得分:1)

这是我学到的东西:

  • 虽然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的依赖,支持基于浏览器维度的相对测量。

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