Skip to content

Commit

Permalink
feat: updated fact_statistics.js for dark mode
Browse files Browse the repository at this point in the history
  • Loading branch information
jstucke committed Nov 28, 2024
1 parent 5077d10 commit 7fef875
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"esversion": 8
"esversion": 9
}
4 changes: 0 additions & 4 deletions src/test/unit/web_interface/test_app_jinja_filter_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ def _get_chart_element_count():
{
'data': [1696, 207, 9],
'backgroundColor': ['#4062fa', '#149df1', '#18cde4'],
'borderColor': '#fff',
'borderWidth': 2,
}
],
},
Expand All @@ -62,8 +60,6 @@ def _get_chart_element_count():
{
'data': [1696, 207, 9],
'backgroundColor': ['#4062fa', '#a0faa1'],
'borderColor': '#fff',
'borderWidth': 2,
}
],
},
Expand Down
2 changes: 1 addition & 1 deletion src/web_interface/components/jinja_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def data_to_chart_limited(self, data, limit: int | None = None, color_list=None)
color_list = get_color_list(len(value_list), limit=limit) if color_list is None else color_list
return {
'labels': label_list,
'datasets': [{'data': value_list, 'backgroundColor': color_list, 'borderColor': '#fff', 'borderWidth': 2}],
'datasets': [{'data': value_list, 'backgroundColor': color_list}],
}

