假设我有一个直方图脚本,构建960 500 svg图形。我如何使这个响应,以便调整图形的宽度和高度是动态的?
<script>
var n = 10000, // number of trials
m = 10, // number of random variables
data = [];
// Generate an Irwin-Hall distribution.
for (var i = 0; i < n; i++) {
for (var s = 0, j = 0; j < m; j++) {
s += Math.random();
}
data.push(s);
}
var histogram = d3.layout.histogram()
(data);
var width = 960,
height = 500;
var x = d3.scale.ordinal()
.domain(histogram.map(function(d) { return d.x; }))
.rangeRoundBands([0, width]);
var y = d3.scale.linear()
.domain([0, d3.max(histogram.map(function(d) { return d.y; }))])
.range([0, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.selectAll("rect")
.data(histogram)
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return height - y(d.y); })
.attr("height", function(d) { return y(d.y); });
svg.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", height)
.attr("y2", height);
</script>
完整的直方图示例要点如下:
https://gist.github.com/993912
您还可以使用bootstrap 3来调整可视化的大小。例如,我们可以将HTML代码设置为:
<div class="container>
<div class="row">
<div class='col-sm-6 col-md-4' id="month-view" style="height:345px;">
<div id ="responsivetext">Something to write</div>
</div>
</div>
</div>
因为我的需要,我已经设置了一个固定的高度,但是你也可以保持大小自动。“col-sm-6 col-md-4”使div能够响应不同的设备。你可以在http://getbootstrap.com/css/#grid-example-basic上了解更多
我们可以在id month-view的帮助下访问该图。
我不会详细介绍d3代码,我只会输入适应不同屏幕尺寸所需的部分。
var width = document.getElementById('month-view').offsetWidth;
var height = document.getElementById('month-view').offsetHeight - document.getElementById('responsivetext2').offsetHeight;
宽度是通过id month-view获取div的宽度来设置的。
在我的例子中,高度不应该包括整个区域。我也有一些文字上面的酒吧,所以我需要计算的面积以及。这就是为什么我用id responsivetext标识文本区域的原因。为了计算栏的允许高度,我用div的高度减去文本的高度。
这允许你有一个条,将采用所有不同的屏幕/div大小。这可能不是最好的方法,但它肯定能满足我的项目的需要。
还有另一种不需要重绘图形的方法,它涉及到修改<svg>元素上的viewBox和preserveAspectRatio属性:
<svg id="chart" viewBox="0 0 960 500"
preserveAspectRatio="xMidYMid meet">
</svg>
15年11月24日更新:大多数现代浏览器可以从viewBox推断SVG元素的纵横比,所以你可能不需要保持图表的大小。如果你需要支持旧的浏览器,你可以在窗口调整大小时调整元素的大小,就像这样:
var aspect = width / height,
chart = d3.select('#chart');
d3.select(window)
.on("resize", function() {
var targetWidth = chart.node().getBoundingClientRect().width;
chart.attr("width", targetWidth);
chart.attr("height", targetWidth / aspect);
});
svg内容将自动缩放。你可以在这里看到一个工作示例(进行了一些修改):调整窗口或右下角窗格的大小,看看它是如何反应的。
D3数据连接的基本原则之一是它是幂等的。换句话说,如果重复计算使用相同数据的数据连接,则呈现的输出是相同的。因此,只要你正确地渲染图表,注意你的进入,更新和退出选择-当大小发生变化时,你所要做的就是重新渲染整个图表。
还有一些其他的事情你应该做,一个是取消窗口调整大小处理程序,以抑制它。此外,这应该通过测量包含元素来实现,而不是硬编码宽度/高度。
作为替代方案,下面是使用d3fc呈现的图表,d3fc是一组正确处理数据连接的D3组件。它还有一个笛卡尔图,可以测量它所包含的元素,从而很容易创建“响应性”图表:
// create some test data
var data = d3.range(50).map(function(d) {
return {
x: d / 4,
y: Math.sin(d / 4),
z: Math.cos(d / 4) * 0.7
};
});
var yExtent = fc.extentLinear()
.accessors([
function(d) { return d.y; },
function(d) { return d.z; }
])
.pad([0.4, 0.4])
.padUnit('domain');
var xExtent = fc.extentLinear()
.accessors([function(d) { return d.x; }]);
// create a chart
var chart = fc.chartSvgCartesian(
d3.scaleLinear(),
d3.scaleLinear())
.yDomain(yExtent(data))
.yLabel('Sine / Cosine')
.yOrient('left')
.xDomain(xExtent(data))
.xLabel('Value')
.chartLabel('Sine/Cosine Line/Area Chart');
// create a pair of series and some gridlines
var sinLine = fc.seriesSvgLine()
.crossValue(function(d) { return d.x; })
.mainValue(function(d) { return d.y; })
.decorate(function(selection) {
selection.enter()
.style('stroke', 'purple');
});
var cosLine = fc.seriesSvgArea()
.crossValue(function(d) { return d.x; })
.mainValue(function(d) { return d.z; })
.decorate(function(selection) {
selection.enter()
.style('fill', 'lightgreen')
.style('fill-opacity', 0.5);
});
var gridlines = fc.annotationSvgGridline();
// combine using a multi-series
var multi = fc.seriesSvgMulti()
.series([gridlines, sinLine, cosLine]);
chart.plotArea(multi);
// render
d3.select('#simple-chart')
.datum(data)
.call(chart);
你可以在这个代码库中看到它的作用:
https://codepen.io/ColinEberhardt/pen/dOBvOy
在这里,您可以调整窗口的大小,并验证图表是否被正确重新渲染。
请注意,作为一个充分的披露,我是d3fc的维护者之一。