在 d3 中制作动画弧响应?
Posted
技术标签:
【中文标题】在 d3 中制作动画弧响应?【英文标题】:Making an animating arc in d3 responsive? 【发布时间】:2014-02-20 02:49:58 【问题描述】:我在 d3 中看这个动画,
http://bl.ocks.org/mbostock/5100636
我想知道有没有什么办法可以让它响应,以便大小随着浏览器窗口大小的调整而变化?或者如果使用 raphael.js 会更容易?
代码如下:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
τ = 2 * Math.PI; // http://tauday.com/tau-manifesto
// An arc function with all values bound except the endAngle. So, to compute an
// SVG path string for a given angle, we pass an object with an endAngle
// property to the `arc` function, and it will return the corresponding string.
var arc = d3.svg.arc()
.innerRadius(180)
.outerRadius(240)
.startAngle(0);
// Create the SVG container, and apply a transform such that the origin is the
// center of the canvas. This way, we don't need to position arcs individually.
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
// Add the background arc, from 0 to 100% (τ).
var background = svg.append("path")
.datum(endAngle: τ)
.style("fill", "#ddd")
.attr("d", arc);
// Add the foreground arc in orange, currently showing 12.7%.
var foreground = svg.append("path")
.datum(endAngle: .127 * τ)
.style("fill", "orange")
.attr("d", arc);
// Every so often, start a transition to a new random angle. Use transition.call
// (identical to selection.call) so that we can encapsulate the logic for
// tweening the arc in a separate function below.
setInterval(function()
foreground.transition()
.duration(750)
.call(arcTween, Math.random() * τ);
, 1500);
// Creates a tween on the specified transition's "d" attribute, transitioning
// any selected arcs from their current angle to the specified new angle.
function arcTween(transition, newAngle)
// The function passed to attrTween is invoked for each selected element when
// the transition starts, and for each element returns the interpolator to use
// over the course of transition. This function is thus responsible for
// determining the starting angle of the transition (which is pulled from the
// element's bound datum, d.endAngle), and the ending angle (simply the
// newAngle argument to the enclosing function).
transition.attrTween("d", function(d)
// To interpolate between the two angles, we use the default d3.interpolate.
// (Internally, this maps to d3.interpolateNumber, since both of the
// arguments to d3.interpolate are numbers.) The returned function takes a
// single argument t and returns a number between the starting angle and the
// ending angle. When t = 0, it returns d.endAngle; when t = 1, it returns
// newAngle; and for 0 < t < 1 it returns an angle in-between.
var interpolate = d3.interpolate(d.endAngle, newAngle);
// The return value of the attrTween is also a function: the function that
// we want to run for each tick of the transition. Because we used
// attrTween("d"), the return value of this last function will be set to the
// "d" attribute at every tick. (It's also possible to use transition.tween
// to run arbitrary code for every tick, say if you want to set multiple
// attributes from a single function.) The argument t ranges from 0, at the
// start of the transition, to 1, at the end.
return function(t)
// Calculate the current arc angle based on the transition time, t. Since
// the t for the transition and the t for the interpolate both range from
// 0 to 1, we can pass t directly to the interpolator.
//
// Note that the interpolated angle is written into the element's bound
// data object! This is important: it means that if the transition were
// interrupted, the data bound to the element would still be consistent
// with its appearance. Whenever we start a new arc transition, the
// correct starting angle can be inferred from the data.
d.endAngle = interpolate(t);
// Lastly, compute the arc path given the updated data! In effect, this
// transition uses data-space interpolation: the data is interpolated
// (that is, the end angle) rather than the path string itself.
// Interpolating the angles in polar coordinates, rather than the raw path
// string, produces valid intermediate arcs during the transition.
return arc(d);
;
);
</script>
【问题讨论】:
看看***.com/questions/16265123/… 【参考方案1】:您有两种选择让 SVG 适应窗口大小。
第一个选项是让“Scalable Vector Graphics”的“Scalable”方面为您完成工作。使用相对单位(百分比或视口单位)或使用 CSS 媒体查询来设置 SVG 大小以适应屏幕大小。然后将viewBox
属性添加到您的 SVG 以使图像缩放以适合您放入的任何大小的框。限制是 everything 均等缩放,这可能导致文本非常大或非常小如果图形的大小发生显着变化,则标记。好处是调整大小完全独立于您的代码和图形中的任何动画。
应用于补间动画演示的概念示例:http://fiddle.jshell.net/h8Mg9/
关键代码:
var svg = d3.select("body").append("svg")
.attr("height", "100%") //or use CSS
.attr("width", "100%")
.attr("viewBox",
"0 0 " + (margin.left + diameter + margin.right) +
" " + (margin.top + diameter + margin.bottom) )
//"0 0 160 120" -- defines relative units for drawing
//(0,0) for top left corner coordinates,
//then width and height.
.attr("preserveAspectRatio", "xMidYMid meet");
//maintain aspect ratio from viewBox dimensions;
//If they don't match svg dimensions, scale down to
//fit the entire viewbox within the svg (meet);
//center it vertically and horizontally (xMidYMid)
请注意,文本的大小始终与圆环成比例,就好像圆环的直径为 100 像素一样。此外,文本过渡只是旧位置和新位置之间的直线过渡。
第二个选项是监听窗口调整大小事件,查询svg大小然后触发重绘。绘图函数中的所有尺寸变量都必须适当地缩放到尺寸。此外,您必须考虑在转换期间发生调整事件大小的可能性。自定义的补间弧实际上使这更容易,因为它在过渡的每个滴答声中调用 arc 函数;通过更改 arc 函数的参数,补间结果也会自动更改。
此方法在 arc tween 演示中的示例:http://fiddle.jshell.net/h8Mg9/2/
关键代码:
function setSize()
var svgStyles = window.getComputedStyle(svg.node());
diameter = Math.min(
(parseInt(svgStyles["width"])
- margin.left - margin.right),
(parseInt(svgStyles["height"])
- margin.top - margin.bottom) );
arc.outerRadius(diameter/2)
.innerRadius(diameter/2 - ringThickness);
vis.attr("transform",
"translate(" + (margin.left + diameter/2) + ","
+ (margin.top + diameter/2) + ")");
background.attr("d", arc);
if(!transitioning)
//don't interrupt an ongoing transition --
//it will automatically adjust
//because we've modified the arc function;
//note that we've created a custom tween
//for the label, so it will adjust too.
//Otherwise:
foreground.attr("d", arc);
label.attr("transform", function(d)
return "translate("+arc.centroid(d)+")"
);
//Note that we're not transitioning the change
//in diameter; it isn't necessary since there
//will be multiple resize events creating a smooth
//shift in size.
setSize(); //initialize
//adapt size to window changes:
window.addEventListener("resize", setSize, false)
饼图的另一个好处是大小实际上只设置一次,在 arc 函数的外半径中。对于更复杂的布局重绘,您需要使用比例来确定位置和大小。 this answer on zooming 的最后一个示例显示了使用比例调整大小。
对于在缩放布局中组合过渡和调整大小,您可以使用与饼图中相同的方法(更改圆弧函数会更改补间函数的结果),并具有自定义补间在每个刻度查询刻度当前状态的函数。但是,在大多数情况下,简单地中断正在进行的转换可能会更有效——即,创建一个新的转换,最终将维度的变化与大小的变化结合起来。
【讨论】:
是的!阿米莉亚说了什么。 感谢您的精彩回答。我希望宽度:90vw;高度:90vh;在 css 中不是强制性的,因为支持不是跨浏览器 不,这只是使 svg 适合窗口大小的众多方法之一。百分比是一种工作,但有点困难,因为没有跨浏览器支持的“自动”高度选项,并且百分比高度要求任何封闭(“div”或其他)元素都已定义高度。我过去使用的一件事是 0 高度和溢出在 svg 上可见,使用 svg 填充来获取纵横比(填充中的百分比是宽度的百分比),然后包装一个 div,溢出隐藏在填充周围svg。或者在window resize函数中自己计算...以上是关于在 d3 中制作动画弧响应?的主要内容,如果未能解决你的问题,请参考以下文章