D3& Angular:在窗口调整大小上调整多个绘图大小的最佳方法是什么?

时间:2017-05-04 11:49:18

标签: javascript html angularjs d3.js svg

我有一个包含三个D3 JS v3图和一些表格数据的报告页面。当窗口最大化时页面看起来很棒,但是当用户调整浏览器窗口大小时,它开始表现得很奇怪,即每个绘图溢出包含div等。

经过一番研究后,我发现我只需要为每个情节设置根svg的viewBox属性,即

var margin = {top: 40, right: 20, bottom: 20, left: 20},
    width = 450 - margin.left - margin.right,
    height = 370 - margin.top - margin.bottom;
var chartSvg = d3.select("#myPlotDivId")
            .append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
            .attr("preserveAspectRatio", "xMidYMid meet")
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

这可以在特定的AngularJS控制器中完成,没问题。但是,每次调整窗口大小时,我还需要更新所有三个绘图svg。有nice JSFiddle demonstrating this

var aspect = chartSvg.width() / chartSvg.height(),
    container = chartSvg.parent();
$(window).on("resize", function() {
   var targetWidth = container.width();
   chartSvg.attr("width", targetWidth);
   chartSvg.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");

但是,我更喜欢在控制器和我创建图表的功能中执行此操作...我该怎么做?我不希望在调用我的控制器的页面中挂起一个Window事件,或者为此创建一个全局指令。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

首先,我希望你有一些角度组件/指令包装d3代码,如果没有 - 这是你应该做的。 然后这个组件应该接受宽度和高度:

app.component('myd3Plot', ...
width: '<',
height: '<'

在父控制器/组件中,您可以监听窗口大小并调整子图大小:

window.on('resize', function() {
   vm.child1.height = ...
   vm.child2.height = ...
})

<myd3-plot height="$ctrl.child1.height"...
<myd3-plot height="$ctrl.child2.height"...

答案 1 :(得分:1)

最后我按如下方式做了,即将窗口组件注入我的控制器并定义onresize事件处理程序:

class ReportCtrl {
    // 1) inject the window into my controller
    constructor(private $window: IWindowService, ...) {
        // etc ...

        // 2) reusable function to resize a d3 js plot
        var resizePlot = function (divId: string) {
            var container = d3.select(divId);
            var svg = container.select("svg");
            var aspect = svg.attr("width") / svg.attr("height");
            var targetWidth = container.node().getBoundingClientRect().width;
            svg.attr("width", targetWidth);
            svg.attr("height", Math.round(targetWidth / aspect));         
        };

        // 3) hook on the window onresize event
        $window.onresize = function (ev: UIEvent) {
            resizePlot("#hist");
            resizePlot("#scatter1");
            resizePlot("#scatter2");
        };  
    }
}