在d3响应动画的弧? [英] Making an animating arc in d3 responsive?

查看:225
本文介绍了在d3响应动画的弧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在d3看这个动画,



http://bl.ocks.org/mbostock/5100636



我想知道有没有什么办法让这个响应,使大小随浏览器窗口大小的变化?

 <$> 



c $ c><!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

//除了endAngle之外的所有值都被绑定的arc函数。因此,为了计算给定角度的
// SVG路径字符串,我们将一个带有endAngle
//属性的对象传递给`arc`函数,它将返回相应的字符串。
var arc = d3.svg.arc()
.innerRadius(180)
.outerRadius(240)
.startAngle(0);

//创建SVG容器,并应用一个变换,使得原点是画布的
//中心。这样,我们不需要单独定位弧线。
var svg = d3.select(body)。append(svg)
.attr(width,width)
.attr(height,height)
.append(g)
.attr(transform,translate(+ width / 2 +,+ height / 2 +))

/ /添加背景弧,从0到100%(τ)。
var background = svg.append(path)
.datum({endAngle:τ})
.style(fill,#ddd)
.attr (d,arc);

//将前景弧添加为橙色,当前显示为12.7%。
var foreground = svg.append(path)
.datum({endAngle:.127 *τ})
.style(fill,orange)
.attr(d,arc);

//经常,开始转换到一个新的随机角度。使用transition.call
//(与selection.call相同),这样我们就可以封装
//的逻辑,在下面的一个单独的函数中补充弧。
setInterval(function(){
foreground.transition()
.duration(750)
.call(arcTween,Math.random()*τ);
},1500);

//在指定的转换的d属性上创建补间,将
//任何选定的弧从当前角度转换到指定的新角度。
function arcTween(transition,newAngle){

//当
//转换开始时,为每个选定的元素调用传递给attrTween的函数,对于每个元素,返回插值器在过渡过程中使用
//。因此,这个函数负责
//确定转换的起始角度(它从
//元素的绑定数据d.endAngle中拉出)和结束角度(简单的
//封装函数的newAngle参数)。
transition.attrTween(d,function(d){

//在两个角度之间插值我们使用默认的d3.interpolate
// ,这映射到d3.interpolateNumber,因为d3.interpolate的
//参数都是数字。)返回的函数接受一个
//单参数t,并返回一个数字在起始角和当t = 0时,它返回d.endAngle;当t = 1时,它返回
// newAngle;对于0 var interpolate = d3.interpolate(d.endAngle,newAngle);

// attrTween的返回值也是一个函数:函数
/因为我们使用
// attrTween(d),这个最后一个函数的返回值将被设置为
//d属性(也可以使用transition.tween
//为每个tick创建任意代码,假设你想从单个函数中设置多个
//属性)。参数t范围从0,在
//转换的开始,到1,在结束。
return function(t){

//根据过渡时间t计算当前的弧角。由于
//转换的t和内插的t都从
// 0到1的范围,我们可以直接传递t给内插器。
//
//注意内插角度写入元素的
//数据对象!这很重要:这意味着如果转换是
//中断,绑定到该元素的数据将仍然与其外观一致
//。每当我们开始一个新的弧转换,
//正确的起始角度可以从数据推断。
d.endAngle = interpolate(t);

//最后,计算给定更新数据的弧路径!实际上,这个
//转换使用数据空间插值:数据是内插的
//(即结束角),而不是路径字符串本身。
//在极坐标中插入角度,而不是原始路径
// string,在转换期间生成有效的中间弧。
return arc(d);
};
});
}

< / script>


解决方案

第一个选项是让可缩放矢量图形的可伸缩方面为您工作。使用相对单位(百分比或视口单位)或使用CSS媒体查询以适应屏幕大小设置SVG大小。然后添加一个 viewBox 属性到你的SVG,使图像缩放适合任何大小的盒子,你把它放在。限制是 ,如果图形的大小变化相当大,这可能导致非常大或非常小的文本标签。好处是重新调整大小完全独立于你的代码和你在图形中的任何动画。



应用于arc tween的概念示例demo: br>
http://fiddle.jshell.net/h8Mg9/



键代码:

  var svg = d3.select(body)append(svg )
.attr(height,100%)//或使用CSS
.attr(width,100%)
.attr(viewBox,
0 0+(margin.left + diameter + margin.right)+
+(margin.top + diameter + margin.bottom))
//0 0 160 120 - 定义绘制
//(0,0)用于左上角坐标的相对单位,
//然后是宽度和高度。
.attr(preserveAspectRatio,xMidYMid meet);
//从viewBox维度中保持宽高比;
//如果它们不匹配svg维度,缩小到
//在svg(meet)中匹配整个viewbox;
//垂直和水平居中(xMidYMid)

请注意,与环成正比,如果环直径为100px。此外,文本转换只是新旧位置之间的直线转换。



第二个选项是监听窗口大小调整事件,查询svg大小然后触发重绘。绘图函数中的所有尺寸变量都必须适当地缩放到尺寸。此外,您必须考虑在转换期间发生的大小调整事件的可能性。自定义圆弧补间实际上使得这更容易,因为它在转换的每个刻度调用弧函数;通过更改弧函数的参数,补间结果也会自动更改。



在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)+,
+顶部+直径/ 2)+));
background.attr(d,arc);

