【问题标题】:angularjs call watch when 2 arrays have been updated更新2个数组时,angularjs调用watch
【发布时间】:2016-12-20 17:00:12
【问题描述】:

我已经制作了一个 angularjs 指令来绘制一个 d3 力导向图。此图表会定期更新,包含新的节点和链接。

最近,我注意到当图表更新时,它会重绘 2 倍,这需要很长时间。部分原因是我必须先更新节点数组,然后更新边数组,每个都会触发重绘。我希望在两者都更新后调用手表。

我已经看到很多关于如何处理 OR 关系的问题,但 我特别希望在两个节点 AND 链接都更新后重绘。

这是我当前的指令:

graphs.directive('myGraph', [function () {

    function renderGraph(scope, elem) {

        drawGraph(scope.data, scope.data.params || {}, elem);

        scope.$watchCollection('data', function (newData) {
            drawGraph(newData, scope.data.params || {}, elem);
        });
    }

    function drawGraph(data, params, elem) {

        const rawSvg = elem.find(".svg")[0];

        forceDirectedGraph.create(data.nodes, data.links, data.nodeTypes, rawSvg, params);
    }

    return {
        scope: {
            data: '='
        },
        templateUrl: 'graph.html',
        link: renderGraph
    }
}]);

这是我更新图表的方式:

//initialization code:
$scope.graph = { links:[], nodes:[], params:{ /*stuff*/} }

//graph update code:
$http.get(url).then( function(response) {
    links = [];
    nodes = [];

    //process and format links and nodes for d3 from request

    $scope.graph.links = links;
    $scope.graph.nodes = nodes;

});

【问题讨论】:

    标签: javascript angularjs d3.js


    【解决方案1】:

    我想到了几个选项,但都不是很好——尽管我倾向于 #1。但不确定它们是否适合您的特定需求:

    选项 1

    向名为shouldRedrawdata 对象添加一个新属性。在 $http.get 成功回调开始时将其设置为 false。数据更新完成后将其设置为 true。在 $watch 中,仅在设置时重绘:

    //initialization code:
    $scope.graph = { links:[], nodes:[], shouldRedraw:true, params:{ /*stuff*/} }
    
    //graph update code:
    $http.get(url).then( function(response) {
        $scope.graph.shouldRedraw = false;
    
        links = [];
        nodes = [];
    
        //process and format links and nodes for d3 from request
    
        $scope.graph.links = links;
        $scope.graph.nodes = nodes;
        $scope.graph.shouldRedraw = true;
    });
    
    // the watch
    scope.$watchCollection('data', function (newData) {
        if (newData.shouldRedraw === true) {
            drawGraph(newData, scope.data.params || {}, elem);
        }
    });
    

    选项 2

    更新您的 myGraph 指令以接受 linksnodesparams 值作为单独的范围输入。然后 $watch linksnodes 变量。有一个默认为 false 的标志 isStagedForRedraw。先更新linksnodes会触发设置标志,第二个会触发重绘和取消设置标志:

    var isStagedForRedraw = false;
    
    scope.$watchGroup(['links', 'nodes'], function (newValues, oldValues, scope) {
        if (isStagedForRedraw) {
            drawGraph({links:scope.links, nodes:scope.nodes}, scope.data.params || {}, elem);
            isStagedForRedraw = false;
        } else {
            isStagedForRedraw = true;
        }
    });
    

    选项 3

    让指令跟踪 data 对象,就像它没有一样,还要跟踪 data.linksdata.nodes 值的 JSON 化值。在观看时,JSONify 的新值 data.linksdata.nodes。如果两者都更改,则重绘并更新跟踪的 JSON 化值。如果只改变了一个,不要做任何事情。

    【讨论】:

    • 谢谢!所以到目前为止的结果:选项 2 在我第一次刷新页面时不喜欢显示图表,但会在随后的导航中显示。选项 1 是我到目前为止所要做的。但是,当我离开一个页面并返回它时,它仍然绘制 2x :( 。但是对于其他情况(页面保持打开状态,图形从请求和初始页面加载更新)它只绘制一次 - 所以有进展。
    • 它绘制了两次,因为 (1) 您在第一次初始化图形对象时默认 shouldRedraw 为 true,以及 (2) 因为您在创建手表之前显式绘制图形。为了防止它绘制两次,只需将shouldRedraw默认为false:$scope.graph = { links:[], nodes:[], shouldRedraw:false, params:{ /*stuff*/} };
    • 我在创建范围对象时预先将draw 设置为 false(否则你是 100% 正确的)只是为了好玩,在手表外取出 drawGraph 语句——一切似乎都正常!我想我以前需要它,但现在不需要。非常感谢!
    猜你喜欢
    • 2013-10-03
    • 2016-08-05
    • 2016-11-05
    • 2014-10-27
    • 1970-01-01
    • 2015-06-12
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多