javascript 在调整大小时重绘 SVG
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25555257/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Redrawing SVG on resize
提问by lebolo
I'm trying to redraw an SVG chart on window resize within d3, but without using the viewBox
and preserveAspectRatio
parameters (I didn't like how they treated text).
我正在尝试在 d3 内调整窗口大小时重新绘制 SVG 图表,但不使用viewBox
和preserveAspectRatio
参数(我不喜欢他们处理文本的方式)。
I'm also trying to stick with d3's databinding design via Bostock's suggestionwhen appending a single element (not based on backed data).
在附加单个元素(不基于支持数据)时,我还尝试通过 Bostock 的建议坚持使用 d3 的数据绑定设计。
I have something that boils down to this (jsFiddle). However the SVG element's width/height never get updated.
我有一些东西可以归结为这个(jsFiddle)。然而,SVG 元素的宽度/高度永远不会更新。
HTML
HTML
<div class="chart-container">
<button class="user-option">Some User Options</button>
<div class="svg-container"></div>
</div>
Javascript
Javascript
$(window).on("resize", function () {
draw();
});
function draw() {
var container = d3.select('.chart-container');
var drawWidth = Math.round(0.80 * container.node().clientWidth);
var drawHeight = Math.round(drawWidth * (3 / 4)); // Fixing a 4/3 aspect ratio
/*
* Use an inner g element as the SVG canvas in order to set and forget margins.
* See http://bl.ocks.org/mbostock/3019563
*/
var margin = {
top: 10,
right: 30,
bottom: 50,
left: 40
};
var width = drawWidth - margin.left - margin.right;
var height = drawHeight - margin.top - margin.bottom;
var svg = container.select(".svg-container").selectAll('svg')
.data([0]) // Single data element to create SVG if it doesn't exist
.enter().append("svg")
.attr("width", drawWidth)
.attr("height", drawHeight)
.append("g")
.attr("class", "canvas")
// jsFiddle doesn't translate correctly, maybe because of frames???
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
console.debug(svg.node()); // null on resize???
// Add some random SVG element
svg.selectAll('rect')
.data([0]) // Single data element to create SVG if it doesn't exist
.enter().append('rect')
.attr({
x: 0,
y: 0,
width: drawWidth - margin.right - margin.left,
height: drawHeight - margin.bottom - margin.top
});
}
采纳答案by lebolo
Thanks, I was able to get to the correct solution from all of your answers! However, neither answer was able to update the SVG on resize ANDkeep the svg
variable as the g
element (to stick with the margin convention). I ended up doing
谢谢,我能够从您的所有答案中找到正确的解决方案!然而,无论答案是能够更新调整大小的SVG和保持svg
变量作为g
元素(坚持使用保证金约定)。我最终做了
// Create SVG element (if it doesn't exist)
var svg = container.select(".svg-container").selectAll('svg').data([null]);
svg.enter().append("svg");
svg.attr({width: drawWidth, height: drawHeight}); // apply to enter + update selections
// Create g element (if it doesn't exist) and remap the svg variable
svg = svg.selectAll(".canvas").data([null]);
svg.enter().append("g") // apply to enter selection only
.attr("class", "canvas")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
回答by CupawnTae
The root problem here is that your svg variable is not being assigned the <svg>
element selection, it's being assigned the end result of the chained method calls, which the first time round is the <g>
element, and after that is empty because there's no 'enter' selection.
这里的根本问题是你的 svg 变量没有被分配<svg>
元素选择,它被分配了链接方法调用的最终结果,第一轮是<g>
元素,之后是空的,因为没有“输入”选择.
So first thing to do is change to
所以首先要做的是改变
var svg = container.select(".svg-container").selectAll('svg').data([0]);
// now you have a reference to the svg selection
On first execution, the update selection will be empty and the enter selection will have a single element. You then bind this to a new <svg>
element:
第一次执行时,更新选择将为空,输入选择将只有一个元素。然后将其绑定到一个新<svg>
元素:
svg.enter()
.append("svg")
.append("g")
// note that from this point you're setting attributes on the <g>, not the <svg>
.attr("class", "canvas")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
This append operation also adds the element to the update selection stored in svg
.
此追加操作还将元素添加到存储在svg
.
On resize, the enter selection will be empty, but the update selection in svg
will already contain the existing <svg>
element. So either way, at this point you can set attributes on the svg
selection - it will work for both cases.
调整大小时,输入选择将为空,但更新选择svg
将已包含现有<svg>
元素。因此,无论哪种方式,此时您都可以在svg
选择上设置属性- 它适用于两种情况。
svg.attr("width", drawWidth)
.attr("height", drawHeight);
Updated fiddle http://jsfiddle.net/3dgn5pz8/5/
回答by Quince
@Pablo Navarro's answer is close the only issue is that svg on the redraw will not be your svg element but an array, use the same technique of separating the two executions but specifically select your svg again to change the width and height
@Pablo Navarro 的回答很接近唯一的问题是重绘上的 svg 不是您的 svg 元素而是一个数组,使用相同的技术来分离两次执行但再次专门选择您的 svg 以更改宽度和高度
var svg = container.select(".svg-container").selectAll('svg')
.data([0]) // Single data element to create SVG if it doesn't exist
.enter().append("svg")
.append("g")
.attr("class", "canvas")
// jsFiddle doesn't translate correctly, maybe because of frames???
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
then
然后
container.select(".svg-container").select('svg').attr("width", drawWidth).attr("height", drawHeight)
回答by Pablo Navarro
You are only setting the width and height of the svg element on enter, if the element already exists, it isn't updated. Try updating the element after the creation of the element (and the child group):
您只是在输入时设置 svg 元素的宽度和高度,如果该元素已存在,则不会更新。在创建元素(和子组)后尝试更新元素:
var svg = container.select(".svg-container").selectAll('svg')
.data([0]) // Single data element to create SVG if it doesn't exist
.enter().append("svg")
.append("g")
.attr("class", "canvas")
// jsFiddle doesn't translate correctly, maybe because of frames???
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.attr("width", drawWidth).attr("height", drawHeight)
Regards,
问候,