重新调整大小时重绘SVG

时间:2014-08-28 18:05:00

标签: javascript svg d3.js

我正在尝试在d3内的窗口大小调整上重绘SVG图表,但没有使用viewBoxpreserveAspectRatio参数(我不喜欢他们如何处理文本)。

在添加单个元素(不基于支持的数据)时,我也试图通过Bostock的suggestion坚持使用d3的数据绑定设计。

我有一些归结为此(jsFiddle)。但是SVG元素的宽度/高度永远不会更新。

HTML

<div class="chart-container">
    <button class="user-option">Some User Options</button>
    <div class="svg-container"></div>
</div>

的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
            });
}

4 个答案:

答案 0 :(得分:3)

这里的根本问题是你的svg变量没有被分配<svg>元素选择,它被分配了链式方法调用的最终结果,第一次是{{{ 1}}元素,之后是空的,因为没有&#39;输入&#39;选择。

首先要做的是改为

<g>

首次执行时,更新选择将为空,输入选择将包含单个元素。然后将其绑定到新的var svg = container.select(".svg-container").selectAll('svg').data([0]); // now you have a reference to the svg selection 元素:

<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 + ")"); 中存储的更新选择。

在调整大小时,输入选择将为空,但svg中的更新选择将包含现有的svg元素。因此,无论哪种方式,您都可以在<svg>选项上设置属性 - 它适用于两种情况。

svg

更新了小提琴http://jsfiddle.net/3dgn5pz8/5/

答案 1 :(得分:1)

@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 + ")");

然后

container.select(".svg-container").select('svg').attr("width", drawWidth).attr("height", drawHeight)

http://jsfiddle.net/LLvuq0Lm/9/

答案 2 :(得分:1)

谢谢,我能够从你的所有答案中找到正确的解决方案!但是,没有一个答案能够在调整大小时更新SVG AND svg变量保留为g元素(以坚持margin convention)。我最终做了

// 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 + ")");

答案 3 :(得分:0)

您只在输入时设置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)

此致