@rws-framework/ai-tools 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bin/add-v.sh +10 -0
- package/.bin/emerge.sh +11 -0
- package/.emerge-vis-output/rws-server/emerge-file_result_dependency_graph.graphml +2067 -0
- package/.emerge-vis-output/rws-server/emerge-filesystem_graph.graphml +1505 -0
- package/.emerge-vis-output/rws-server/emerge-statistics-and-metrics.json +1 -0
- package/.emerge-vis-output/rws-server/emerge-statistics-metrics.txt +1147 -0
- package/.emerge-vis-output/rws-server/html/emerge.html +501 -0
- package/.emerge-vis-output/rws-server/html/jsconfig.json +9 -0
- package/.emerge-vis-output/rws-server/html/resources/css/custom.css +211 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_common.js +45 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_data.js +13 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_git.js +1414 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_graph.js +539 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_heatmap.js +220 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_hull.js +180 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_main.js +1003 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_search.js +71 -0
- package/.emerge-vis-output/rws-server/html/resources/js/emerge_ui.js +199 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.css +4124 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.rtl.css +4123 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.rtl.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.rtl.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-grid.rtl.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.css +488 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.rtl.css +485 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.rtl.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.rtl.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-reboot.rtl.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.css +4266 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.rtl.css +4257 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.rtl.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.rtl.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap-utilities.rtl.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.css +10878 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.rtl.css +10842 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.rtl.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.rtl.min.css +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/css/bootstrap.rtl.min.css.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.bundle.js +7075 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.bundle.js.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.bundle.min.js +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.bundle.min.js.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.esm.js +5202 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.esm.js.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.esm.min.js +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.esm.min.js.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.js +5249 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.js.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.min.js +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/bootstrap/js/bootstrap.min.js.map +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/d3/d3.v7.8.4.min.js +2 -0
- package/.emerge-vis-output/rws-server/html/vendors/d3/d3.v7.min.js +2 -0
- package/.emerge-vis-output/rws-server/html/vendors/dark-mode-switch/css/dark-mode.css +148 -0
- package/.emerge-vis-output/rws-server/html/vendors/dark-mode-switch/js/dark-mode-switch.min.js +1 -0
- package/.emerge-vis-output/rws-server/html/vendors/daterangepicker/daterangepicker.css +410 -0
- package/.emerge-vis-output/rws-server/html/vendors/daterangepicker/daterangepicker.min.js +8 -0
- package/.emerge-vis-output/rws-server/html/vendors/daterangepicker/moment.min.js +7 -0
- package/.emerge-vis-output/rws-server/html/vendors/hull/hull.js +373 -0
- package/.emerge-vis-output/rws-server/html/vendors/jquery/jquery-3.6.0.min.js +2 -0
- package/.emerge-vis-output/rws-server/html/vendors/popper/popper.min.js +6 -0
- package/.emerge-vis-output/rws-server/html/vendors/simpleheat/simpleheat.js +141 -0
- package/.eslintrc.json +53 -0
- package/README.md +862 -0
- package/package.json +49 -0
- package/src/index.ts +22 -0
- package/src/models/convo/ConvoLoader.ts +415 -0
- package/src/models/convo/VectorStore.ts +33 -0
- package/src/models/prompts/_prompt.ts +388 -0
- package/src/services/VectorStoreService.ts +15 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
function initHeatmapSwitches() {
|
|
2
|
+
// normal heatmap
|
|
3
|
+
$("#switchActivateHeatmap").on('change', function() {
|
|
4
|
+
if ($(this).is(':checked')) {
|
|
5
|
+
heatmapActive = true
|
|
6
|
+
if ($("#switchMergeHeatmap").is(':checked')) {
|
|
7
|
+
$("#switchMergeHeatmap").prop('checked', false);
|
|
8
|
+
heatmapMerged = false
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if ($("#switchChurnHeatmap").is(':checked')) {
|
|
12
|
+
$("#switchChurnHeatmap").prop('checked', false);
|
|
13
|
+
heatmapChurn = false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if ($("#switchHotspotHeatmap").is(':checked')) {
|
|
17
|
+
$("#switchHotspotHeatmap").prop('checked', false);
|
|
18
|
+
heatmapHotspot = false
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
heatmapActive = false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
simulationUpdate();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// hybrid/merged heatmap
|
|
28
|
+
$("#switchMergeHeatmap").on('change', function() {
|
|
29
|
+
if ($(this).is(':checked')) {
|
|
30
|
+
heatmapMerged = true
|
|
31
|
+
if ($("#switchActivateHeatmap").is(':checked')) {
|
|
32
|
+
$("#switchActivateHeatmap").prop('checked', false);
|
|
33
|
+
heatmapActive = false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ($("#switchChurnHeatmap").is(':checked')) {
|
|
37
|
+
$("#switchChurnHeatmap").prop('checked', false);
|
|
38
|
+
heatmapChurn = false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ($("#switchHotspotHeatmap").is(':checked')) {
|
|
42
|
+
$("#switchHotspotHeatmap").prop('checked', false);
|
|
43
|
+
heatmapHotspot = false
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
heatmapMerged = false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
simulationUpdate();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// churn heatmap
|
|
53
|
+
$("#switchChurnHeatmap").on('change', function() {
|
|
54
|
+
if ($(this).is(':checked')) {
|
|
55
|
+
heatmapChurn = true
|
|
56
|
+
if ($("#switchActivateHeatmap").is(':checked')) {
|
|
57
|
+
$("#switchActivateHeatmap").prop('checked', false);
|
|
58
|
+
heatmapActive = false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if ($("#switchMergeHeatmap").is(':checked')) {
|
|
62
|
+
$("#switchMergeHeatmap").prop('checked', false);
|
|
63
|
+
heatmapMerged = false
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if ($("#switchHotspotHeatmap").is(':checked')) {
|
|
67
|
+
$("#switchHotspotHeatmap").prop('checked', false);
|
|
68
|
+
heatmapHotspot = false
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
heatmapChurn = false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
simulationUpdate();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// hotspot heatmap
|
|
78
|
+
$("#switchHotspotHeatmap").on('change', function() {
|
|
79
|
+
if ($(this).is(':checked')) {
|
|
80
|
+
heatmapHotspot = true
|
|
81
|
+
if ($("#switchActivateHeatmap").is(':checked')) {
|
|
82
|
+
$("#switchActivateHeatmap").prop('checked', false);
|
|
83
|
+
heatmapActive = false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if ($("#switchMergeHeatmap").is(':checked')) {
|
|
87
|
+
$("#switchMergeHeatmap").prop('checked', false);
|
|
88
|
+
heatmapMerged = false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if ($("#switchChurnHeatmap").is(':checked')) {
|
|
92
|
+
$("#switchChurnHeatmap").prop('checked', false);
|
|
93
|
+
heatmapChurn = false
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
heatmapHotspot = false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
simulationUpdate();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* * MARK: - Drawing a heatmap for normal / hybrid (merged) mode
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
function calculateHeatmapScore(node) {
|
|
109
|
+
|
|
110
|
+
let totalScore = 0
|
|
111
|
+
|
|
112
|
+
if (normalHeatmapIsActive() || mergedHeatmapIsActive() ) {
|
|
113
|
+
|
|
114
|
+
let score = analysis_config['heatmap']['score']['base']
|
|
115
|
+
let slocScore = 0
|
|
116
|
+
let fanoutScore = 0
|
|
117
|
+
|
|
118
|
+
if (analysis_config['heatmap']['metrics']['active']['sloc'] == true) {
|
|
119
|
+
// add weighted sloc metric if present
|
|
120
|
+
if ('metric_sloc_in_entity' in node) {
|
|
121
|
+
slocScore = node.metric_sloc_in_entity * analysis_config['heatmap']['metrics']['weights']['sloc']
|
|
122
|
+
}
|
|
123
|
+
if ('metric_sloc_in_file' in node) {
|
|
124
|
+
slocScore = node.metric_sloc_in_file * analysis_config['heatmap']['metrics']['weights']['sloc']
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (analysis_config['heatmap']['metrics']['active']['fan_out'] == true) {
|
|
129
|
+
// add weighted fan-out metric is present
|
|
130
|
+
if ('metric_fan_out_dependency_graph' in node) {
|
|
131
|
+
fanoutScore = node.metric_fan_out_dependency_graph * analysis_config['heatmap']['metrics']['weights']['fan_out']
|
|
132
|
+
}
|
|
133
|
+
if ('metric_fan_out_inheritance_graph' in node) {
|
|
134
|
+
fanoutScore = node.metric_fan_out_inheritance_graph * analysis_config['heatmap']['metrics']['weights']['fan_out']
|
|
135
|
+
}
|
|
136
|
+
if ('metric_fan_out_complete_graph' in node) {
|
|
137
|
+
fanoutScore = node.metric_fan_out_complete_graph * analysis_config['heatmap']['metrics']['weights']['fan_out']
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// limit the total score to the heatmap limit parameter, since the rendering seems to be buggy if this is exceeded
|
|
142
|
+
totalScore = score + slocScore + fanoutScore
|
|
143
|
+
if (totalScore > analysis_config['heatmap']['score']['limit']) {
|
|
144
|
+
totalScore = analysis_config['heatmap']['score']['limit']
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
} else if (churnHeatmapIsActive()) {
|
|
148
|
+
let score = analysis_config['churn_heatmap']['score']['base']
|
|
149
|
+
let churnScore = 0
|
|
150
|
+
|
|
151
|
+
if (node.hasOwnProperty('metric_git_code_churn')) {
|
|
152
|
+
if (analysis_config['churn_heatmap']['metrics']['active']['churn'] == true) {
|
|
153
|
+
churnScore = node.metric_git_code_churn * analysis_config['churn_heatmap']['metrics']['weights']['churn']
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
totalScore = score + churnScore
|
|
157
|
+
if (totalScore > analysis_config['churn_heatmap']['score']['limit']) {
|
|
158
|
+
totalScore = analysis_config['churn_heatmap']['score']['limit']
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
} else if (hotspotHeatmapIsActive()) {
|
|
163
|
+
// approach: let's define a hotspot as a product of the following factors
|
|
164
|
+
// 1. code churn over a given time period
|
|
165
|
+
// 2. whitespace complexity over a given time period
|
|
166
|
+
// 3. SLOC over a given time period
|
|
167
|
+
// 4. connectivity based on dependencies inside the network (i.e. fan-in / fan-out)
|
|
168
|
+
|
|
169
|
+
let score = analysis_config['hotspot_heatmap']['score']['base']
|
|
170
|
+
let churnScore = 0
|
|
171
|
+
let ws_complexity_score = 0
|
|
172
|
+
let connectivity_score = 0
|
|
173
|
+
let sloc_score = 0
|
|
174
|
+
|
|
175
|
+
if (node.hasOwnProperty('metric_git_code_churn') && node.hasOwnProperty('metric_git_ws_complexity') ) {
|
|
176
|
+
if (analysis_config['hotspot_heatmap']['metrics']['active']['churn'] == true && analysis_config['hotspot_heatmap']['metrics']['active']['ws_complexity'] == true) {
|
|
177
|
+
|
|
178
|
+
churnScore = node.metric_git_code_churn * analysis_config['hotspot_heatmap']['metrics']['weights']['churn'] * 2.0
|
|
179
|
+
ws_complexity_score = node.metric_git_code_churn * analysis_config['hotspot_heatmap']['metrics']['weights']['ws_complexity'] * 0.75
|
|
180
|
+
|
|
181
|
+
if ('metric_fan_out_dependency_graph' in node) {
|
|
182
|
+
connectivity_score = node.metric_fan_out_dependency_graph * 1.5
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
totalScore = (churnScore + ws_complexity_score + connectivity_score )
|
|
186
|
+
if (totalScore > analysis_config['hotspot_heatmap']['score']['limit'] * 1.25 ) {
|
|
187
|
+
totalScore = analysis_config['hotspot_heatmap']['score']['limit'] * 1.25
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return totalScore
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function drawHeatMap(context) {
|
|
198
|
+
|
|
199
|
+
if (normalHeatmapIsActive() || mergedHeatmapIsActive()) {
|
|
200
|
+
heat.max(analysis_config['heatmap']['score']['limit']);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (churnHeatmapIsActive()) {
|
|
204
|
+
heat.max(analysis_config['churn_heatmap']['score']['limit']);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (hotspotHeatmapIsActive()) {
|
|
208
|
+
heat.max(analysis_config['hotspot_heatmap']['score']['limit']);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
heat.clear();
|
|
212
|
+
currentGraph.nodes.forEach(function(node, i) {
|
|
213
|
+
heat.add([node.x, node.y, calculateHeatmapScore(node)])
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
heat.draw()
|
|
217
|
+
|
|
218
|
+
// reset alpha from heatmap rendering
|
|
219
|
+
context.globalAlpha = 1;
|
|
220
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* * MARK: - Rendering concave hulls of clusters.
|
|
3
|
+
*/
|
|
4
|
+
function setupGraphClustersById() {
|
|
5
|
+
clusterMap = {}
|
|
6
|
+
currentGraph.nodes.forEach(function(node, i) {
|
|
7
|
+
let nodeClusterId = 0
|
|
8
|
+
|
|
9
|
+
if (node.hasOwnProperty('metric_file_result_dependency_graph_louvain_modularity_in_file')) {
|
|
10
|
+
nodeClusterId = node.metric_file_result_dependency_graph_louvain_modularity_in_file
|
|
11
|
+
} else if (node.hasOwnProperty('metric_entity_result_dependency_graph_louvain_modularity_in_entity')) {
|
|
12
|
+
nodeClusterId = node.metric_entity_result_dependency_graph_louvain_modularity_in_entity
|
|
13
|
+
} else if (node.hasOwnProperty('metric_entity_result_inheritance_graph_louvain_modularity_in_entity')) {
|
|
14
|
+
nodeClusterId = node.metric_entity_result_inheritance_graph_louvain_modularity_in_entity
|
|
15
|
+
} else if (node.hasOwnProperty('metric_entity_result_complete_graph_louvain_modularity_in_entity')) {
|
|
16
|
+
nodeClusterId = node.metric_entity_result_complete_graph_louvain_modularity_in_entity
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
nodeClusterId = nodeClusterId.toString()
|
|
20
|
+
|
|
21
|
+
if (nodeClusterId in clusterMap) {
|
|
22
|
+
clusterMap[nodeClusterId].push(node)
|
|
23
|
+
} else {
|
|
24
|
+
clusterMap[nodeClusterId] = []
|
|
25
|
+
clusterMap[nodeClusterId].push(node)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// console.log(clusterMap)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function onMouseOverHullMenuNode(clusterId) {
|
|
33
|
+
if (!selectedClusterHullIds.includes(clusterId)) {
|
|
34
|
+
addHighlightToSVGCircle(clusterId)
|
|
35
|
+
}
|
|
36
|
+
hoveredClusterHullId = clusterId
|
|
37
|
+
simulationUpdate()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function onMouseOutHullMenuNode(clusterId) {
|
|
41
|
+
if (!selectedClusterHullIds.includes(clusterId)) {
|
|
42
|
+
removeHighlightFromSVGCircle(clusterId)
|
|
43
|
+
}
|
|
44
|
+
hoveredClusterHullId = undefined
|
|
45
|
+
simulationUpdate()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function addHighlightToSVGCircle(clusterId) {
|
|
49
|
+
let hullNodeSVG = $("#clusterHullNodeSVGCircle-" + clusterId)
|
|
50
|
+
hullNodeSVG.attr('stroke', 'yellow')
|
|
51
|
+
hullNodeSVG.attr('stroke-width', '2')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function removeHighlightFromSVGCircle(clusterId) {
|
|
55
|
+
let hullNodeSVG = $("#clusterHullNodeSVGCircle-" + clusterId)
|
|
56
|
+
hullNodeSVG.attr('stroke', 'black')
|
|
57
|
+
hullNodeSVG.attr('stroke-width', '1')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function onClickHullMenuNode(clusterId) {
|
|
61
|
+
if (selectedClusterHullIds.includes(clusterId)) {
|
|
62
|
+
removeItemAll(selectedClusterHullIds, clusterId)
|
|
63
|
+
removeHighlightFromSVGCircle(clusterId)
|
|
64
|
+
} else {
|
|
65
|
+
selectedClusterHullIds.push(clusterId)
|
|
66
|
+
addHighlightToSVGCircle(clusterId)
|
|
67
|
+
}
|
|
68
|
+
simulationUpdate()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function createClusterHullMenu() {
|
|
72
|
+
// check if there is at least one cluster
|
|
73
|
+
if ("0" in clusterMap) {
|
|
74
|
+
// build menu
|
|
75
|
+
let clusterMenuHtml = "<div id=\"clusterHullContainer\"> \
|
|
76
|
+
<div class=\"row\">"
|
|
77
|
+
|
|
78
|
+
clusterMenuHtml += "<div class=\"svg-column\">"
|
|
79
|
+
|
|
80
|
+
// insert SVG circles
|
|
81
|
+
let iteration = 0
|
|
82
|
+
Object.keys(clusterMap).forEach(function(key) {
|
|
83
|
+
|
|
84
|
+
if (iteration < maxClusterHulls) {
|
|
85
|
+
let firstNode = clusterMap[key][0]
|
|
86
|
+
let color = nodeColorByModularity(firstNode)
|
|
87
|
+
|
|
88
|
+
let svgElement = "<svg onmouseover=\"onMouseOverHullMenuNode(" + key + ")\" onmouseout=\"onMouseOutHullMenuNode(" + key + ")\" onclick=\"onClickHullMenuNode(" + key + ")\" height=\"16px\" width=\"16px\" viewBox=\"0 0 18 18\"><circle id=\"clusterHullNodeSVGCircle-" + key + "\" cx=\"5\" cy=\"10\" r=\"4\" \
|
|
89
|
+
stroke=\"black\" stroke-width=\"1\" fill=\""
|
|
90
|
+
svgElement += color
|
|
91
|
+
svgElement += "\" /></svg>"
|
|
92
|
+
clusterMenuHtml += svgElement
|
|
93
|
+
}
|
|
94
|
+
iteration += 1
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// finish menu and append to div
|
|
98
|
+
clusterMenuHtml += "</div></div></div>"
|
|
99
|
+
d3.select("#clusterHullMenu").html(clusterMenuHtml)
|
|
100
|
+
|
|
101
|
+
// add tooltips to cluster hull nodes
|
|
102
|
+
iteration = 0
|
|
103
|
+
Object.keys(clusterMap).forEach(function(clusterId) {
|
|
104
|
+
if (iteration < maxClusterHulls) {
|
|
105
|
+
let clusterToolTipDescription = "<u>Cluster metrics</u><br>"
|
|
106
|
+
let clusterMetrics = clusterMetricsMap[clusterId]
|
|
107
|
+
|
|
108
|
+
// TODO: check why clusterMetrics can be undefined
|
|
109
|
+
if (clusterMetrics !== undefined) {
|
|
110
|
+
// add all cluster metrics that we can find
|
|
111
|
+
Object.keys(clusterMetrics).forEach(function(clusterMetric) {
|
|
112
|
+
let metricPrettyName = clusterMetric.replace(/_/gi, " ").replace(/metric/gi, "")
|
|
113
|
+
clusterToolTipDescription += metricPrettyName + ": " + "<b>" + clusterMetrics[clusterMetric] + "</b>" + "<br>"
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
$('#' + 'clusterHullNodeSVGCircle-' + clusterId).attr('data-bs-toggle', 'tooltip')
|
|
117
|
+
$('#' + 'clusterHullNodeSVGCircle-' + clusterId).attr('data-bs-title', clusterToolTipDescription)
|
|
118
|
+
$('#' + 'clusterHullNodeSVGCircle-' + clusterId).attr('data-bs-html', 'true')
|
|
119
|
+
$('#' + 'clusterHullNodeSVGCircle-' + clusterId).attr('data-bs-placement', 'bottom')
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
|
127
|
+
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getPointArrayForClusterId(id) {
|
|
131
|
+
let pointArray = []
|
|
132
|
+
let clusterId = id.toString()
|
|
133
|
+
|
|
134
|
+
if (clusterId in clusterMap) {
|
|
135
|
+
clusterMap[clusterId].forEach(function(node, i) {
|
|
136
|
+
pointArray.push([node.x, node.y])
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
return pointArray
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// calculate hull
|
|
143
|
+
function getHullFromPointArray(pointArray) {
|
|
144
|
+
let hullArray = hull(pointArray, 60)
|
|
145
|
+
return hullArray
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// draw a single cluster hull as a polygon
|
|
149
|
+
function drawHull(context, clusterId) {
|
|
150
|
+
let pointArray = getPointArrayForClusterId(clusterId)
|
|
151
|
+
let hullArray = getHullFromPointArray(pointArray)
|
|
152
|
+
let firstNodeInCluster = clusterMap[clusterId][0]
|
|
153
|
+
context.fillStyle = nodeColorByModularity(firstNodeInCluster, 0.2)
|
|
154
|
+
|
|
155
|
+
context.beginPath();
|
|
156
|
+
|
|
157
|
+
let firstPoint = hullArray[0]
|
|
158
|
+
context.moveTo(firstPoint[0], firstPoint[1]);
|
|
159
|
+
|
|
160
|
+
hullArray.forEach(function(arrayElement, i) {
|
|
161
|
+
context.lineTo(arrayElement[0], arrayElement[1]);
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
context.closePath();
|
|
165
|
+
context.fill();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// draw all required cluster hulls (selected/hovered nodes from the menu)
|
|
169
|
+
function drawHulls(context) {
|
|
170
|
+
|
|
171
|
+
// draw a hull if someone hovers ofer a hull menu cluster node
|
|
172
|
+
if (hoveredClusterHullId !== undefined) {
|
|
173
|
+
drawHull(context, hoveredClusterHullId)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// draw every hull was was selected by a mouse click before
|
|
177
|
+
selectedClusterHullIds.forEach(clusterId => {
|
|
178
|
+
drawHull(context, clusterId)
|
|
179
|
+
})
|
|
180
|
+
}
|