Updated report mobile version

This commit is contained in:
Luis Aleixo 2021-10-12 16:44:58 +02:00
parent 53e3b0cec6
commit 3ce30558b3
4 changed files with 353 additions and 185 deletions

View file

@ -1,93 +1,95 @@
/* Generate the concentration plot using d3 library. */
function draw_concentration_plot(svg_id, times, concentrations, exposed_presence_intervals) {
var visBoundingBox = d3.select(svg_id)
.node()
.getBoundingClientRect();
var time_format = d3.timeFormat('%H:%M');
// H:M time format for x axis.
var data = []
times.map((time, index) => data.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': concentrations[index] }))
// Prepare data
times.map((time, index) => data.push({'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': concentrations[index] }))
var vis = d3.select(svg_id),
width = visBoundingBox.width - 300,
height = visBoundingBox.height,
margins = { top: 30, right: 20, bottom: 50, left: 50 },
// Add main SVG element
var plot_div = document.getElementById(svg_id);
var vis = d3.select(plot_div).append('svg');
var xRange = d3.scaleTime().domain([data[0].hour, data[data.length - 1].hour]);
var xTimeRange = d3.scaleLinear().domain([data[0].time, data[data.length - 1].time]);
var bisecHour = d3.bisector((d) => { return d.hour; }).left;
// H:M time format for x axis.
xRange = d3.scaleTime().range([margins.left, width - margins.right]).domain([data[0].hour, data[data.length - 1].hour]),
xTimeRange = d3.scaleLinear().range([margins.left, width - margins.right]).domain([data[0].time, data[data.length - 1].time]),
bisecHour = d3.bisector((d) => { return d.hour; }).left,
yRange = d3.scaleLinear().range([height - margins.bottom, margins.top]).domain([0., Math.max(...concentrations)]),
xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d)),
yAxis = d3.axisLeft(yRange);
// Plot tittle.
plot_title(vis, width, margins.top, 'Mean concentration of virions');
var yRange = d3.scaleLinear().domain([0., Math.max(...concentrations)]);
// Line representing the mean concentration.
plot_scenario_data(vis, data, xTimeRange, yRange, '#1f77b4');
// X axis.
plot_x_axis(vis, height, width, margins, xAxis, 'Time of day');
// Y axis
plot_y_axis(vis, height, width, margins, yAxis, 'Mean concentration (virions/m³)')
var lineFunc = d3.line();
var draw_line = vis.append('svg:path')
.attr('stroke', '#1f77b4')
.attr('stroke-width', 2)
.attr('fill', 'none');
// Area representing the presence of exposed person(s).
exposed_presence_intervals.forEach(b => {
var curveFunc = d3.area()
.x(d => xTimeRange(d.time))
.y0(height - margins.bottom)
.y1(d => yRange(d.concentration));
vis.append('svg:path')
.attr('d', curveFunc(data.filter(d => {
return d.time >= b[0] && d.time <= b[1]
})))
var exposedArea = {};
var drawArea = {};
exposed_presence_intervals.forEach((b, index) => {
exposedArea[index] = d3.area();
drawArea[index] = vis.append('svg:path')
.attr('fill', '#1f77b4')
.attr('fill-opacity', '0.1');
})
});
// Plot tittle.
var plotTitleEl = vis.append('svg:foreignObject')
.attr("background-color", "transparent")
.attr('height', 30)
.style('text-align', 'center')
.html('<b>Mean concentration of virions</b>');
// X axis declaration.
var xAxisEl = vis.append('svg:g')
.attr('class', 'x axis');
// X axis label.
var xAxisLabelEl = vis.append('text')
.attr('class', 'x label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Time of day')
// Y axis declaration.
var yAxisEl = vis.append('svg:g')
.attr('class', 'y axis');
// Y axis label.
var yAxisLabelEl = vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Mean concentration (virions/m³)');
// Legend for the plot elements - line and area.
var size = 20
vis.append('rect')
.attr('x', width + size)
.attr('y', margins.top + size)
var legendLineIcon = vis.append('rect')
.attr('width', 20)
.attr('height', 3)
.style('fill', '#1f77b4');
vis.append('rect')
.attr('x', width + size)
.attr('y', 3 * size)
var legendAreaIcon = vis.append('rect')
.attr('width', 20)
.attr('height', 20)
.attr('fill', '#1f77b4')
.attr('fill-opacity', '0.1');
vis.append('text')
.attr('x', width + 3 * size)
.attr('y', margins.top + size)
var legendLineText = vis.append('text')
.text('Mean concentration')
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
vis.append('text')
.attr('x', width + 3 * size)
.attr('y', margins.top + 2 * size)
var legendAreaText = vis.append('text')
.text('Presence of exposed person(s)')
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
// Legend bounding box.
vis.append('rect')
// Legend bounding
var legendBBox = vis.append('rect')
.attr('width', 275)
.attr('height', 50)
.attr('x', width * 1.005)
.attr('y', margins.top + 5)
.attr('stroke', 'lightgrey')
.attr('stroke-width', '2')
.attr('rx', '5px')
@ -122,15 +124,111 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
.attr('x', 18)
.attr('y', 18);
vis.append('rect')
var toolBox = vis.append('rect')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.attr('width', width - margins.right)
.attr('height', height)
.on('mouseover', () => { focus.style('display', null); })
.on('mouseout', () => { focus.style('display', 'none'); })
.on('mousemove', mousemove);
function redraw() {
// Define width and height according to the screen size.
var div_width = plot_div.clientWidth;
var div_height = plot_div.clientHeight;
var graph_width = div_width;
var graph_height = div_height
if (div_width >= 900) { // For screens with width > 900px legend can be on the graph's right side.
var margins = { top: 30, right: 20, bottom: 50, left: 50 };
div_width = 900;
graph_width = div_width * (2/3);
}
else {
var margins = { top: 30, right: 5, bottom: 50, left: 20 };
graph_height = div_height * 0.85; // On mobile screen sizes we want the legend to be on the bottom of the graph.
};
// Use the extracted size to set the size of the SVG element.
vis.attr("width", div_width)
.attr('height', div_height);
// SVG components according to the width and height.
// Axis ranges.
xRange.range([margins.left, graph_width - margins.right]);
xTimeRange.range([margins.left, graph_width - margins.right]);
yRange.range([graph_height - margins.bottom, margins.top])
// Line.
lineFunc.defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yRange(d.concentration));
draw_line.attr("d", lineFunc(data));
// Area.
exposed_presence_intervals.forEach((b, index) => {
exposedArea[index].x(d => xTimeRange(d.time))
.y0(graph_height - margins.bottom)
.y1(d => yRange(d.concentration));
drawArea[index].attr('d', exposedArea[index](data.filter(d => {
return d.time >= b[0] && d.time <= b[1]
})));
});
// Title.
plotTitleEl.attr('width', graph_width);
// Axis.
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
var yAxis = d3.axisLeft(yRange);
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
.call(xAxis);
xAxisLabelEl.attr('x', (graph_width + margins.right) / 2)
.attr('y', graph_height * 0.97);
yAxisEl.attr('transform', 'translate(' + margins.left + ',0)').call(yAxis);
yAxisLabelEl.attr('x', (graph_height + margins.bottom) / 2)
.attr('y', (graph_height + margins.left) * 0.92)
.attr('transform', 'rotate(-90, 0,' + graph_height + ')');
// Legend on right side.
const size = 20;
if (plot_div.clientWidth >= 900) {
legendLineIcon.attr('x', graph_width + size)
.attr('y', margins.top + size);
legendLineText.attr('x', graph_width + 3 * size)
.attr('y', margins.top + size);
legendAreaIcon.attr('x', graph_width + size)
.attr('y', margins.top + 1.5 * size);
legendAreaText.attr('x', graph_width + 3 * size)
.attr('y', margins.top + 2 * size);
legendBBox.attr('x', graph_width * 1.005)
.attr('y', margins.top * 1.2);
}
// Legend on the bottom.
else {
legendLineIcon.attr('x', size * 0.5)
.attr('y', graph_height * 1.05);
legendLineText.attr('x', 2 * size)
.attr('y', graph_height * 1.05);
legendAreaIcon.attr('x', size * 0.50)
.attr('y', graph_height * 1.01 + size);
legendAreaText.attr('x', 2 * size)
.attr('y', graph_height + 1.7 * size);
legendBBox.attr('x', 1)
.attr('y', graph_height * 1.01);
}
// ToolBox.
toolBox.attr('width', graph_width - margins.right)
.attr('height', graph_height);
}
// Draw for the first time to initialize.
redraw();
function mousemove() {
var x0 = xRange.invert(d3.pointer(event, this)[0]),
i = bisecHour(data, x0, 1),
@ -141,12 +239,17 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
focus.select('#tooltip-time').text('x = ' + time_format(d.hour));
focus.select('#tooltip-concentration').text('y = ' + d.concentration.toFixed(2));
}
// Redraw based on the new size whenever the browser window is resized.
window.addEventListener("resize", redraw);
}
// Generate the alternative scenarios plot using d3 library.
// 'alternative_scenarios' is a dictionary with all the alternative scenarios
// 'times' is a list of times for all the scenarios
function draw_alternative_scenarios_plot(svg_id, width, height, alternative_scenarios, times) {
function draw_alternative_scenarios_plot(concentration_plot_svg_id, alternative_plot_svg_id, times, alternative_scenarios) {
// H:M format
var time_format = d3.timeFormat('%H:%M');
// D3 array of ten categorical colors represented as RGB hexadecimal strings.
@ -171,148 +274,169 @@ function draw_alternative_scenarios_plot(svg_id, width, height, alternative_scen
// We need one scenario to get the time range
var first_scenario = Object.values(data_for_scenarios)[0]
var vis = d3.select(svg_id),
width = width,
height = height,
margins = { top: 30, right: 20, bottom: 50, left: 50 },
// Add main SVG element
var alternative_plot_div = document.getElementById(alternative_plot_svg_id);
var vis = d3.select(alternative_plot_div).append('svg');
// H:M time format for x axis.
xRange = d3.scaleTime().range([margins.left, width - margins.right]).domain([first_scenario[0].hour, first_scenario[first_scenario.length - 1].hour]),
xTimeRange = d3.scaleLinear().range([margins.left, width - margins.right]).domain([times[0], times[times.length - 1]]),
var xRange = d3.scaleTime().domain([first_scenario[0].hour, first_scenario[first_scenario.length - 1].hour]);
var xTimeRange = d3.scaleLinear().domain([times[0], times[times.length - 1]]);
yRange = d3.scaleLinear().range([height - margins.bottom, margins.top]).domain([0., highest_concentration]),
xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d)),
yAxis = d3.axisLeft(yRange);
// Plot title.
plot_title(vis, width, margins.top, 'Mean concentration of virions');
var yRange = d3.scaleLinear().domain([0., highest_concentration]);
// Line representing the mean concentration for each scenario.
var lineFuncs = {}, draw_lines = {}, label_icons = {}, label_text = {};
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
var scenario_index = Object.keys(data_for_scenarios).indexOf(scenario_name)
// Line representing the mean concentration.
plot_scenario_data(vis, data, xTimeRange, yRange, colors[scenario_index])
lineFuncs[scenario_name] = d3.line();
draw_lines[scenario_name] = vis.append('svg:path')
.attr("stroke", colors[scenario_index])
.attr('stroke-width', 2)
.attr('fill', 'none');
// Legend for the plot elements - lines.
var size = 20 * (scenario_index + 1)
vis.append('rect')
.attr('x', width + 20)
.attr('y', margins.top + size)
label_icons[scenario_name] = vis.append('rect')
.attr('width', 20)
.attr('height', 3)
.style('fill', colors[scenario_index]);
vis.append('text')
.attr('x', width + 3 * 20)
.attr('y', margins.top + size)
label_text[scenario_name] = vis.append('text')
.text(scenario_name)
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
}
// Plot title.
var plotTitleEl = vis.append('svg:foreignObject')
.attr("background-color", "transparent")
.attr('height', 30)
.style('text-align', 'center')
.html('<b>Mean concentration of virions</b>');
// X axis.
plot_x_axis(vis, height, width, margins, xAxis, "Time of day");
var xAxisEl = vis.append('svg:g')
.attr('class', 'x axis');
// X axis label.
var xAxisLabelEl = vis.append('text')
.attr('class', 'x label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Time of day');
// Y axis declaration.
vis.append('svg:g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + margins.left + ',0)')
.call(yAxis);
var yAxisEl = vis.append('svg:g')
.attr('class', 'y axis');
// Y axis label.
vis.append('svg:text')
var yAxisLabelEl = vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('transform', 'rotate(-90, 0,' + height + ')')
.attr('text-anchor', 'middle')
.attr('x', (height + margins.bottom) / 2)
.attr('y', (height + margins.left) * 0.92)
.text('Mean concentration (virions/m³)');
// Legend bounding box.
vis.append('rect')
var legendBBox = vis.append('rect')
.attr('width', 275)
.attr('height', 25 * (Object.keys(data_for_scenarios).length))
.attr('x', width * 1.005)
.attr('y', margins.top + 5)
.attr('stroke', 'lightgrey')
.attr('stroke-width', '2')
.attr('rx', '5px')
.attr('ry', '5px')
.attr('stroke-linejoin', 'round')
.attr('fill', 'none');
}
function redraw() {
// Define width and height according to the screen size.
var div_width = document.getElementById(concentration_plot_svg_id).clientWidth;
var div_height = document.getElementById(concentration_plot_svg_id).clientHeight;
var graph_width = div_width;
var graph_height = div_height
if (div_width >= 900) { // For screens with width > 900px legend can be on the graph's right side.
var margins = { top: 30, right: 20, bottom: 50, left: 50 };
div_width = 900;
graph_width = div_width * (2/3);
}
else {
var margins = { top: 30, right: 5, bottom: 50, left: 20 };
graph_height = div_height * 0.8; // On mobile screen sizes we want the legend to be on the bottom of the graph.
};
// Functions used to build the plots' components
// Use the extracted size to set the size of the SVG element.
vis.attr("width", div_width)
.attr('height', div_height);
function plot_title(vis, width, margin_top, title) {
vis.append('svg:foreignObject')
.attr('width', width)
.attr('height', margin_top)
.attr('fill', 'none')
.append('xhtml:div')
.style('text-align', 'center')
.html(title);
// SVG components according to the width and height.
return vis;
}
// Axis ranges.
xRange.range([margins.left, graph_width - margins.right]);
xTimeRange.range([margins.left, graph_width - margins.right]);
yRange.range([graph_height - margins.bottom, margins.top]);
function plot_x_axis(vis, height, width, margins, xAxis, label) {
// X axis declaration
vis.append('svg:g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + (height - margins.bottom) + ')')
.call(xAxis);
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
var scenario_index = Object.keys(data_for_scenarios).indexOf(scenario_name)
// Lines.
lineFuncs[scenario_name].defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yRange(d.concentration));
draw_lines[scenario_name].attr("d", lineFuncs[scenario_name](data));
// X axis label.
vis.append('text')
.attr('class', 'x label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.attr('x', (width + margins.right) / 2)
.attr('y', height * 0.97)
.text(label);
// Legend on right side.
var size = 20 * (scenario_index + 1);
if (document.getElementById(concentration_plot_svg_id).clientWidth >= 900) {
label_icons[scenario_name].attr('x', graph_width + 20)
.attr('y', margins.top + size);
label_text[scenario_name].attr('x', graph_width + 3 * 20)
.attr('y', margins.top + size);
}
// Legend on the bottom.
else {
label_icons[scenario_name].attr('x', margins.left * 0.5)
.attr('y', graph_height + size);
label_text[scenario_name].attr('x', margins.left * 1.75)
.attr('y', graph_height + size);
}
return vis;
}
}
function plot_y_axis(vis, height, width, margins, yAxis, label) {
// Y axis declaration.
vis.append('svg:g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + margins.left + ',0)')
.call(yAxis);
// Title.
plotTitleEl.attr('width', graph_width);
// Y axis label.
vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('transform', 'rotate(-90, 0,' + height + ')')
.attr('text-anchor', 'middle')
.attr('x', (height + margins.bottom) / 2)
.attr('y', (height + margins.left) * 0.92)
.text(label);
// Axis.
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
var yAxis = d3.axisLeft(yRange);
return vis;
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
.call(xAxis);
xAxisLabelEl.attr('x', (graph_width + margins.right) / 2)
.attr('y', graph_height * 0.97)
}
yAxisEl.attr('transform', 'translate(' + margins.left + ',0)')
.call(yAxis);
yAxisLabelEl.attr('transform', 'rotate(-90, 0,' + graph_height + ')')
.attr('x', (graph_height + margins.bottom) / 2)
.attr('y', (graph_height + margins.left) * 0.92);
function plot_scenario_data(vis, data, xTimeRange, yRange, line_color) {
var lineFunc = d3.line()
.defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yRange(d.concentration))
.curve(d3.curveBasis);
// Legend on right side.
if (document.getElementById(concentration_plot_svg_id).clientWidth >= 900) {
legendBBox.attr('x', graph_width * 1.02)
.attr('y', margins.top * 1.15);
}
// Legend on the bottom.
else {
legendBBox.attr('x', 1)
.attr('y', graph_height * 1.01)
}
}
vis.append('svg:path')
.attr('d', lineFunc(data))
.attr("stroke", line_color)
.attr('stroke-width', 2)
.attr('fill', 'none');
// Draw for the first time to initialize.
redraw();
return vis;
// Redraw based on the new size whenever the browser window is resized.
window.addEventListener("resize", redraw);
}

