Added mobile style
This commit is contained in:
commit
ca8d69c6d6
5 changed files with 680 additions and 330 deletions
|
|
@ -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')
|
||||
|
|
@ -102,36 +104,148 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
|
|||
focus.append('circle')
|
||||
.attr('r', 3);
|
||||
|
||||
focus.append('rect')
|
||||
var tooltip_rect = focus.append('rect')
|
||||
.attr('fill', 'white')
|
||||
.attr('stroke', '#000')
|
||||
.attr('width', 80)
|
||||
.attr('height', 50)
|
||||
.attr('x', 10)
|
||||
.attr('y', -22)
|
||||
.attr('rx', 4)
|
||||
.attr('ry', 4);
|
||||
|
||||
focus.append('text')
|
||||
var tooltip_time = focus.append('text')
|
||||
.attr('id', 'tooltip-time')
|
||||
.attr('x', 18)
|
||||
.attr('y', -2);
|
||||
|
||||
focus.append('text')
|
||||
var tooltip_concentration = focus.append('text')
|
||||
.attr('id', 'tooltip-concentration')
|
||||
.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);
|
||||
|
||||
var graph_width;
|
||||
var graph_height;
|
||||
|
||||
function redraw() {
|
||||
|
||||
// Define width and height according to the screen size.
|
||||
var div_width = plot_div.clientWidth;
|
||||
var div_height = plot_div.clientHeight;
|
||||
graph_width = div_width;
|
||||
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: 60 };
|
||||
div_width = 900;
|
||||
graph_width = div_width * (2/3);
|
||||
const svg_margins = {'margin-left': '0rem', 'margin-top': '0rem'};
|
||||
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
|
||||
}
|
||||
else {
|
||||
var margins = { top: 30, right: 20, bottom: 50, left: 40 };
|
||||
div_width = div_width * 1.1
|
||||
graph_width = div_width * .95;
|
||||
graph_height = div_height * 0.65; // On mobile screen sizes we want the legend to be on the bottom of the graph.
|
||||
const svg_margins = {'margin-left': '-1rem', 'margin-top': '3rem'};
|
||||
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
|
||||
};
|
||||
|
||||
// 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 * 0.9 + margins.bottom) / 2)
|
||||
.attr('y', (graph_height + margins.left) * 0.9)
|
||||
.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);
|
||||
}
|
||||
|
||||
// ToolBox.
|
||||
toolBox.attr('width', graph_width - margins.right)
|
||||
.attr('height', graph_height);
|
||||
}
|
||||
|
||||
// Draw for the first time to initialize.
|
||||
redraw();
|
||||
|
||||
function mousemove() {
|
||||
if (d3.pointer(event)[0] < graph_width / 2) {
|
||||
tooltip_rect.attr('x', 10)
|
||||
tooltip_time.attr('x', 18)
|
||||
tooltip_concentration.attr('x', 18);
|
||||
}
|
||||
else {
|
||||
tooltip_rect.attr('x', -90)
|
||||
tooltip_time.attr('x', -82)
|
||||
tooltip_concentration.attr('x', -82)
|
||||
}
|
||||
var x0 = xRange.invert(d3.pointer(event, this)[0]),
|
||||
i = bisecHour(data, x0, 1),
|
||||
d0 = data[i - 1],
|
||||
|
|
@ -141,12 +255,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 +290,254 @@ 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]]);
|
||||
var bisecHour = d3.bisector((d) => { return d.hour; }).left;
|
||||
|
||||
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');
|
||||
|
||||
// Tooltip.
|
||||
var focus = {}, tooltip_rect = {}, tooltip_time = {}, tooltip_concentration = {}, toolBox = {};
|
||||
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
|
||||
|
||||
focus[scenario_name] = vis.append('svg:g')
|
||||
.style('display', 'none');
|
||||
|
||||
focus[scenario_name].append('circle')
|
||||
.attr('r', 3);
|
||||
|
||||
tooltip_rect[scenario_name] = focus[scenario_name].append('rect')
|
||||
.attr('fill', 'white')
|
||||
.attr('stroke', '#000')
|
||||
.attr('width', 80)
|
||||
.attr('height', 50)
|
||||
.attr('y', -22)
|
||||
.attr('rx', 4)
|
||||
.attr('ry', 4);
|
||||
|
||||
tooltip_time[scenario_name] = focus[scenario_name].append('text')
|
||||
.attr('id', 'tooltip-time')
|
||||
.attr('y', -2);
|
||||
|
||||
tooltip_concentration[scenario_name] = focus[scenario_name].append('text')
|
||||
.attr('id', 'tooltip-concentration')
|
||||
.attr('y', 18);
|
||||
|
||||
toolBox[scenario_name] = vis.append('rect')
|
||||
.attr('fill', 'none')
|
||||
.attr('pointer-events', 'all')
|
||||
.on('mouseover', () => { for (const [scenario_name, data] of Object.entries(focus)) focus[scenario_name].style('display', null); })
|
||||
.on('mouseout', () => { for (const [scenario_name, data] of Object.entries(focus)) focus[scenario_name].style('display', 'none'); })
|
||||
.on('mousemove', mousemove);
|
||||
}
|
||||
|
||||
var graph_width;
|
||||
var graph_height;
|
||||
|
||||
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;
|
||||
graph_width = div_width;
|
||||
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: 60 };
|
||||
div_width = 900;
|
||||
graph_width = div_width * (2/3);
|
||||
const svg_margins = {'margin-left': '0rem'};
|
||||
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
|
||||
}
|
||||
else {
|
||||
var margins = { top: 30, right: 20, bottom: 50, left: 40 };
|
||||
div_width = div_width * 1.1
|
||||
graph_width = div_width * .95;
|
||||
graph_height = div_height * 0.65; // On mobile screen sizes we want the legend to be on the bottom of the graph.
|
||||
const svg_margins = {'margin-left': '-1rem'};
|
||||
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
|
||||
};
|
||||
|
||||
// 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]);
|
||||
|
||||
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));
|
||||
|
||||
// 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.3)
|
||||
.attr('y', graph_height + size);
|
||||
label_text[scenario_name].attr('x', margins.left * 1.4)
|
||||
.attr('y', graph_height + size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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('transform', 'rotate(-90, 0,' + graph_height + ')')
|
||||
.attr('x', (graph_height * 0.9 + margins.bottom) / 2)
|
||||
.attr('y', (graph_height + margins.left) * 0.90);
|
||||
|
||||
// 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.02)
|
||||
}
|
||||
|
||||
// ToolBox.
|
||||
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
|
||||
toolBox[scenario_name].attr('width', graph_width - margins.right)
|
||||
.attr('height', graph_height);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw for the first time to initialize.
|
||||
redraw();
|
||||
|
||||
function mousemove() {
|
||||
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
|
||||
if (d3.pointer(event)[0] < graph_width / 2) {
|
||||
tooltip_rect[scenario_name].attr('x', 10)
|
||||
tooltip_time[scenario_name].attr('x', 18)
|
||||
tooltip_concentration[scenario_name].attr('x', 18);
|
||||
}
|
||||
else {
|
||||
tooltip_rect[scenario_name].attr('x', -90)
|
||||
tooltip_time[scenario_name].attr('x', -82)
|
||||
tooltip_concentration[scenario_name].attr('x', -82)
|
||||
}
|
||||
var x0 = xRange.invert(d3.pointer(event, this)[0]),
|
||||
i = bisecHour(data, x0, 1),
|
||||
d0 = data[i - 1],
|
||||
d1 = data[i],
|
||||
d = x0 - d0.hour > d1.hour - x0 ? d1 : d0;
|
||||
focus[scenario_name].attr('transform', 'translate(' + xRange(d.hour) + ',' + yRange(d.concentration) + ')');
|
||||
focus[scenario_name].select('#tooltip-time').text('x = ' + time_format(d.hour));
|
||||
focus[scenario_name].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);
|
||||
}
|
||||
|
||||
function copy_clipboard(shareable_link) {
|
||||
const el = document.createElement('textarea');
|
||||
el.value = shareable_link;
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
|
||||
// Functions used to build the plots' components
|
||||
|
||||
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);
|
||||
|
||||
return vis;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
return vis;
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
vis.append('svg:path')
|
||||
.attr('d', lineFunc(data))
|
||||
.attr("stroke", line_color)
|
||||
.attr('stroke-width', 2)
|
||||
.attr('fill', 'none');
|
||||
|
||||
return vis;
|
||||
alert("Shareable link copied to clipboard.")
|
||||
}
|
||||
|
|
@ -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">
|
||||
|
|
@ -150,7 +155,7 @@
|
|||
{% endblock report_results %}
|
||||
|
||||
{% block report_footer %}
|
||||
<div class="card bg-light mb-3" id="link_reproduce_results">
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header"><strong>Link to reproduce results </strong>
|
||||
<button class="icon_button p-0 float-right" data-toggle="collapse" href="#collapseQRcode" role="button" aria-expanded="true" aria-controls="collapseQRcode">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-expand" viewBox="0 0 16 16">
|
||||
|
|
@ -160,13 +165,14 @@
|
|||
</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="text-center"><button id="mobile_link" class="btn btn-primary btn-sm d-none" onclick="copy_clipboard('{{ permalink.link }}');">Click to copy a shareable link</button></div>
|
||||
<div id="link_reproduce_results" 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>
|
||||
|
|
@ -299,11 +305,13 @@
|
|||
</p></li>
|
||||
<li><p class="data_text">Exposed occupant(s) activity time:</p></li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_start | minutes_to_time }}    End time: {{ form.exposed_finish | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_start | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">End time: {{ form.exposed_finish | minutes_to_time }}</p></li>
|
||||
</ul>
|
||||
<li><p class="data_text">Infected occupant(s) activity time:</p></li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.infected_start | minutes_to_time }}    End time: {{ form.infected_finish | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">Start time: {{ form.infected_start | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">End time: {{ form.infected_finish | minutes_to_time }}</p></li>
|
||||
</ul>
|
||||
<li><p class="data_text">Event for the month of {{ form.event_month }}</p></li>
|
||||
</ul>
|
||||
|
|
@ -321,7 +329,8 @@
|
|||
{% if form.exposed_lunch_option%}
|
||||
Yes</li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_lunch_start | minutes_to_time }}    End time: {{ form.exposed_lunch_finish | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_lunch_start | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">End time: {{ form.exposed_lunch_finish | minutes_to_time }}</p></li>
|
||||
</ul>
|
||||
{% else%}
|
||||
No
|
||||
|
|
@ -346,7 +355,8 @@
|
|||
{% if form.infected_lunch_option%}
|
||||
Yes</li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.infected_lunch_start | minutes_to_time }}    End time: {{ form.infected_lunch_finish | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">Start time: {{ form.infected_lunch_start | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">End time: {{ form.infected_lunch_finish | minutes_to_time }}</p></li>
|
||||
</ul>
|
||||
{% else%}
|
||||
No
|
||||
|
|
@ -390,7 +400,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>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@
|
|||
|
||||
{% block main %}
|
||||
|
||||
v{{ calculator_version }} <span style="float:right; font-weight:bold">Please send feedback to <a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a></span>
|
||||
<span class="cara_version">v{{ calculator_version }}</span>
|
||||
<span class="feedback">Please send feedback to <a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a></span>
|
||||
<header class= "bg-light">
|
||||
<div class="container container--narrow container--padding">
|
||||
<img src="/static/images/cara_logo.200x200.png" class="logo">
|
||||
|
|
@ -59,14 +60,16 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<span class="tooltip_text">?</span>
|
||||
</div><br>
|
||||
|
||||
<div class="row">
|
||||
<label class="col-xl-3 col-lg-4 col-sm-3 col-form-label">Variant:</label>
|
||||
<select id="Variant" name="virus_type" class="col-xl-5 col-lg-7 col-sm-7 col-7">
|
||||
<option value="SARS_CoV_2">SARS-CoV-2 (nominal strain)</option>
|
||||
<option value="SARS_CoV_2_B117">SARS-CoV-2 (Alpha VOC)</option>
|
||||
<option value="SARS_CoV_2_P1">SARS-CoV-2 (Gamma VOC)</option>
|
||||
<option selected value="SARS_CoV_2_B16172">SARS-CoV-2 (Delta VOC)</option>
|
||||
</select>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-4"><label class="col-form-label">Variant:</label></div>
|
||||
<div class="col-sm-6">
|
||||
<select id="Variant" name="virus_type" class="form-control">
|
||||
<option value="SARS_CoV_2">SARS-CoV-2 (nominal strain)</option>
|
||||
<option value="SARS_CoV_2_B117">SARS-CoV-2 (Alpha VOC)</option>
|
||||
<option value="SARS_CoV_2_P1">SARS-CoV-2 (Gamma VOC)</option>
|
||||
<option selected value="SARS_CoV_2_B16172">SARS-CoV-2 (Delta VOC)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr width="80%">
|
||||
|
|
@ -92,7 +95,7 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-4">
|
||||
<input type="radio" id="room_data_dimensions" name="volume_type" value="room_volume_from_dimensions" onclick="require_fields(this)" tabindex="-1" required>
|
||||
<label for="room_data_dimensions">Floor area:</label>
|
||||
<label for="room_data_dimensions">Floor area:</label>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<input type="number" step="any" id="floor_area" class="non_zero form-control" name="floor_area" placeholder="Room floor area (m²)" min="0" data-has-radio="#room_data_dimensions">
|
||||
|
|
@ -100,33 +103,34 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-4">
|
||||
<label for="room_data_dimensions">Ceiling height:</label>
|
||||
<label for="room_data_dimensions">Ceiling height:</label>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<input type="number" step="any" id="ceiling_height" class="non_zero form-control" name="ceiling_height" placeholder="Room ceiling height (m)" min="0" data-has-radio="#room_data_dimensions">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
Central heating system in use:
|
||||
<input type="radio" id="heating_no" name="room_heating_option" value=0 checked="checked">
|
||||
<label for="heating_no">No</label>
|
||||
<input type="radio" id="heating_yes" name="room_heating_option" value=1>
|
||||
<label for="heating_yes">Yes</label>
|
||||
|
||||
<div class="split">
|
||||
<div>Central heating system in use:</div>
|
||||
<div>
|
||||
<input class="ml-2" type="radio" id="heating_no" name="room_heating_option" value=0 checked="checked">
|
||||
<label for="heating_no">No</label>
|
||||
<input class="ml-2" type="radio" id="heating_yes" name="room_heating_option" value=1>
|
||||
<label for="heating_yes">Yes</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3">Location:</label>
|
||||
<select id="location_select" form="not-submitted" class="col-sm-7 form-control" name="location_select" required></select>
|
||||
<div style="display: none">
|
||||
<!--
|
||||
This block allows us to have hidden input values which are retained during forward/back navigation, as per
|
||||
https://stackoverflow.com/a/6384276/741316
|
||||
-->
|
||||
<input type="text" name="location_name">
|
||||
<input type="text" name="location_latitude">
|
||||
<input type="text" name="location_longitude">
|
||||
</div>
|
||||
<div class="col-sm-4"><label class="col-form-label">Location:</label></div>
|
||||
<div class="col-sm-6 align-self-center"><select id="location_select" form="not-submitted" class="form-control" name="location_select" required></select></div>
|
||||
</div>
|
||||
<div style="display: none">
|
||||
<!--
|
||||
This block allows us to have hidden input values which are retained during forward/back navigation, as per
|
||||
https://stackoverflow.com/a/6384276/741316
|
||||
-->
|
||||
<input type="text" name="location_name">
|
||||
<input type="text" name="location_latitude">
|
||||
<input type="text" name="location_longitude">
|
||||
</div>
|
||||
|
||||
<hr width="80%">
|
||||
|
|
@ -141,56 +145,70 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<div class='sub_title'>Ventilation type:</div>
|
||||
|
||||
<div class="split">
|
||||
<div>
|
||||
<input type="radio" id="no_ventilation" name="ventilation_type" value="no_ventilation" checked>
|
||||
<label for="no_ventilation">No ventilation</label>
|
||||
<input type="radio" id="mechanical_ventilation" name="ventilation_type" value="mechanical_ventilation" data-enables="#DIVmechanical_ventilation">
|
||||
<label for="mechanical_ventilation">Mechanical</label>
|
||||
<label for="no_ventilation">No ventilation</label>
|
||||
<input class="ml-2" type="radio" id="mechanical_ventilation" name="ventilation_type" value="mechanical_ventilation" data-enables="#DIVmechanical_ventilation">
|
||||
<label for="mechanical_ventilation">Mechanical</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="natural_ventilation" name="ventilation_type" value="natural_ventilation" data-enables="#DIVnatural_ventilation">
|
||||
<label for="natural_ventilation">Natural</label><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="DIVmechanical_ventilation" class="tabbed" style="display:none">
|
||||
<div class="form-group row">
|
||||
<div class="split">
|
||||
<div>
|
||||
<input type="radio" id="mech_type_air_supply" name="mechanical_ventilation_type" value="mech_type_air_supply" class="center_radio" onclick="require_fields(this)" tabindex="-1">
|
||||
<label for="mech_type_air_supply" class="col-form-label col-sm-5">Air supply flow rate</label>
|
||||
<input type="number" step="any" id="air_supply" class="non_zero form-control col-sm-5" name="air_supply" min="0" placeholder="(m³ / hour)" data-has-radio="#mech_type_air_supply"><br>
|
||||
<label for="mech_type_air_supply" class="col-form-label ml-2">Air supply flow rate</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="number" step="any" id="air_supply" class="non_zero form-control" name="air_supply" min="0" placeholder="(m³ / hour)" data-has-radio="#mech_type_air_supply"><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="split">
|
||||
<div>
|
||||
<input type="radio" id="mech_type_air_changes" name="mechanical_ventilation_type" value="mech_type_air_changes" class="center_radio" onclick="require_fields(this)" tabindex="-1">
|
||||
<label for="mech_type_air_changes" class="col-form-label col-sm-5">Air changes per hour</label>
|
||||
<input type="number" step="any" id="air_changes" class="non_zero form-control col-sm-5" name="air_changes" min="0" placeholder="(h⁻¹) only fresh air" data-has-radio="#mech_type_air_changes"><br>
|
||||
<label for="mech_type_air_changes" class="col-form-label ml-2">Air changes per hour</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="number" step="any" id="air_changes" class="non_zero form-control" name="air_changes" min="0" placeholder="(h⁻¹) only fresh air" data-has-radio="#mech_type_air_changes"><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="DIVnatural_ventilation" class="tabbed" style="display:none">
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Number of windows:</label>
|
||||
<input type="number" id="windows_number" class="non_zero form-control col-sm-5" name="windows_number" min="1"><br>
|
||||
<div class="split">
|
||||
<div><label class="col-form-label">Number of windows:</label></div>
|
||||
<div><input type="number" id="windows_number" class="non_zero form-control" name="windows_number" min="1"><br></div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Height of window: </label>
|
||||
<input type="number" step="any" id="window_height" class="non_zero form-control col-sm-5" name="window_height" placeholder="meters" min="0"><br>
|
||||
<div class="split">
|
||||
<div><label class="col-form-label">Height of window: </label></div>
|
||||
<div><input type="number" step="any" id="window_height" class="non_zero form-control" name="window_height" placeholder="meters" min="0"><br></div>
|
||||
</div>
|
||||
<div class='sub_title'>Window type:</div>
|
||||
<input type="radio" id="window_sliding" name="window_type" value="window_sliding" onclick="require_fields(this)" checked="checked">
|
||||
<label for="window_sliding">Sliding / Side-Hung</label>
|
||||
<input type="radio" id="window_hinged" name="window_type" value="window_hinged" onclick="require_fields(this)">
|
||||
<label for="window_hinged">Top- or Bottom-Hung</label> <br>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Width of window: </label>
|
||||
<input type="number" step="any" id="window_width" class="non_zero disabled form-control col-sm-5" name="window_width" placeholder="meters" min="0" data-has-radio="#window_hinged"><br>
|
||||
<input class="ml-2" type="radio" id="window_sliding" name="window_type" value="window_sliding" onclick="require_fields(this)" checked="checked">
|
||||
<label for="window_sliding">Sliding / Side-Hung</label>
|
||||
<input class="ml-2" type="radio" id="window_hinged" name="window_type" value="window_hinged" onclick="require_fields(this)">
|
||||
<label for="window_hinged">Top- or Bottom-Hung</label><br>
|
||||
<div class="split">
|
||||
<div><label class="col-form-label">Width of window: </label></div>
|
||||
<div><input type="number" step="any" id="window_width" class="non_zero disabled form-control" name="window_width" placeholder="meters" min="0" data-has-radio="#window_hinged"><br></div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Opening distance: </label>
|
||||
<input type="number" step="any" id="opening_distance" class="non_zero form-control col-sm-5" name="opening_distance" placeholder="meters" min="0"><br>
|
||||
<div class="split">
|
||||
<div><label class="col-form-label">Opening distance: </label></div>
|
||||
<div><input type="number" step="any" id="opening_distance" class="non_zero form-control" name="opening_distance" placeholder="meters" min="0"><br></div>
|
||||
</div>
|
||||
<div class='sub_title'>Window open:</div>
|
||||
<div class="form-group row">
|
||||
<span class="tabbed center_radio"><input type="radio" id="windows_open_permanently" name="window_opening_regime" value="windows_open_permanently" onclick="require_fields(this)" checked="checked"></span>
|
||||
<label for="windows_open_permanently" class="col-form-label col-sm-3">Permanently</label><br>
|
||||
<label for="windows_open_permanently" class="col-form-label ml-2">Permanently</label><br>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<span class="tabbed center_radio"><input type="radio" id="windows_open_periodically" name="window_opening_regime" value="windows_open_periodically" onclick="require_fields(this)"></span>
|
||||
<label for="windows_open_periodically" class="col-form-label col-sm-3">Periodically:</label> <br>
|
||||
<label for="windows_open_periodically" class="col-form-label ml-2 mr-2">Periodically:</label><br>
|
||||
<input type="number" step="any" id="windows_duration" class="non_zero disabled form-control col-sm-4" name="windows_duration" placeholder="Duration (min)" min="1" data-has-radio="#windows_open_periodically">
|
||||
<input type="number" step="any" id="windows_frequency" class="non_zero disabled form-control col-sm-4" name="windows_frequency" placeholder="Frequency (min)" min="1" data-has-radio="#windows_open_periodically">
|
||||
</div>
|
||||
|
|
@ -198,11 +216,17 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</div>
|
||||
|
||||
<div class='sub_title'>HEPA filtration:</div>
|
||||
<div class="split">
|
||||
<div>
|
||||
<input type="radio" id="hepa_no" name="hepa_option" value=0 onclick="require_fields(this)" checked="checked">
|
||||
<label for="hepa_no" class="col-form-label">No</label>
|
||||
<input type="radio" id="hepa_yes" name="hepa_option" value=1 onclick="require_fields(this)">
|
||||
<label for="hepa_yes" class="col-form-label">Yes</label>
|
||||
<input type="number" step="any" id="hepa_amount" class="non_zero disabled form-control col-sm-4" name="hepa_amount" placeholder="(m³ / hour)" min="0" data-has-radio="#hepa_yes">
|
||||
<label for="hepa_no" class="col-form-label ml-2">No</label>
|
||||
<input class="ml-2" type="radio" id="hepa_yes" name="hepa_option" value=1 onclick="require_fields(this)">
|
||||
<label for="hepa_yes" class="col-form-label ml-2">Yes</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="number" step="any" id="hepa_amount" class="non_zero disabled form-control" name="hepa_amount" placeholder="(m³ / hour)" min="0" data-has-radio="#hepa_yes">
|
||||
</div>
|
||||
</div>
|
||||
<hr width="80%">
|
||||
|
||||
<b>Face masks:</b>
|
||||
|
|
@ -214,13 +238,13 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<div class='sub_title'>Are masks worn when occupants are at workstations?</div>
|
||||
<input type="radio" id="mask_on" name="mask_wearing_option" value="mask_on" required>
|
||||
<label for="mask_on">Yes</label>
|
||||
<input type="radio" id="mask_off" name="mask_wearing_option" value="mask_off" required checked="checked">
|
||||
<label for="mask_on">Yes</label>
|
||||
<input class="ml-2" type="radio" id="mask_off" name="mask_wearing_option" value="mask_off" required checked="checked">
|
||||
<label for="mask_off">No</label><br>
|
||||
Type of masks used:
|
||||
<input type="radio" id="mask_type_1" name="mask_type" value="Type I" checked="checked" onclick="require_fields(this)">
|
||||
<label for="mask_type_1">Type 1</label>
|
||||
<input type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
|
||||
<label for="mask_type_1">Type 1</label>
|
||||
<input class="ml-2" type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
|
||||
<label for="mask_type_ffp2">FFP2</label><br>
|
||||
<hr width="80%">
|
||||
|
||||
|
|
@ -234,33 +258,34 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</div><br>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-5 col-form-label">Total number of occupants:</label>
|
||||
<input type="number" id="total_people" class="form-control col-sm-3" name="total_people" min=1 required>
|
||||
<div class="col-sm-4"><label class="col-form-label">Total number of occupants:</label></div>
|
||||
<div class="col-sm-6 align-self-center"><input type="number" id="total_people" class="form-control" name="total_people" min=1 required></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-5 col-form-label">Number of infected people: </label>
|
||||
<input type="number" id="infected_people" class="form-control col-sm-3" name="infected_people" min=1 value=1 required><br>
|
||||
<div class="col-sm-4"><label class="col-form-label">Number of infected people: </label></div>
|
||||
<div class="col-sm-6 align-self-center"><input type="number" id="infected_people" class="form-control" name="infected_people" min=1 value=1 required></div>
|
||||
</div>
|
||||
|
||||
<span id="training_limit_error" class="red_text" hidden>Training activities limited to 1 infected<br></span>
|
||||
<hr width="80%">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-4">Activity type:</label>
|
||||
|
||||
<select id="activity_type" name="activity_type" class="form-control col-sm-5">
|
||||
<option value="office">Office</option>
|
||||
<option value="meeting">Meeting</option>
|
||||
<option value="callcentre">Call Centre</option>
|
||||
<option value="controlroom-day">Control Room - Day shift</option>
|
||||
<option value="controlroom-night">Control Room - Night shift</option>
|
||||
<option value="library">Library</option>
|
||||
<option value="lab">Laboratory</option>
|
||||
<option value="workshop">Workshop</option>
|
||||
<option value="training">Training</option>
|
||||
<option value="gym">Gym</option>
|
||||
</select><br>
|
||||
<div class="col-sm-4"><label class="col-form-label">Activity type:</label></div>
|
||||
<div class="col-sm-6">
|
||||
<select id="activity_type" name="activity_type" class="form-control">
|
||||
<option value="office">Office</option>
|
||||
<option value="meeting">Meeting</option>
|
||||
<option value="callcentre">Call Centre</option>
|
||||
<option value="controlroom-day">Control Room - Day shift</option>
|
||||
<option value="controlroom-night">Control Room - Night shift</option>
|
||||
<option value="library">Library</option>
|
||||
<option value="lab">Laboratory</option>
|
||||
<option value="workshop">Workshop</option>
|
||||
<option value="training">Training</option>
|
||||
<option value="gym">Gym</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -269,11 +294,11 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<div class='sub_title'>Exposed person(s) presence:</div>
|
||||
<div class="split">
|
||||
<div>
|
||||
<label class="tabbed mb-0">Start: </label>
|
||||
<input type="time" id="exposed_start" class="start_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_start" value="08:30" required>
|
||||
<label class="tabbed mb-0">Start:</label>
|
||||
<input type="time" id="exposed_start" class="start_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_start" value="08:30" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="tabbed mb-0">Finish: </label>
|
||||
<label class="tabbed mb-0">Finish:</label>
|
||||
<input type="time" id="exposed_finish" class="finish_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_finish" value="17:30" required>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -285,7 +310,7 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<div class="split">
|
||||
<div>
|
||||
<label class="tabbed mb-0">Start: </label>
|
||||
<input type="time" id="infected_start" class="start_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_start" value="08:30" required>
|
||||
<input type="time" id="infected_start" class="start_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_start" value="08:30" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="tabbed mb-0">Finish: </label>
|
||||
|
|
@ -299,8 +324,9 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<hr width="80%">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="tabbed col-form-label col-sm-7">Which month is the event?</label>
|
||||
<select id="event_month" name="event_month" class="form-control col-sm-4" value="January" required>
|
||||
<div class="col-sm-4"><label class="col-form-label">Which month is the event?</label></div>
|
||||
<div class="col-sm-6 align-self-center">
|
||||
<select id="event_month" name="event_month" class="form-control" value="January" required>
|
||||
<option value="January">January</option>
|
||||
<option value="February">February</option>
|
||||
<option value="March">March</option>
|
||||
|
|
@ -313,7 +339,8 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<option value="October">October</option>
|
||||
<option value="November">November</option>
|
||||
<option value="December">December</option>
|
||||
</select><br>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<hr width="80%">
|
||||
|
||||
|
|
@ -333,14 +360,14 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<div class="breakBoxExposed" id="DIVexposed_breaks">
|
||||
<span id="exposed_break_title" style="display:none;"><b>Exposed person(s) breaks:</b></span>
|
||||
<div class="boxMargin">
|
||||
Lunch break:
|
||||
<input type="radio" id="exposed_lunch_option_no" data-lunch-select="exposed" name="exposed_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="exposed_lunch_option_no">No</label>
|
||||
<input type="radio" id="exposed_lunch_option_yes" data-lunch-select="exposed" name="exposed_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
Lunch break:
|
||||
<input class="ml-2" type="radio" id="exposed_lunch_option_no" data-lunch-select="exposed" name="exposed_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="exposed_lunch_option_no">No</label>
|
||||
<input class="ml-2" type="radio" id="exposed_lunch_option_yes" data-lunch-select="exposed" name="exposed_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
<label for="exposed_lunch_option_yes">Yes</label><br>
|
||||
<div class="split">
|
||||
<div>
|
||||
Start: <input type="time" id="exposed_lunch_start" class="start_time" data-time-group="exposed_lunch" data-lunch-for="exposed" data-has-radio="#exposed_lunch_option_yes" name="exposed_lunch_start" value="12:30" required>
|
||||
Start: <input type="time" id="exposed_lunch_start" class="start_time" data-time-group="exposed_lunch" data-lunch-for="exposed" data-has-radio="#exposed_lunch_option_yes" name="exposed_lunch_start" value="12:30" required>
|
||||
</div>
|
||||
<div>
|
||||
Finish: <input type="time" id="exposed_lunch_finish" class="finish_time" data-time-group="exposed_lunch" data-lunch-for="exposed" data-has-radio="#exposed_lunch_option_yes" name="exposed_lunch_finish" value="13:30" required><br>
|
||||
|
|
@ -349,15 +376,15 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<!-- Coffee Options -->
|
||||
<div class="split">
|
||||
<div class="col-sm-5">
|
||||
Coffee Breaks:
|
||||
<div>
|
||||
Coffee Breaks:
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<div>
|
||||
<input type="radio" id="exposed_coffee_break_0" name="exposed_coffee_break_option" value="coffee_break_0" checked="checked">
|
||||
<label for="exposed_coffee_break_0" >No breaks</label>
|
||||
<input type="radio" id="exposed_coffee_break_2" name="exposed_coffee_break_option" value="coffee_break_2">
|
||||
<label for="exposed_coffee_break_2">2</label>
|
||||
<input type="radio" id="exposed_coffee_break_4" name="exposed_coffee_break_option" value="coffee_break_4">
|
||||
<label for="exposed_coffee_break_0" >No breaks</label>
|
||||
<input class="ml-2" type="radio" id="exposed_coffee_break_2" name="exposed_coffee_break_option" value="coffee_break_2">
|
||||
<label for="exposed_coffee_break_2">2</label>
|
||||
<input class="ml-2" type="radio" id="exposed_coffee_break_4" name="exposed_coffee_break_option" value="coffee_break_4">
|
||||
<label for="exposed_coffee_break_4">4</label><br>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -380,15 +407,15 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<div class="breakBoxInfected" id="DIVinfected_breaks">
|
||||
<b>Infected person(s) breaks:</b>
|
||||
<div class="boxMargin">
|
||||
Lunch break:
|
||||
<input type="radio" id="infected_lunch_option_no" data-lunch-select="infected" name="infected_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="infected_lunch_option_no">No</label>
|
||||
<input type="radio" id="infected_lunch_option_yes" data-lunch-select="infected" name="infected_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
Lunch break:
|
||||
<input class="ml-2" type="radio" id="infected_lunch_option_no" data-lunch-select="infected" name="infected_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="infected_lunch_option_no">No</label>
|
||||
<input class="ml-2" type="radio" id="infected_lunch_option_yes" data-lunch-select="infected" name="infected_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
<label for="infected_lunch_option_yes">Yes</label><br>
|
||||
|
||||
<div class="split">
|
||||
<div>
|
||||
Start: <input type="time" id="infected_lunch_start" class="start_time" data-time-group="infected_lunch" data-lunch-for="infected" data-has-radio="#infected_lunch_option_yes" name="infected_lunch_start" value="12:30">
|
||||
Start: <input type="time" id="infected_lunch_start" class="start_time" data-time-group="infected_lunch" data-lunch-for="infected" data-has-radio="#infected_lunch_option_yes" name="infected_lunch_start" value="12:30">
|
||||
</div>
|
||||
<div>
|
||||
Finish: <input type="time" id="infected_lunch_finish" class="finish_time" data-time-group="infected_lunch" data-lunch-for="infected" data-has-radio="#infected_lunch_option_yes" name="infected_lunch_finish" value="13:30"><br>
|
||||
|
|
@ -397,15 +424,15 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<!-- Coffee Options -->
|
||||
<div class="split">
|
||||
<div class="col-sm-5">
|
||||
Coffee Breaks:
|
||||
<div>
|
||||
Coffee Breaks:
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<div>
|
||||
<input type="radio" id="infected_coffee_break_0" name="infected_coffee_break_option" value="coffee_break_0" checked="checked">
|
||||
<label for="infected_coffee_break_0" >No breaks</label>
|
||||
<input type="radio" id="infected_coffee_break_2" name="infected_coffee_break_option" value="coffee_break_2">
|
||||
<label for="infected_coffee_break_2">2</label>
|
||||
<input type="radio" id="infected_coffee_break_4" name="infected_coffee_break_option" value="coffee_break_4">
|
||||
<label for="infected_coffee_break_0" >No breaks</label>
|
||||
<input style="ml-2" type="radio" id="infected_coffee_break_2" name="infected_coffee_break_option" value="coffee_break_2">
|
||||
<label for="infected_coffee_break_2">2</label>
|
||||
<input style="ml-2" type="radio" id="infected_coffee_break_4" name="infected_coffee_break_option" value="coffee_break_4">
|
||||
<label for="infected_coffee_break_4">4</label><br>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -436,10 +463,6 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</section>
|
||||
|
||||
<div class="center">
|
||||
<button class="btn btn-primary bigButton">
|
||||
<a href="{{ calculator_prefix }}/user-guide" class="{{ "nav-link active" if "user-guide" in active_page else "nav-link" }}">User guide</a>
|
||||
</button>
|
||||
|
||||
<button type='submit' class="btn btn-primary bigButton" id="generate_report">
|
||||
Generate report
|
||||
</button>
|
||||
|
|
@ -495,8 +518,11 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
for more detailed explanations on how to use this tool. <br>
|
||||
</div>
|
||||
|
||||
<div class="center container--padding">
|
||||
<button class="btn btn-primary bigButton" type="button" data-toggle="collapse" data-target="#collapseDisclaimer" aria-expanded="false" aria-controls="collapseDisclaimer">
|
||||
<div class="center container--padding pr-3 pl-3">
|
||||
<button class="btn btn-primary bigButton">
|
||||
<a href="{{ calculator_prefix }}/user-guide" class="{{ "nav-link active" if "user-guide" in active_page else "nav-link" }}" style="color:white">User guide</a>
|
||||
</button>
|
||||
<button class="btn btn-primary bigButton ml-2" type="button" data-toggle="collapse" data-target="#collapseDisclaimer" aria-expanded="false" aria-controls="collapseDisclaimer">
|
||||
Disclaimer
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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-xl-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-xl-3 align-self-center text-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">
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ body {
|
|||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .1rem;
|
||||
box-shadow: 0 .5rem .5rem rgba(0,0,0,.5);
|
||||
/* box-shadow: 0 .5rem .5rem rgba(0,0,0,.5); */
|
||||
z-index: 1;
|
||||
background: rgb(42, 52, 66);
|
||||
}
|
||||
|
|
@ -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 =============*/
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ body {
|
|||
clear: both;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
/* width: 100%; */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ body {
|
|||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 6em;
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
|
@ -104,10 +104,12 @@ body {
|
|||
|
||||
.header-text {
|
||||
text-align: center;
|
||||
font-size: 2.75vh;
|
||||
}
|
||||
|
||||
.head-center {
|
||||
text-align: center;
|
||||
font-size: 3vh;
|
||||
}
|
||||
|
||||
.center {
|
||||
|
|
@ -168,10 +170,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;
|
||||
}
|
||||
|
|
@ -194,13 +202,92 @@ footer img {
|
|||
|
||||
.logo {
|
||||
float: left;
|
||||
height: 6em;
|
||||
}
|
||||
|
||||
.head-center {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.header_text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#report_logo {
|
||||
height: 6em;
|
||||
margin: 1%;
|
||||
}
|
||||
.feedback {
|
||||
float:right;
|
||||
font-size:1rem;
|
||||
font-weight:bold;
|
||||
}
|
||||
.cara_version {
|
||||
float:left;
|
||||
font-size:1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 40em) {
|
||||
#body {
|
||||
font-size: .75rem;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
.header_text {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
#mobile_link {
|
||||
display: inline!important;
|
||||
}
|
||||
.feedback {
|
||||
float:right;
|
||||
font-size:.75rem;
|
||||
font-weight:bold;
|
||||
}
|
||||
.cara_version {
|
||||
float:left;
|
||||
font-size:.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Devices under 768px (md) */
|
||||
/* @media (max-width: 767.98px) {
|
||||
|
||||
} */
|
||||
|
||||
/* Large (lg) devices (desktops, 992px and up) */
|
||||
@media (max-width: 992px) {
|
||||
#download-pdf {
|
||||
display: none;
|
||||
}
|
||||
#link_reproduce_results {
|
||||
display: none;
|
||||
}
|
||||
#mobile_link {
|
||||
display: inline!important;
|
||||
}
|
||||
}
|
||||
|
||||
/*============ BOOTSTRAP BREAK POINTS:
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue