chg: [distributionGraph] Added bar chart and deferred distribution data

fetching process
pull/4309/head
mokaddem 2019-03-11 14:24:15 +01:00
parent f2c2ade76b
commit 6a7efb92c5
3 changed files with 263 additions and 189 deletions

View File

@ -145,15 +145,25 @@
'key' => __('Distribution'),
'value_class' => ($event['Event']['distribution'] == 0) ? 'privateRedText' : '',
'html' => sprintf(
'%s %s',
'%s %s %s %s',
($event['Event']['distribution'] == 4) ?
sprintf('<a href="%s%s">%s</a>', $baseurl . '/sharing_groups/view/', h($event['SharingGroup']['id']), h($event['SharingGroup']['name'])) :
h($distributionLevels[$event['Event']['distribution']]),
sprintf(
'<span class="%s" data-object-id="%s" data-object-context="event" data-shown="false"></span><div style="display: none">%s</div>',
'<span id="distribution_graph_bar" style="margin-left: 5px;" data-object-id="%s" data-object-context="event"></span>',
h($event['Event']['id'])
),
sprintf(
'<it class="%s" data-object-id="%s" data-object-context="event" data-shown="false"></it><div style="display: none">%s</div>',
'useCursorPointer fa fa-info-circle distribution_graph',
h($event['Event']['id']),
$this->element('view_event_distribution_graph')
),
sprintf(
'<it type="button" id="showAdvancedSharingButton" title="%s" class="%s" aria-hidden="true" style="margin-left: 5px;" onclick="%s"></it>',
'Toggle advanced sharing network viewer',
'fa fa-share-alt useCursorPointer',
'showAdvancedSharing(this)'
)
)
);

View File