View file

@ -8,6 +8,7 @@
<link rel="stylesheet" type="text/css" href="{{ calculator_prefix }}/static/css/report.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="/static/css/style.css">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="{{ calculator_prefix }}/static/js/report.js" type="application/javascript"></script>
@ -17,14 +18,14 @@
{% block report_header %}
<div id="report-header-div" class="d-flex flex-row">
<img id="cara_logo" src="/static/images/cara_logo.200x200.png" class="d-inline-block align-middle">
<div class="d-flex align-self-center flex-column mr-auto" style="margin-left: 1em;">
<h2 class="text-component-title mb-0">CARA - CALCULATOR REPORT</h1>
<p class="mb-0"> Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}</p>
<div id="report-header-div" class="d-flex flex-row" style="margin: 1%">
<img id="report_logo" src="/static/images/cara_logo.200x200.png" class="d-inline-block align-middle mr-3">
<div style="margin-right: -105px" class='align-self-center mr-auto'>
<h2 class="header_text mb-0">CARA - CALCULATOR REPORT</h1>
<p class="mb-0" id="report_version"> Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}</p>
</div>
<button type="button" class="btn btn-outline-dark align-self-center" id="print-button" style="margin-right: -100pt" onclick="print()">Print Report</button>
<a href="{{ permalink.link }}" style="float: left;" id="pdf_qrcode_aref" class="align-self-center invisible"><div id="pdf_qrcode"></div></a>
<button type="button" class="btn btn-outline-dark align-self-center" id="download-pdf" style="margin-right: -100pt" onclick="print()">Print Report</button>
<a href="{{ permalink.link }}" style="float: left;" id="pdf_qrcode_aref" class="align-self-center invisible mr-0"><div id="pdf_qrcode"></div></a>
</div>
{% endblock report_header %}
@ -59,8 +60,8 @@
<p class="card-text">
<div class="align-self-center">
<div class="d-flex">
<div style="min-width: 25%">
<div class="split">
<div class="col-md-3">
<div style="text-align:center"><b>Probability of infection (%)</b></div>
<div class="d-flex" style="min-height: 160px">
{% block warning_animation %}
@ -74,23 +75,26 @@
{% endblock warning_animation %}
</div>
</div>
{% block report_summary %}
<div class="align-self-center alert alert-dark" role="alert">
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% endblock report_summary %}
<div class="col-md-8 pr-0 pl-0">
{% block report_summary %}
<div class="align-self-center alert alert-dark" role="alert">
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% endblock report_summary %}
</div>
</div>
</div>
{% block report_summary_footnote %}
{% endblock report_summary_footnote %}
</div>
<p id="section1">* The results are based on the parameters and assumptions published in the CERN Open Report <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>.</p>
<svg id="result_plot" width="900" height="400"></svg>
<div id="concentration_plot" style="height: 400px"></div>
<script type="application/javascript">
var times = {{ times | JSONify }}
var concentrations = {{ concentrations | JSONify }}
var exposed_presence_intervals = {{ exposed_presence_intervals | JSONify }}
draw_concentration_plot("#result_plot", times, concentrations, exposed_presence_intervals);
draw_concentration_plot("concentration_plot", times, concentrations, exposed_presence_intervals);
</script>
</p>
</div>
@ -107,12 +111,13 @@
<div class="collapse" id="collapseAlternativeScenarios">
<div class="card-body">
<div>
<svg id="alternative_scenario_plot" width="900" height="400"></svg>
<div id="alternative_scenario_plot" style="height: 400px"></div>
<script type="application/javascript">
var alternative_scenarios = {{ alternative_scenarios.stats | JSONify }}
var times = {{ times | JSONify }}
draw_alternative_scenarios_plot("#alternative_scenario_plot", width=600, height=400, alternative_scenarios, times);
draw_alternative_scenarios_plot("concentration_plot", "alternative_scenario_plot", times, alternative_scenarios);
</script>
<br>
{% block report_scenarios_summary_table %}
<table class="table w-auto">
<thead class="thead-light">
@ -160,13 +165,13 @@
</div>
<div class="collapse show" id="collapseQRcode">
<div class="card-body">
<div>
<a href="{{ permalink.link }}" style="float: left;"><div id="qrcode"></div></a>
<span style="float: left; min-height: 250pt; line-height: 250pt; vertical-align: middle; display: inline-block;">
<div class="split">
<div><a href="{{ permalink.link }}" style="float: left;"><div id="qrcode"></div></a></div>
<div class="align-self-center"><span style="float: left; vertical-align: middle; display: inline-block;">
<p style="display: inline-block; vertical-align: middle; line-height: normal;">
Click the QR code to regenerate the report and get a shareable link.<br>Alternatively, scan to regenerate the report.<br>
</p>
</span>
</span></div>
</div>
</div>
</div>
@ -390,7 +395,7 @@
{% block disclaimer_container %}
<br><br><br>
<div style="border: 2px solid black; padding: 15px;">
<div style="border: #dee2e6 1px solid; margin: 1%; padding: 20px" class="rounded">
{% block disclaimer %}
<p class="image"> <img align="middle" src="{{ calculator_prefix }}/static/images/disclaimer.jpg" width="40" height="40"><b>Disclaimer:</b><br><br></p>

