preserveAspectRatio、viewBox 和 layout.size() 的问题
Issues with preserveAspectRatio, viewBox and layout.size()
我编写了以下代码来显示 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.");
}
});
演示:
这是我学到的:
- 虽然 svg 可以 "dimensionless" 但不能 "aspect-ratio-less." 必须有一些核心宽高比来控制调整大小。
- tree.size() and tree.nodeSize() 函数创建一个 "arbitrary coordinate system" "is not limited screen coordinates."
- 宽高比是多少,由开发者决定,可以表示为"arbitrary coordinates",或者根据响应式设计,可以表示为相对论测量
我的解决方法如下:
// 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
的依赖,支持基于浏览器尺寸的相对测量。
这可能(并且几乎肯定会)导致跨多个视口的渲染不一致,但可以通过在渲染之前查询视口并进行修饰调整来相应地处理。
我编写了以下代码来显示 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.");
}
});
演示:
这是我学到的:
- 虽然 svg 可以 "dimensionless" 但不能 "aspect-ratio-less." 必须有一些核心宽高比来控制调整大小。
- tree.size() and tree.nodeSize() 函数创建一个 "arbitrary coordinate system" "is not limited screen coordinates."
- 宽高比是多少,由开发者决定,可以表示为"arbitrary coordinates",或者根据响应式设计,可以表示为相对论测量
我的解决方法如下:
// 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
的依赖,支持基于浏览器尺寸的相对测量。
这可能(并且几乎肯定会)导致跨多个视口的渲染不一致,但可以通过在渲染之前查询视口并进行修饰调整来相应地处理。