@ -181,7 +181,7 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) {
}
// text
var span = document.createElement('span');
span.classList.add('useCursorPointer', 'pbDistributionText', 'badge');
span.classList.add('useCursorPointer', 'pbDistributionText', 'badge', 'toBeCleared');
span.onclick = clickHandlerPbText;
span.innerHTML = distribution[d].key;
span.setAttribute('data-distribution', d);
@ -212,7 +212,7 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) {
// tick
var span = document.createElement('span');
span.classList.add('pbDistributionTick');
span.classList.add('pbDistributionTick', 'toBeCleared');
spanOffset += (pbStep*(d+1))+spanOffset > pb_container.clientWidth ? -3 : 0; // avoid the tick width to go further than the pb
span.style.left = (pbStep*(d+1))+spanOffset + 'px';
span.style.top = d % 2 == 0 ? pb_top-15+'px' : pb_top+0+'px';
@ -258,6 +258,170 @@ function showAdvancedSharing(clicked) {
construct_network();
}
function construct_piechart(data) {
$('.toBeCleared').remove();
$(".loadingPopover").hide();
// DISTRIBUTION PROGRESSBAR
$('#eventdistri_pb_invalid').tooltip();
$('#eventdistri_pb').tooltip();
$('#eventdistri_pb_min').tooltip();
$('#eventdistri_pb_invalid').click(function(evt) { clickHandlerPb(evt); });
$('#eventdistri_pb').click(function(evt) { clickHandlerPb(evt); });
$('#eventdistri_pb_min').click(function(evt) { clickHandlerPb(evt); });
$('#eventdistri_sg_pb').click(function(evt) { clickHandlerPb(evt); });
// pb
var event_dist, min_distri, max_distri;
if (event_distribution == 4) { // if distribution is sharing group, overwrite default behavior
var event_dist = 1;
var min_distri = 0;
var max_distri = 0;
} else {
var event_dist = event_distribution+1; // +1 to reach the first level
var min_distri = get_minimum_distribution(data.event, event_dist)+1; // +1 to reach the first level
var max_distri = get_maximum_distribution(data.event)+1; // +1 to reach the first level
}
add_level_to_pb(data.distributionInfo, data.additionalDistributionInfo, event_dist);
var bg_width_step = $('#eventdistri_pb_background').width()/4.0;
$('#eventdistri_pb_min').width(bg_width_step*min_distri + 'px');
$('#eventdistri_pb_min').data("distribution", fill_distri_for_search(0, min_distri-1));
$('#eventdistri_pb_min').attr('aria-valuenow', min_distri*25);
$('#eventdistri_pb_min').css("background", "#ffc107");
$('#eventdistri_pb').width((event_dist)*25+'%');
$('#eventdistri_pb').data("distribution", fill_distri_for_search(0, event_dist-1));
$('#eventdistri_pb').attr('aria-valuenow', (event_dist-min_distri)*25);
$('#eventdistri_pb').css("background", "#28a745");
$('#eventdistri_pb_invalid').width((max_distri-event_dist)*25+'%');
$('#eventdistri_pb_invalid').data("distribution", fill_distri_for_search(event_dist, max_distri-1));
$('#eventdistri_pb_invalid').attr('aria-valuenow', (max_distri-event_dist)*25);
$('#eventdistri_pb_invalid').css("background", "#dc3545");
// SHARING GROUPS
var sgNum = data.additionalDistributionInfo[4].length;
var sgPerc = (sgNum/data.allSharingGroup.length)*100;
if (sgPerc > 0) {
$('#eventdistri_sg_pb').width(sgPerc+'%');
$('#eventdistri_sg_pb').tooltip({
title: "Distribution among sharing group: "+(sgNum +' / '+ data.allSharingGroup.length)
});
$('#eventdistri_sg_pb').data("distribution", '4' + (event_distribution==4 ? '|5' : ''));
$('#eventdistri_sg_pb').attr('aria-valuenow', sgPerc);
$('#eventdistri_sg_pb').css("background", "#7a86e0");
} else { // no sg, hide it and display
$('#eventdistri_sg_pb_background').text("Event not distributed to any sharing group");
}
$('.sharingGroup_pb_text').popover({
placement: 'bottom',
trigger: 'click',
title: 'Sharing group',
content: '<b>Distribution description:</b> ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]) + '<div class="distributionInfo" style="height: 150px; width: 300px; position: relative; left: 25%;"><canvas class="distributionInfo" id="sg_distribution_graph_canvas" height="150px" width="300px"></canvas></div>',
container: 'body',
html: true,
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title distributionInfo"></h3><div class="popover-content distributionInfo" style="white-space: pre-wrap"></div></div>'
})
.click(function() {
generate_pie_chart(data.sharingGroupRepartition, document.getElementById('sg_distribution_graph_canvas'));
});
// doughtnut
var doughnutColors = ['#ff0000', '#ff9e00', '#957200', '#008000', 'rgb(122, 134, 224)'];
var doughnut_dataset = [
{
label: "All",
data: data.event,
hidden: false,
backgroundColor: doughnutColors
},
{
label: "Attributes",
data: data.attribute,
hidden: false,
backgroundColor: doughnutColors
},
{
label: "Object attributes",
data: data.obj_attr,
hidden: false,
backgroundColor: doughnutColors
},
];
var ctx = document.getElementById("distribution_graph_canvas");
ctx.onclick = function(evt) { clickHandlerGraph(evt); };
var count = 0;
for (var i=0, n=data.event.length; i < n; i++) {
count += data.event[i];
}
if (count > 0) {
distribution_chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }),
distribution: data.distributionInfo,
datasets: doughnut_dataset,
},
options: {
title: {
display: false
},
animation: {
duration: 500
},
tooltips: {
callbacks: {
label: function(item, data) {
return data.datasets[item.datasetIndex].label
+ " - " + data.labels[item.index]
+ ": " + data.datasets[item.datasetIndex].data[item.index];
}
}
}
},
});
} else {
var canvas = ctx;
ctx = canvas.getContext("2d");
ctx.font = "30px Comic Sans MS";
ctx.textAlign = "center";
ctx.fillText("Event is empty", canvas.width/2, canvas.height/2);
}
// create checkboxes
var div = $('<div class="toBeCleared"></div>');
div.addClass('distribution_checkboxes_dataset');
var distri_graph = $('#eventdistri_graph');
var distriOffset = distri_graph.offset();
var distriHeight = distri_graph.height()/2;
div.css({left: '50px'});
for (var i in doughnut_dataset) {
var item = doughnut_dataset[i];
var label = $('<label></label>');
label.addClass('useCursorPointer');
label.css({'user-select': 'none'});
var checkbox = $('<input type="checkbox">');
checkbox.data('dataset-index', i);
checkbox.prop('checked', true);
checkbox.change(function(evt) {
var clickedIndex = $(this).data('dataset-index');
var isChecked = $(this).prop('checked');
distribution_chart.config.data.datasets[clickedIndex].hidden = !isChecked;
distribution_chart.update();
});
label.append(checkbox);
label.append(item.label);
div.append(label);
}
distri_graph.append(div);
}
function construct_network(target_distribution, scope_text, overwriteSg) {
cacheAddedOrgName = {};
if (advancedSharingNetwork !== undefined) {
@ -684,30 +848,7 @@ function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) {
});
}
$(document).ready(function() {
var rightBtn = '<span type="button" id="showAdvancedSharingButton" title="Toggle advanced sharing network viewer" class="fa fa-share-alt useCursorPointer" aria-hidden="true" style="float:right; margin-left: 5px;" onclick="showAdvancedSharing(this)"></span>';
var pop = $('.distribution_graph').popover({
title: "<b>Distribution graph</b> [atomic event]" + rightBtn,
html: true,
content: function() { return $('#distribution_graph_container').html(); },
template : '<div class="popover" role="tooltip" style="z-index: 1;"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content" style="padding-left: '+spanOffset_orig+'px; padding-right: '+spanOffset_orig*2+'px;"></div></div>'
});
$('body').on('mouseup', function(e) {
if(!$(e.target).hasClass('distributionInfo') && !($(e.target).hasClass('pbDistributionText') || $(e.target).hasClass('sharingGroup_pb_text'))) {
$('.pbDistributionText').popover('hide');
$('.sharingGroup_pb_text').popover('hide');
}
});
$('.distribution_graph').click(function() {
if ($(this).data('shown') == 'true') {
$(this).data('shown', 'false');
$('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 200, function() { $('#advancedSharingNetworkWrapper').remove(); });
return;
} else {
$(this).data('shown', 'true');
}
function fetchDistributionData(callback) {
$.ajax({
url: "/events/"+"getDistributionGraph"+"/"+scope_id+"/event.json",
dataType: 'json',
@ -720,169 +861,53 @@ $(document).ready(function() {
},
success: function( data, textStatus, jQxhr ){
distributionData = data;
$(".loadingPopover").hide();
// DISTRIBUTION PROGRESSBAR
$('#eventdistri_pb_invalid').tooltip();
$('#eventdistri_pb').tooltip();
$('#eventdistri_pb_min').tooltip();
$('#eventdistri_pb_invalid').click(function(evt) { clickHandlerPb(evt); });
$('#eventdistri_pb').click(function(evt) { clickHandlerPb(evt); });
$('#eventdistri_pb_min').click(function(evt) { clickHandlerPb(evt); });
$('#eventdistri_sg_pb').click(function(evt) { clickHandlerPb(evt); });
// pb
var event_dist, min_distri, max_distri;
if (event_distribution == 4) { // if distribution is sharing group, overwrite default behavior
var event_dist = 1;
var min_distri = 0;
var max_distri = 0;
} else {
var event_dist = event_distribution+1; // +1 to reach the first level
var min_distri = get_minimum_distribution(data.event, event_dist)+1; // +1 to reach the first level
var max_distri = get_maximum_distribution(data.event)+1; // +1 to reach the first level
if (callback !== undefined) {
callback(data);
}
add_level_to_pb(data.distributionInfo, data.additionalDistributionInfo, event_dist);
var bg_width_step = $('#eventdistri_pb_background').width()/4.0;
$('#eventdistri_pb_min').width(bg_width_step*min_distri + 'px');
$('#eventdistri_pb_min').data("distribution", fill_distri_for_search(0, min_distri-1));
$('#eventdistri_pb_min').attr('aria-valuenow', min_distri*25);
$('#eventdistri_pb_min').css("background", "#ffc107");
$('#eventdistri_pb').width((event_dist)*25+'%');
$('#eventdistri_pb').data("distribution", fill_distri_for_search(0, event_dist-1));
$('#eventdistri_pb').attr('aria-valuenow', (event_dist-min_distri)*25);
$('#eventdistri_pb').css("background", "#28a745");
$('#eventdistri_pb_invalid').width((max_distri-event_dist)*25+'%');
$('#eventdistri_pb_invalid').data("distribution", fill_distri_for_search(event_dist, max_distri-1));
$('#eventdistri_pb_invalid').attr('aria-valuenow', (max_distri-event_dist)*25);
$('#eventdistri_pb_invalid').css("background", "#dc3545");
// SHARING GROUPS
var sgNum = data.additionalDistributionInfo[4].length;
var sgPerc = (sgNum/data.allSharingGroup.length)*100;
if (sgPerc > 0) {
$('#eventdistri_sg_pb').width(sgPerc+'%');
$('#eventdistri_sg_pb').tooltip({
title: "Distribution among sharing group: "+(sgNum +' / '+ data.allSharingGroup.length)
});
$('#eventdistri_sg_pb').data("distribution", '4' + (event_distribution==4 ? '|5' : ''));
$('#eventdistri_sg_pb').attr('aria-valuenow', sgPerc);
$('#eventdistri_sg_pb').css("background", "#7a86e0");
} else { // no sg, hide it and display
$('#eventdistri_sg_pb_background').text("Event not distributed to any sharing group");
}
$('.sharingGroup_pb_text').popover({
placement: 'bottom',
trigger: 'click',
title: 'Sharing group',
content: '<b>Distribution description:</b> ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]) + '<div class="distributionInfo" style="height: 150px; width: 300px; position: relative; left: 25%;"><canvas class="distributionInfo" id="sg_distribution_graph_canvas" height="150px" width="300px"></canvas></div>',
container: 'body',
html: true,
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title distributionInfo"></h3><div class="popover-content distributionInfo" style="white-space: pre-wrap"></div></div>'
})
.click(function() {
generate_pie_chart(data.sharingGroupRepartition, document.getElementById('sg_distribution_graph_canvas'));
});
// doughtnut
var doughnutColors = ['#ff0000', '#ff9e00', '#957200', '#008000', 'rgb(122, 134, 224)'];
var doughnut_dataset = [
{
label: "All",
data: data.event,
hidden: false,
backgroundColor: doughnutColors
},
{
label: "Attributes",
data: data.attribute,
hidden: false,
backgroundColor: doughnutColors
},
{
label: "Object attributes",
data: data.obj_attr,
hidden: false,
backgroundColor: doughnutColors
},
];
var ctx = document.getElementById("distribution_graph_canvas");
ctx.onclick = function(evt) { clickHandlerGraph(evt); };
var count = 0;
for (var i=0, n=data.event.length; i < n; i++) {
count += data.event[i];
}
if (count > 0) {
distribution_chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }),
distribution: data.distributionInfo,
datasets: doughnut_dataset,
},
options: {
title: {
display: false
},
animation: {
duration: 500
},
tooltips: {
callbacks: {
label: function(item, data) {
return data.datasets[item.datasetIndex].label
+ " - " + data.labels[item.index]
+ ": " + data.datasets[item.datasetIndex].data[item.index];
}
}
}
},
});
} else {
var canvas = ctx;
ctx = canvas.getContext("2d");
ctx.font = "30px Comic Sans MS";
ctx.textAlign = "center";
ctx.fillText("Event is empty", canvas.width/2, canvas.height/2);
}
// create checkboxes
var div = $('<div></div>');
div.addClass('distribution_checkboxes_dataset');
var distri_graph = $('#eventdistri_graph');
var distriOffset = distri_graph.offset();
var distriHeight = distri_graph.height()/2;
div.css({left: '50px'});
for (var i in doughnut_dataset) {
var item = doughnut_dataset[i];
var label = $('<label></label>');
label.addClass('useCursorPointer');
label.css({'user-select': 'none'});
var checkbox = $('<input type="checkbox">');
checkbox.data('dataset-index', i);
checkbox.prop('checked', true);
checkbox.change(function(evt) {
var clickedIndex = $(this).data('dataset-index');
var isChecked = $(this).prop('checked');
distribution_chart.config.data.datasets[clickedIndex].hidden = !isChecked;
distribution_chart.update();
});
label.append(checkbox);
label.append(item.label);
div.append(label);
}
distri_graph.append(div);
},
error: function( jqXhr, textStatus, errorThrown ){
console.log( errorThrown );
}
});
}
function drawBarChart(data) {
var csv = "scope,val\n";
var lineCount = 0;
data.event.forEach(function(d, i) {
var scope = data.distributionInfo[i].key;
var val = d;
csv += scope + "," + val + "\n";
lineCount++;
})
sparklineBar('#distribution_graph_bar', csv, lineCount);
}
$(document).ready(function() {
var rightBtn = '<div style="float:right;"><span type="button" id="reloadDistributionGraph" title="Reload Distribution Graph" class="fa fa-refresh useCursorPointer" aria-hidden="true" style="margin-left: 5px;" onclick="fetchDistributionData(function(data) { construct_piechart(data); });"></span></div>';
var pop = $('.distribution_graph').popover({
title: "<b>Distribution graph</b> [atomic event]" + rightBtn,
html: true,
content: function() { return $('#distribution_graph_container').html(); },
template : '<div class="popover" role="tooltip" style="z-index: 1;"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content" style="padding-left: '+spanOffset_orig+'px; padding-right: '+spanOffset_orig*2+'px;"></div></div>'
}).on('shown.bs.popover', function(e) {
if (distributionData !== undefined) {
construct_piechart(distributionData);
} else {
fetchDistributionData(function(data) { construct_piechart(data); });
}
}).on('hide.bs.popover', function(e) {
// $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 200, function() { $('#advancedSharingNetworkWrapper').remove(); });
});
$('body').on('mouseup', function(e) {
if(!$(e.target).hasClass('distributionInfo') && !($(e.target).hasClass('pbDistributionText') || $(e.target).hasClass('sharingGroup_pb_text'))) {
$('.pbDistributionText').popover('hide');
$('.sharingGroup_pb_text').popover('hide');
}
});
fetchDistributionData(function(data) {
drawBarChart(data);
});
});

View File

@ -3998,6 +3998,45 @@ function liveFilter() {
}
}
function sparklineBar(elemId, data, lineCount) {
data = d3.csv.parse(data);
var y_max = 0;
data.forEach(function(e) {
e = parseInt(e.val);
y_max = e > y_max ? e : y_max;
});
// y_max = Math.log(y_max)
var WIDTH = 50;
var HEIGHT = 25;
var DATA_COUNT = lineCount;
var BAR_WIDTH = (WIDTH - DATA_COUNT) / DATA_COUNT;
var x = d3.scale.linear().domain([0, DATA_COUNT]).range([0, WIDTH]);
var y = d3.scale.linear().domain([0, y_max]).range([0, HEIGHT]);
var distributionGraphBarTooltip = d3.select("body").append("div")
.attr("class", "distributionGraphBarTooltip")
.style("opacity", 0);
var svg = d3.select(elemId).append('svg')
.attr('width', WIDTH)
.attr('height', HEIGHT)
.append('g');
svg.selectAll('.bar').data(data)
.enter()
.append('g')
.attr('title', function(d, i) { return d.scope + ': ' + d.val })
.attr('class', 'DGbar')
.append('rect')
.attr('class', 'bar')
.attr('x', function(d, i) { return x(i); })
.attr('y', function(d, i) { return HEIGHT - y(d.val); })
.attr('width', BAR_WIDTH)
.attr('height', function(d, i) { return y(d.val); })
.attr('fill', '#3465a4');
$('.DGbar').tooltip({container: 'body'});
}
(function(){
"use strict";
$(".datepicker").datepicker({