View file

@ -22,7 +22,7 @@
{% endblock warning_animation %}
{% block report_summary %}
<div class="flex-row w-75 align-self-center">
<div class="flex-row align-self-center">
{% if ((prob_inf > 15) or (expected_new_cases >= 1)) %}
<div class="alert alert-danger" role="alert">
<strong>Not Acceptable:</strong>
@ -120,14 +120,16 @@
<p class="card-text">
Please ensure that this scenario conforms to current COVID-related <a href="https://hse.cern/covid-19-information"> Health & Safety requirements</a>, under the applicable COVID Scale and measures in force at the time of the CARA assessment.</strong> <br>
The results of this simulation are colour coded according to the risk values authorized at CERN (approved in December 2020):
</p>
</p><br>
<div class="d-flex">
<div class="d-flex flex-column justify-content-between">
<div class="alert alert-success ml-3" role="alert">Events with a <strong>P(i) less than 5%</strong> may go ahead without further mitigation measures.</div>
<div class="alert alert-warning ml-3" role="alert">Events with a <strong>P(i) between 5% and 15%</strong> shall be subject to ALARA principles (see footnote) to minimise the risk before proceeding.</div>
<div class="alert alert-danger ml-3 mb-0" role="alert">Events with a <strong>P(i) exceeding 15% or a number of expected new cases that exceeds 1</strong> may not take place until additional measures are in place and a risk reduction has been performed.</div>
<div class="split">
<div class="d-flex flex-column col-md-8 p-0">
<div class="alert alert-success" role="alert">Events with a <strong>P(i) less than 5%</strong> may go ahead without further mitigation measures.</div>
<div class="alert alert-warning" role="alert">Events with a <strong>P(i) between 5% and 15%</strong> shall be subject to ALARA principles (see footnote) to minimise the risk before proceeding.</div>
<div class="alert alert-danger mb-0" role="alert">Events with a <strong>P(i) exceeding 15% or a number of expected new cases that exceeds 1</strong> may not take place until additional measures are in place and a risk reduction has been performed.</div>
</div>
<div class="col-md-3 align-self-center text-align-center"><img id="cern_level" class="rounded" src="{{ calculator_prefix }}/static/images/warning_scale/{{scale_warning.level}}.png"></div>
</div>
<img class="rounded ml-4 align-self-center" src="{{ calculator_prefix }}/static/images/warning_scale/{{scale_warning.level}}.png">
</div>
<br>
<p class="data_text">