if(!transitioning){
//不中断正在进行的转换 -
//它会自动调整
//因为我们修改了弧函数;
//注意,我们为标签创建了自定义补间
//,因此它也将调整。

//否则:
foreground.attr(d,arc);
label.attr(transform,function(d){
returntranslate(+ arc.centroid(d)+)
}
}
//注意,我们不是直接转换
//的变化;它没有必要,因为
//将是多个调整大小事件,创建一个平滑的
//大小移位。
}
setSize(); // initialize

//根据窗口更改调整大小:
window.addEventListener(resize,setSize,false)

饼图的另一个好处是,在arc函数的outerRadius中,尺寸只设置一次。对于更复杂的布局重绘,您需要使用缩放来确定位置和大小。 缩放的最终示例显示了按比例缩放的大小。



对于在缩放布局中组合过渡和调整大小,您可以使用与饼图相同的方法(更改圆弧函数更改补间函数的结果),并且具有自定义补间函数,其在每次刻度时查询刻度的当前状态。然而,在大多数情况下,简单地中断正在进行的转换可能更有效,即,创建新的转换,其将结合尺寸的移位与尺寸的移位。


I was looking at this animation in d3,

http://bl.ocks.org/mbostock/5100636

And I was wondering is there any way to make this responsive, so that the size changes with resizing of the browser window ? Or if it would be easier using raphael.js ?

Here's the code :

<!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>

解决方案

You have two options for getting an SVG to adapt to window size.

The first option is to let the "Scalable" aspect of "Scalable Vector Graphics" do the work for you. Set the SVG size using relative units (percents or viewport units) or using CSS media queries to adapt to screen size. Then add a viewBox attribute to your SVG to make the image scale to fit whatever size box you put it in. The limitation is that everything scales equally, which can result in very large or very small text labels if the size of the graphic changes considerably. The benefit is that the re-size is completely independent of your code and any animations you have in the graphic.

Example of the concept applied to the arc tween demo:
http://fiddle.jshell.net/h8Mg9/

Key code:

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)

Note that the text is always sized proportional to the ring as if the ring was 100px in diameter. Also, the text transition is just a straight-line transition between old and new positions.

The second option is to listen for window resize events, query the svg size and then trigger a re-draw. All the size variables in your drawing function have to be appropriately scaled to the dimensions. Furthermore, you have to factor in the possibility of resize events happening during a transition. The custom arc tween actually makes that easier, since it calls the arc function at every tick of the transition; by changing the arc function's parameters, the tween results are automatically changed as well.

Example of this method on the arc tween demo:
http://fiddle.jshell.net/h8Mg9/2/

Key code:

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)

Another benefit of the pie chart is that the size is really only set once, in the arc function's outerRadius. For a more complex layout redraw, you'll want to use scales to determine positions and sizing. The final examples of this answer on zooming show resizing with scales.

For combining transitions and resize in a scaled layout, you could use the same approach as in the pie chart (changing the arc function changes the results of the tween function), and have a custom tween function that queries the current state of the scale at each tick. However, in most cases it would probably be more efficient to simply interrupt the ongoing transition -- i.e., create a new transition which would end up combining the shift in dimension with the shift in size.

这篇关于在d3响应动画的弧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