def _get_chart_element_count(self):
Expand Down
189 changes: 130 additions & 59 deletions src/web_interface/static/js/fact_statistics.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
function get_extended_tooltip(element, data){
function getExtendedTooltip(element, data) {
const value = data.datasets[element.datasetIndex].data[element.index];
const sum = data.datasets[element.datasetIndex].data.reduce(function(pv, cv) { return pv + cv; }, 0);
const sum = data.datasets[element.datasetIndex].data.reduce((pv, cv) => pv + cv, 0);
const percent = Math.round((value / sum) * 1000) / 10;
return value + " (" + percent + "%)";
return `${value} (${percent}%)`;
}

function get_extended_tooltip_value_percentage_pairs(element, data){
function getExtendedTooltipValuePercentagePairs(element, data) {
const percent = _round(data.datasets[element.datasetIndex].percentage[element.index], 2);
const value = data.datasets[element.datasetIndex].data[element.index];
return value + " (" + percent + " %)";
return `${value} (${percent}%)`;
}

function _round(value, decimals){
return Number(Math.round(value*100+'e'+decimals)+'e-'+decimals);
function _round(value, decimals) {
return Number(Math.round(value * 100 + 'e' + decimals) + 'e-' + decimals);
}

function _truncate(str){
function _truncate(str) {
if (str.length > 20) {
return str.substr(0, 17) + '...';
return str.slice(0, 17) + '...';
} else {
return str;
}
}

function get_full_title(tooltipItems, data) {
function getFullTitle(tooltipItems, data) {
return data.labels[tooltipItems[0].index];
}

let chart_options = {
let chartOptions = {
legend: {position: "bottom", display: false},
tooltips: {
callbacks: {
label: get_extended_tooltip,
title: get_full_title,
label: getExtendedTooltip,
title: getFullTitle,
}
},
scales: {
Expand All @@ -41,98 +41,169 @@ let chart_options = {
}
};

let chart_options_value_percentage_pairs = {
legend: {position: "bottom", display: false},
let chartOptionsValuePercentagePairs = {
...chartOptions,
tooltips: {
callbacks: {
label: get_extended_tooltip_value_percentage_pairs,
title: get_full_title,
label: getExtendedTooltipValuePercentagePairs,
title: getFullTitle,
}
},
scales: {
xAxes: [{display: false, ticks: {beginAtZero: true}}],
yAxes: [{ticks: {callback: _truncate}}],
}
};

function _add(a, b){
function _add(a, b) {
return a + b;
}

function set_links(canvas_id, any_chart, link) {

document.getElementById(canvas_id).onclick = function(evt){
const points = any_chart.getElementsAtEvent(evt);
const label = any_chart.data.labels[points[0]._index];
function setLinks(canvasId, chart, link) {
document.getElementById(canvasId).onclick = (evt) => {
const points = chart.getElementsAtEvent(evt);
const label = chart.data.labels[points[0]._index];
if ((points[0] !== undefined) && (label !== "rest"))
window.location = link.replace("PLACEHOLDER", label);
};

}

function set_links_from_data(canvas_id, chart, link) {

document.getElementById(canvas_id).onclick = function(evt){
function setLinksFromData(canvasId, chart, link) {
document.getElementById(canvasId).onclick = (evt) => {
const points = chart.getElementsAtEvent(evt);
if (chart.data.datasets[0].links !== undefined) {
const key = chart.data.datasets[0].links[points[0]._index];
window.location = link.replace("PLACEHOLDER", key);
}
};

}

function create_horizontal_bar_chart(canvas_id, chart_data, link, value_percentage_present_flag = false, links_in_data = false) {
const ctx = document.getElementById(canvas_id);
let chart_opt, max;
let charts = {};

if (value_percentage_present_flag) {
chart_opt = chart_options_value_percentage_pairs;
max = chart_data.datasets[0].data.slice(0, 2).reduce(_add);
function createHorizontalBarChart(canvasId, chartData, link, isPercentage = false, linksInData = false) {
let options, max;

if (isPercentage) {
options = chartOptionsValuePercentagePairs;
max = chartData.datasets[0].data.slice(0, 2).reduce(_add);
} else {
chart_opt = chart_options;
max = Math.max(...chart_data.datasets[0].data);
options = chartOptions;
max = Math.max(...chartData.datasets[0].data);
}
chart_opt.scales.xAxes[0].ticks.max = max * 1.05;
options.scales.xAxes[0].ticks.max = max * 1.05;

let BarChart = new Chart(
ctx, {
document.getElementById(canvasId),
{
type: "horizontalBar",
data: chart_data,
options: chart_opt
data: chartData,
options: options
}
);

if (links_in_data) {
set_links_from_data(canvas_id, BarChart, link);
if (linksInData) {
setLinksFromData(canvasId, BarChart, link);
} else {
set_links(canvas_id, BarChart, link);
setLinks(canvasId, BarChart, link);
}

BarChart.options.scales.yAxes[0].ticks.fontColor = getTextColor();
charts[canvasId] = BarChart;
return BarChart;
}

function create_pie_chart(canvas_id, chart_data, link) {
const ctx = document.getElementById(canvas_id);

function createPieChart(canvasId, chartData, link) {
chartData.datasets[0].borderColor = getLineColor();
chartData.datasets[0].borderWidth = 3;
let PieChart = new Chart(
ctx, {
document.getElementById(canvasId),
{
type: "doughnut",
data: chart_data,
data: chartData,
options: {
legend: {
fullWidth: false,
position: 'right',
labels: {
boxWidth: 20,
fontSize: 10
}
}
}
fontSize: 10,
fontColor: getTextColor(),
},
},
},
},
);
setLinks(canvasId, PieChart, link);
charts[canvasId] = PieChart;
return PieChart;
}

function createHistogram(canvasId, chartData) {
let options = {
legend: {display: false},
scales: {
xAxes: [{ticks: {fontColor: getTextColor()}}],
yAxes: [
{
ticks: {
beginAtZero: true,
fontColor: getTextColor(),
},
scaleLabel: {
display: true,
labelString: "Firmware Releases",
fontColor: getTextColor(),
},
},
],
},
};
let dateBarChart = new Chart(
document.getElementById(canvasId),
{
type: "bar",
data: chartData,
options: options,
}
);
charts[canvasId] = dateBarChart;
return dateBarChart;
}

set_links(canvas_id, PieChart, link);
const lightTextColor = "#212529";
const darkTextColor = "#ccc";
const lightLineColor = "#f8f9fa";
const darkLineColor = "#343a40";

return PieChart;
function getTextColor() {
return isDark() ? darkTextColor : lightTextColor;
}

function getLineColor() {
return isDark() ? darkLineColor : lightLineColor;
}

function isDark() {
return document.getElementById("darkModeSwitch").checked;
}

function updateChartColors() {
Object.entries(charts).forEach(([id, chart]) => {
try {
if (chart.config.type === "doughnut") {
chart.options.legend.labels.fontColor = getTextColor();
chart.data.datasets[0].borderColor = getLineColor();
} else if (chart.config.type === "horizontalBar") {
chart.options.scales.yAxes[0].ticks.fontColor = getTextColor();
} else if (chart.config.type === "bar") {
chart.options.scales.yAxes[0].ticks.fontColor = getTextColor();
chart.options.scales.yAxes[0].scaleLabel.fontColor = getTextColor();
chart.options.scales.xAxes[0].ticks.fontColor = getTextColor();
} else {
console.log(`Error: unknown chart type ${chart.config.type}!`);
}
chart.update();
} catch (e) {
console.log(`Error when changing lightness of ${id} chart: ${e}`);
}
});
}

$(document).ready(function () {
document.getElementById("darkModeSwitch").addEventListener("change", updateChartColors);
});
43 changes: 16 additions & 27 deletions src/web_interface/templates/show_statistic.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ <h3 class="mb-3">Firmware Statistics</h3>
{% call macros.stats_panel(title) %}
<canvas id="{{ key }}_canvas" width="80%" height="80%"></canvas>
<script>
create_pie_chart(
canvas_id="{{ key }}_canvas",
chart_data={{ data_set[key] | sort_chart_list_by_value | data_to_chart_limited | safe }},
createPieChart(
canvasId="{{ key }}_canvas",
chartData={{ data_set[key] | sort_chart_list_by_value | data_to_chart_limited | safe }},
link="{{ query_url + query | json_dumps | urlencode }}"
);
</script>
Expand All @@ -171,9 +171,9 @@ <h3 class="mb-3">Firmware Statistics</h3>
{% call macros.stats_panel("Exploit Mitigations") %}
<canvas id="exploit_mitigations_canvas" width="100%" height="{{ stats['exploit_mitigations_stats']['exploit_mitigations'] | get_canvas_height }}"></canvas>
<script>
create_horizontal_bar_chart(
canvas_id="exploit_mitigations_canvas",
chart_data={{ stats['exploit_mitigations_stats']['exploit_mitigations'] | data_to_chart_with_value_percentage_pairs(limit=13) | safe }},
createHorizontalBarChart(
canvasId="exploit_mitigations_canvas",
chartData={{ stats['exploit_mitigations_stats']['exploit_mitigations'] | data_to_chart_with_value_percentage_pairs(limit=13) | safe }},
link="{{ query_url + {'processed_analysis.exploit_mitigations.summary': {'$regex': 'PLACEHOLDER'}} | json_dumps | urlencode }}",
expl_mit_flag=true
);
Expand All @@ -190,11 +190,11 @@ <h3 class="mb-3">Firmware Statistics</h3>
{% call macros.stats_panel("ELF Executables") %}
<canvas id="elf_executable_canvas" width="100%" height="{{ stats['elf_executable_stats']['executable_stats'] | get_canvas_height }}"></canvas>
<script>
create_horizontal_bar_chart(
canvas_id="elf_executable_canvas",
chart_data={{ stats["elf_executable_stats"]["executable_stats"] | data_to_chart_with_value_percentage_pairs(limit=11) | safe }},
createHorizontalBarChart(
canvasId="elf_executable_canvas",
chartData={{ stats["elf_executable_stats"]["executable_stats"] | data_to_chart_with_value_percentage_pairs(limit=11) | safe }},
link="{{ query_url + {'processed_analysis.file_type.full': {'$regex': 'PLACEHOLDER'}} | json_dumps | urlencode }}",
value_percentage_present_flag=true, links_in_data=true
isPercentage=true, linksInData=true
);
</script>
{% endcall %}
Expand Down Expand Up @@ -253,27 +253,16 @@ <h5 class="card-title mt-2"><i class="far fa-calendar-alt"></i> Release Date Sta
<div class="card-text">
<canvas id="release_date_canvas"></canvas>
<script>
var options = {
legend: {display: false},
scales: {
yAxes: [{
ticks: {beginAtZero: true},
scaleLabel: {display: true, labelString: "Firmware Releases"}
}]
}
};

var data = {{ stats["release_date_stats"]["date_histogram_data"] | data_to_chart | safe }};
var ctx = document.getElementById("release_date_canvas");
var DateBarChart = new Chart(ctx, {type: "bar", data: data, options: options});

const DateBarChart = createHistogram(
"release_date_canvas",
{{ stats["release_date_stats"]["date_histogram_data"] | data_to_chart | safe }}
);
document.getElementById("release_date_canvas").onclick = function(evt){
var points = DateBarChart.getElementsAtEvent(evt);
var date = DateBarChart.data.labels[points[0]._index];
const points = DateBarChart.getElementsAtEvent(evt);
const date = DateBarChart.data.labels[points[0]._index];
if (points[0] !== undefined)
window.location = "database/browse?date=" + date;
};

</script>
</div>
</div>
Expand Down

0 comments on commit 7fef875

Please sign in to comment.