View file

@ -59,14 +59,14 @@ body {
padding: .2rem;
}
.nav-link {
/* .nav-link {
color: rgb(255, 255, 255)!important;
}
.nav-link.active,
.nav-link:hover {
color: rgb(45, 138, 241)!important;
}
} */
/*============= SPLIT =============*/
@ -176,10 +176,16 @@ footer img {
margin: 1.5rem auto;
}
/*============= REPORT =============*/
#report_logo {
height: 4em;
margin: 1%;
}
/*============= MEDIA QUERIES =============*/
/* Devices over 640px (xl) */
@media screen and (min-width: 40em) {
@media (min-width: 40em) {
.split {
flex-direction: row;
}
@ -212,6 +218,37 @@ footer img {
.header-text {
font-size: 2rem;
}
#report_logo {
height: 6em;
margin: 1%;
}
}
@media (max-width: 40em) {
#body {
font-size: .75rem;
padding: 10px;
}
.header_text {
font-size: 2vh;
}
.nav-link {
padding: .5rem .5rem!important;
}
#report_version {
font-size: .5rem;
}
#download-pdf, #pdf_qrcode_aref {
display: none;
}
#cern_level{
height: 15em;
margin-top: 1em;
}
#link_reproduce_results {
display: none;
}
}
/* Devices under 768px (md) */
/* @media (max-width: 767.98px) {