OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * This is a view class showing tree-menu. | |
7 * @param {Object} profiler Must have addListener method. | |
8 * @construct | |
9 */ | |
10 var MenuView = function(profiler) { | |
11 this.profiler_ = profiler; | |
12 this.placeholder_ = '#category-menu'; | |
13 | |
14 // Update graph view and menu view when profiler model changed. | |
15 profiler.addListener('changed', this.redraw_.bind(this)); | |
16 profiler.addListener('changed:selected', this.selectNode_.bind(this)); | |
17 }; | |
18 | |
19 /** | |
20 * Highlight the node being selected. | |
21 * @param {string} id Model id. | |
22 * @private | |
23 */ | |
24 MenuView.prototype.selectNode_ = function(id) { | |
25 var $tree = this.$tree_; | |
26 var node = $tree.tree('getNodeById', id); | |
27 $tree.tree('selectNode', node); | |
28 $tree.tree('scrollToNode', node); | |
29 }; | |
30 | |
31 /** | |
32 * Update menu view when model updated. | |
33 * @param {Array.<Object>} models | |
34 * @private | |
35 */ | |
36 MenuView.prototype.redraw_ = function(models) { | |
37 function convert(origin, target) { | |
38 target.label = origin.name; | |
39 target.id = origin.id; | |
40 | |
41 if ('children' in origin) { | |
42 target.children = []; | |
43 origin.children.forEach(function(originChild) { | |
44 var targetChild = {}; | |
45 target.children.push(targetChild); | |
46 convert(originChild, targetChild); | |
47 }); | |
48 } | |
49 } | |
50 | |
51 function merge(left, right) { | |
52 if (!('children' in right) && 'children' in left) | |
53 return; | |
54 if ('children' in right && !('children' in left)) | |
55 left.children = right.children; | |
56 if ('children' in right && 'children' in left) { | |
57 right.children.forEach(function(child) { | |
58 // Find child with the same label in right tree. | |
59 var index = left.children.reduce(function(previous, current, index) { | |
60 if (child.label === current.label) | |
61 return index; | |
62 return previous; | |
63 }, -1); | |
64 if (index === -1) | |
65 left.children.push(child); | |
66 else | |
67 merge(child, left.children[index]); | |
68 }); | |
69 } | |
70 } | |
71 | |
72 var self = this; | |
73 | |
74 // Merge trees in all snapshots. | |
75 var union = null; | |
76 models.forEach(function(model) { | |
77 var data = {}; | |
78 convert(model, data); | |
79 if (!union) | |
80 union = data; | |
81 else | |
82 merge(union, data); | |
83 }); | |
84 | |
85 // Draw breakdown menu. | |
86 var data = [union]; | |
87 if (!this.$tree_) { | |
88 this.$tree_ = $(this.placeholder_).tree({ | |
89 data: data, | |
90 autoOpen: true, | |
91 onCreateLi: function(node, $li) { | |
92 // TODO(junjianx): Add checkbox to decide the breakdown visibility. | |
93 } | |
94 }); | |
95 | |
96 // Delegate click event to profiler. | |
97 this.$tree_.bind('tree.click', function(event) { | |
98 event.preventDefault(); | |
99 self.profiler_.setSelected(event.node.id); | |
100 }); | |
101 } else { | |
102 this.$tree_.tree('loadData', data); | |
103 } | |
104 }; | |
OLD | NEW |