Updates as per Team meeting 28 Aug 2025

This commit is contained in:
Peter Edmond 2025-05-28 19:53:00 +01:00
parent 9d6c761d15
commit 88853e955c
9 changed files with 581 additions and 185 deletions

View File

@ -1,7 +1,8 @@
function drawBar(id) {
function drawBar(id,data) {
//console.log(id);
const svg = d3.select(`${id}`);
const backgroundwidth = +svg.attr("width");
const backgroundradius = 10;
@ -23,8 +24,9 @@ svg.append("rect")
// .attr("stroke-width", 2);
const data = {
//const data = {
/*
data = {
"-3": 0,
"-2": 1,
"-1": 3,
@ -33,6 +35,9 @@ const data = {
"2": 0,
"3": 10
};
*/
//console.log(data);
const dataArray = Object.entries(data).map(([key, count]) => ({
key: +key,
@ -72,10 +77,6 @@ svg.append("g")
.selectAll("text")
.style("visibility", "hidden"); // This hides the labels
// Y Axis
//svg.append("g")
// .attr("transform", `translate(${margin.left},0)`)
@ -110,15 +111,14 @@ svg.selectAll(".label")
const format = d3.format(".2f");
const totalCount = d3.sum(dataArray, d => d.count);
const weightedSum = d3.sum(dataArray, d => d.key * d.count);
const average = totalCount > 0 ? format(weightedSum / totalCount) : 0;
average = totalCount > 0 ? weightedSum / totalCount : 0;
const xLinear = d3.scaleLinear()
.domain([-3, 3])
.range([margin.left + x.bandwidth() / 2, width - margin.right - x.bandwidth() / 2]);
// const avgX = xLinear(average);
const avgX = xLinear(2.7); // Temporary for testing
const avgX = xLinear(average);
//const avgX = xLinear(-0.50); // Temporary for testing
svg.append("line")
.attr("x1", avgX)
@ -127,7 +127,7 @@ svg.append("line")
.attr("y2", y(d3.max(dataArray, d => d.count)) - 20)
.attr("stroke", "#e40074") // From brand guidelines
.attr("stroke-width", 4)
.attr("stroke-dasharray", "6,2");
.attr("stroke-dasharray", "10,4");
/*
svg.append("text")
@ -140,6 +140,7 @@ svg.append("text")
*/
// Title beneath the graph
/*
svg.append("text")
.attr("x", width / 2)
.attr("y", height - 10) // Just below the x-axis
@ -147,13 +148,14 @@ svg.append("text")
.attr("font-size", "14px")
.attr("fill", "black")
.text("Demo bar graph");
*/
// Add infor to right of bar chart
// Add info to right of bar chart
// Oblong settings
const boxx = 620;
const boxx = 610;
const boxy = 60;
const boxwidth = 150;
const boxwidth = 170;
const boxheight = 80;
const cornerRadius = 10;
@ -185,9 +187,40 @@ svg.append("text")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.attr("font-size", "20px")
.attr("font-weight", "900") // 400 is normal, 700 is bold, 900 is extra-bold
.attr("font-weight", "400") // 400 is normal, 700 is bold, 900 is extra-bold
.attr("font-family", "sans-serif")
.text("Average : 1.69");
.text("Average: ")
.append(function() {
return document.createElementNS("http://www.w3.org/2000/svg", "tspan");
})
.text(average.toFixed(1))
.attr("class", "average")
.attr("fill", "#e40074")
.attr("font-weight", "900");
// .text("Average : "+average.toFixed(2));
// Get the score gap:
let maxKey = null;
let minKey = null;
for (const [key, value] of Object.entries(data)) {
if (value > 0) {
const numKey = Number(key);
//console.log(numkey);
if (maxKey === null || numKey > maxKey) {
maxKey = numKey;
}
if (minKey === null || numKey < minKey) {
minKey = numKey;
}
}
}
scoregap = maxKey - minKey+1;
// Add text to the bottom half
svg.append("text")
@ -196,8 +229,58 @@ svg.append("text")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.attr("font-size", "20px")
.attr("font-weight", "900") // 400 is normal, 700 is bold, 900 is extra-bold
.attr("font-weight", "400") // 400 is normal, 700 is bold, 900 is extra-bold
.attr("font-family", "sans-serif")
.text("Score Gap : 6");
.text("Score gap: ")
.append(function() {
return document.createElementNS("http://www.w3.org/2000/svg", "tspan");
})
.text(scoregap)
.attr("font-weight", "900");
}
// .text("Score Gap : "+scoregap);
return average; //Needed for the next layer up in the analysis
}
function doBarData(id,qid) {
return fetch('get_qid_counts.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ qid })
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not OK');
}
return response.json();
})
.then(data => {
if (data.error) {
throw new Error(data.error);
}
// console.log(data);
// console.log(data[0][Object.keys(data[0])[0]]);
/* */
bardata = {
"-3": data[0][Object.keys(data[0])[0]],
"-2": data[1][Object.keys(data[1])[0]],
"-1": data[2][Object.keys(data[2])[0]],
"0": data[3][Object.keys(data[3])[0]],
"1": data[4][Object.keys(data[4])[0]],
"2": data[5][Object.keys(data[5])[0]],
"3": data[6][Object.keys(data[6])[0]],
};
//console.log(bardata);
drawBar(id,bardata);
// return data; // Should be an array like [{ value: -3, count: 2 }, ..., { value: 3, count: 5 }]
});
}

View File

@ -155,7 +155,7 @@ svg.append("text")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", bigfont)
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.attr("font-family", 'sans-serif, Consolas, "Lucida Console", Menlo, "DejaVu Sans Mono", monospace')
.text(`${mean}`);
// Add axis labels

View File

@ -133,7 +133,7 @@ const midY = (bottomLeft[1] + bottomRight[1]) / 2;
if (!svg.classed("no-text")){
svg.append("text")
.attr("x", midX)
.attr("y", midY + 30) // Adjust for correct height (moved to bottom)
.attr("y", midY + 25) // Adjust for correct height (moved to bottom)
.attr("text-anchor", "middle")
.attr("fill", textcolour) // My Colour
.attr("font-size", "22px")
@ -142,20 +142,20 @@ svg.append("text")
}
// And now a central number
let bigy = midY-45;
let bigy = midY + 70;
let bigfont = "36px";
if (svg.classed("big-number")){
bigy = midY-85;
bigy = midY + 120;
bigfont = "70px";
}
svg.append("text")
.attr("x", midX)
.attr("y", midY + 70)
.attr("y", bigy)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", bigfont)
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.attr("font-family", 'sans-serif, Consolas, "Lucida Console", Menlo, "DejaVu Sans Mono", monospace')
.text(`${mean}`);
}

View File

@ -7,7 +7,7 @@ $dataCentre = $config['data_centre'];
$surveyId = $_POST['survey_id'] ?? null;
if (!$surveyId) {
$surveyId="SV_bD838sNKZEmi6Tc"; // *****FIXME***** JUST FOR DEVELOPMENT
$surveyId="SV_cwKjMqAqGxImjMG"; // *****FIXME***** JUST FOR DEVELOPMENT
//die("No survey ID provided.");
}
@ -93,6 +93,10 @@ curl_close($ch);
// Decode the response
$data = json_decode($response, true);
//For testing only
echo $response;
//Save surveyId
//insertSurveyIfNotExists($identifier, $description); // The identifier is actually the surveyId, and the description isn't included at this point.
$surveyIndex = getOrCreateSurvey($surveyId, "");

View File

@ -7,7 +7,8 @@ $dataCenter = $config['data_centre'];
// Get the survey ID from POST
$surveyId = $_POST['survey_id'] ?? null;
if (!$surveyId) {
$surveyId="SV_cAstEvm4ZrPaqGi";
//$surveyId="SV_cAstEvm4ZrPaqGi";
$surveyId="SV_cwKjMqAqGxImjMG";
#die("No survey ID provided.");
}

View File

@ -40,6 +40,19 @@ $surveys = $result['result']['elements'] ?? [];
<body>
<h1>Select a Survey</h1>
<p>This tool has been created by Peter Edmond working for <a href="https://www.telospartners.com/">Telos Partners</a> as part of the OPL Data Analysis Project. Whilst it *SHOULD* behave as expected, it has been know for lightning to strike, computers to explode, and pigs to fly (allegedly, if thrown out of an aircraft?). There may be other interesting side effects? If this software does something unexpected, then it should be addressed to Telos Partners <a href="https://www.chiark.greenend.org.uk/~sgtatham/bugs.html">AFTER READING AND UNDERSTANDING how to report bugs effectively</a>.
</p>
<p>In order to be able to access the survey data, you must use this form to export the data from <a href="https://telospartners.eu.qualtrics.com/login">Qualtrics</a>. This is done via an API key. Normally the survey will be immediately visible by name in the drop down, however under certain circumstances this might not work, such as if it has the same name as another survey, or the survey has not been shared with the account that is associated with the API.
</p>
<p>The ability to check whether a surveyId is accessible for exporting can be checked directly via the surveyId. The form allowing direct entry of the surveyID lso carries out a full export of the data associated with the requested surveyId (provided that surveyId data can be accessed). The template survey is surveyId SV_cwKjMqAqGxImjMG if you wish to test a value. The surveyId is of the form SV_************** and can be found by looking at the survey web page path when looking at the survey in the Qualtrics interface.
</p>
<p>NOTE - Once you have pressed submit, your browser will appear to freeze. This is because there is LOADS of work going on in the background to authenticate, identify all the answers that have been provided to this survey, and download them. Once the available answer sets have been downloaded, you will get a messy page showing the surveyId, the total number of COMPLETED AND SUBMITTED response sets (responseId). Once the page with the Response IDs has appeared, then the data has been fully exported, and is <a href="./reportTemplate.html">available for analysis.</a></p>
<p>The export process OVER-WRITES any previous results for a particular survey. This means that that if data is deleted in the Qualtrics interface, then that data set will be lost. Additionally, by importing the data, and additional completed surveys will be added to the data set and be available for analysis. Carrying out the import process effectively aims to sychronise the data for analysis with that from the Qualtrics survey software.</p>
<?php if (empty($surveys)): ?>
<p>No surveys found or an error occurred.</p><br><br><hr><br>
@ -61,6 +74,13 @@ $surveys = $result['result']['elements'] ?? [];
<br><br>
<input type="submit" value="Submit">
</form>
<br>
<form method="POST" action="getData.php">
<label for="survey_id">.....OR enter a surveyId to download data and produce reports:</label>
<input name="survey_id" id="survey_id">
<br><br>
<input type="submit" value="Submit">
</form>
<?php endif; ?>
</body>
</html>

View File

@ -1,13 +1,19 @@
<?php
header('Content-Type: application/json');
// Basic input validation and sanitization
if (!isset($_POST['qid']) || empty($_POST['qid'])) {
echo json_encode(['error' => 'Missing QID parameter']);
exit;
if (php_sapi_name() === 'cli') {
echo "Running from command line.\n";
$qid="QID2_7";
} else {
//echo "Running from browser.\n";
// Basic input validation and sanitization
if (!isset($_POST['qid']) || empty($_POST['qid'])) {
echo json_encode(['error' => 'Missing QID parameter']);
exit;
}
$qid = $_POST['qid'];
}
$qid = $_POST['qid'];
// Database connection (adjust credentials accordingly)
//
@ -54,7 +60,8 @@ try {
// Return as JSON array of objects [{value: -3, count: 5}, ...]
$response = [];
foreach ($counts as $value => $count) {
$response[] = ['value' => $value, 'count' => $count];
//$response[] = ['value' => $value, 'count' => $count];
$response[] = ['"'.strval($value).'"' => $count];
}
echo json_encode($response);
@ -65,3 +72,12 @@ try {
}

View File

@ -1,148 +1,345 @@
function RAGGED(average){
// This returns the correct colour red, amber or gree depending on the value presented
if (average <= -1) {
return "red";
}
if (average >= 1) {
return "green";
}
return "#ffbf00";
// This returns the correct colour red, amber or gree depending on the value presented
if (average <= -1) {
return "red";
}
if (average >= 1) {
return "green";
}
return "#ffbf00";
}
function getAverage(prefix) {
console.log("Prefix:", prefix);
const elements = Array.from(document.querySelectorAll(`svg[id^="${prefix}"] tspan.average`));
const numbers = elements.map(el => {
const text = el.textContent;
//console.log("Raw text content:", text);
const value = parseFloat(text);
//console.log("Parsed value:", value);
return value;
}).filter(n => !isNaN(n));
//console.log("Parsed numeric values:", numbers);
if (numbers.length === 0) {
console.warn("No valid numbers found!");
return NaN;
}
function getAverage(prefix) {
console.log("Prefix:", prefix);
const elements = Array.from(document.querySelectorAll(`svg[id^="${prefix}"] tspan.average`));
const numbers = elements.map(el => {
const text = el.textContent;
//console.log("Raw text content:", text);
const value = parseFloat(text);
//console.log("Parsed value:", value);
return value;
}).filter(n => !isNaN(n));
//console.log("Parsed numeric values:", numbers);
if (numbers.length === 0) {
console.warn("No valid numbers found!");
return NaN;
}
const avg = numbers.reduce((sum, n) => sum + n, 0) / numbers.length;
//console.log("Average of averages:", avg);
return avg;
}
function loaded(){
console.log("loaded");
let amber = '#ffbf00';
//doBigWhiteTriangle('svg1');
//drawtriangle('#svg1','Roles','#008845',[0.5,0.6,0.5],'red', { x: 0, y: 350 },-0.7);
//drawtriangle('#svg1','Actions','#b2c8c4',[0.1,0.6,0.5],'green',{ x: 370, y: 350 },2.3);
//drawtriangle('#svg1','Approach','#ed4c0c',[0.3,0.6,0.5],amber,{ x: 185, y: 30 },1.4);
//drawtriangleinverted('#svg1','Impact','#74469c',[0.7,0.6,0.8],'green',{ x: 185, y: 243},2.4);
//makeSvgRightClickable('svg1');
//doLittleWhiteTriangle('svg2');
//drawtriangle('#svg2','Roles','#008845',[0.5,0.6,0.5],'', { x: 0, y: 100 },-0.7);
//EO ROLES
//Great Employee Owners
let average = doBarData('#svg1_1','QID35_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg1_2','QID35_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg1_3','QID35_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg1_4','QID35_9');
//makeSvgRightClickable('svg1_4');
doBarData('#svg1_5','QID35_10');
//makeSvgRightClickable('svg1_5');
//Great EO Leaders
average = doBarData('#svg2_1','QID35_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg2_2','QID35_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg2_3','QID35_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg2_4','QID35_7');
//makeSvgRightClickable('svg1_4');
//doBarData('#svg2_5','QID35_10');
//makeSvgRightClickable('svg1_5');
//Great EO Governance
average = doBarData('#svg3_1','QID35_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg3_2','QID35_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg3_3','QID35_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg3_4','QID35_7');
//makeSvgRightClickable('svg1_4');
doBarData('#svg3_5','QID35_10');
//makeSvgRightClickable('svg1_5');
doBarData('#svg3_6','QID35_10');
//makeSvgRightClickable('svg1_5');
// Make sure that evreything is loaded!
setTimeout(() => {
console.log("Waited 2 seconds");
// We now have access to all of the averages, so can calculate the basic triangle.
let svg1_avg = (getAverage("svg1_")+3)/7;
let svg2_avg = (getAverage("svg2_")+3)/7;
let svg3_avg = (getAverage("svg3_")+3)/7;
let roles_avg = (7*(svg1_avg+svg2_avg+svg3_avg)/3)-3; // this converts the scales lengths to the correct value
console.log(svg1_avg,svg2_avg,svg3_avg, roles_avg);
doLittleWhiteTriangle('svg_roles');
//drawtriangle('#svg_roles','Roles','#008845',[0.25,0.5,0.75],'', { x: 0, y: 100 },roles_avg.toFixed(1));
drawtriangle('#svg_roles','Roles','#008845',[svg1_avg,svg2_avg,svg3_avg],'', { x: 0, y: 100 },roles_avg.toFixed(1));
//makeSvgRightClickable('svg_roles');
doLittleWhiteTriangle('svg_roles_RAG');
drawtriangle('#svg_roles_RAG','Roles','#008845',[svg1_avg,svg2_avg,svg3_avg],RAGGED(roles_avg), { x: 0, y: 100 },roles_avg.toFixed(1));
//makeSvgRightClickable('svg_roles_RAG');
doLittleWhiteTriangle('svg_roles_test');
drawtriangle('#svg_roles_test','Roles','#008845',[0.95,0.95,0.95],RAGGED(roles_avg), { x: 0, y: 100 },roles_avg.toFixed(1));
//makeSvgRightClickable('svg_roles_test');
}, 500);
//EO APPROACH
//drawBar('#svg1_1','QID34_7');
//makeSvgRightClickable('svg1_1');
//drawBar('#svg1_2');
//makeSvgRightClickable('svg1_2');
//drawBar('#svg1_3');
//makeSvgRightClickable('svg1_3');
//drawBar('#svg1_4');
//makeSvgRightClickable('svg1_4');
//drawBar('#svg1_5');
//makeSvgRightClickable('svg1_5');
}
const avg = numbers.reduce((sum, n) => sum + n, 0) / numbers.length;
//console.log("Average of averages:", avg);
return avg;
}
function loaded(){
console.log("loaded");
let amber = '#ffbf00';
//doBigWhiteTriangle('svg1');
//drawtriangle('#svg1','Roles','#008845',[0.5,0.6,0.5],'red', { x: 0, y: 350 },-0.7);
//drawtriangle('#svg1','Actions','#b2c8c4',[0.1,0.6,0.5],'green',{ x: 370, y: 350 },2.3);
//drawtriangle('#svg1','Approach','#ed4c0c',[0.3,0.6,0.5],amber,{ x: 185, y: 30 },1.4);
//drawtriangleinverted('#svg1','Impact','#74469c',[0.7,0.6,0.8],'green',{ x: 185, y: 243},2.4);
//makeSvgRightClickable('svg1');
//doLittleWhiteTriangle('svg2');
//drawtriangle('#svg2','Roles','#008845',[0.5,0.6,0.5],'', { x: 0, y: 100 },-0.7);
//EO ROLES
//Great Employee Owners
let average = doBarData('#svg1_1','QID35_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg1_2','QID35_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg1_3','QID35_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg1_4','QID35_9');
//makeSvgRightClickable('svg1_4');
doBarData('#svg1_5','QID35_10');
//makeSvgRightClickable('svg1_5');
//Great EO Leaders
average = doBarData('#svg2_1','QID36_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg2_2','QID36_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg2_3','QID36_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg2_4','QID36_9');
//makeSvgRightClickable('svg1_4');
//Great EO Governance
average = doBarData('#svg3_1','QID37_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg3_2','QID37_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg3_3','QID37_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg3_4','QID37_20');
//makeSvgRightClickable('svg1_4');
doBarData('#svg3_5','QID37_21');
//makeSvgRightClickable('svg1_5');
doBarData('#svg3_6','QID37_22');
//makeSvgRightClickable('svg1_5');
//EO APPROACH
//Great EO Culture
average = doBarData('#svg4_1','QID2_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg4_2','QID2_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg4_3','QID2_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg4_4','QID2_9');
//makeSvgRightClickable('svg1_4');
//Great EO Engagement
average = doBarData('#svg5_1','QID33_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg5_2','QID33_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg5_3','QID33_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg5_4','QID33_9');
//makeSvgRightClickable('svg1_4');
//Great EO Stewardship
average = doBarData('#svg6_1','QID34_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg6_2','QID34_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg6_3','QID34_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg6_4','QID34_17');
//makeSvgRightClickable('svg1_4');
//EO ACTIONS
//Great EO Strategy
average = doBarData('#svg7_1','QID40_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg7_2','QID40_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg7_3','QID40_8');
//makeSvgRightClickable('svg1_3');
doBarData('#svg7_4','QID40_9');
//makeSvgRightClickable('svg1_4');
//Great EO Innovation
average = doBarData('#svg8_1','QID41_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg8_2','QID41_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg8_3','QID41_19');
//makeSvgRightClickable('svg1_3');
doBarData('#svg8_4','QID41_20');
//makeSvgRightClickable('svg1_4');
doBarData('#svg8_5','QID41_21');
//makeSvgRightClickable('svg1_5');
//Great EO Advantage
average = doBarData('#svg9_1','QID42_7');
//makeSvgRightClickable('svg1_1');
doBarData('#svg9_2','QID42_2');
//makeSvgRightClickable('svg1_2');
doBarData('#svg9_3','QID42_8');
//makeSvgRightClickable('svg1_3');
//EO RESULTS
//Great EO Measurement
average = doBarData('#svg10_1','QID44_21');
//makeSvgRightClickable('svg1_1');
doBarData('#svg10_2','QID44_7');
//makeSvgRightClickable('svg1_2');
doBarData('#svg10_3','QID44_2');
//makeSvgRightClickable('svg1_3');
doBarData('#svg10_4','QID44_8');
//makeSvgRightClickable('svg1_4');
//Great EO Evaluation
average = doBarData('#svg11_1','QID45_24');
//makeSvgRightClickable('svg1_1');
doBarData('#svg11_2','QID45_25');
//makeSvgRightClickable('svg1_2');
doBarData('#svg11_3','QID45_26');
//makeSvgRightClickable('svg1_3');
doBarData('#svg11_4','QID45_29');
//makeSvgRightClickable('svg1_4');
//Great EO Impact
average = doBarData('#svg12_1','QID46_27');
//makeSvgRightClickable('svg1_1');
doBarData('#svg12_2','QID46_28');
//makeSvgRightClickable('svg1_2');
doBarData('#svg12_3','QID46_29');
//makeSvgRightClickable('svg1_3');
doBarData('#svg12_4','QID46_30');
//makeSvgRightClickable('svg1_4');
doBarData('#svg12_5','QID46_31');
//makeSvgRightClickable('svg1_5');
doBarData('#svg12_6','QID46_32');
//makeSvgRightClickable('svg1_5');
doBarData('#svg12_7','QID46_33');
//makeSvgRightClickable('svg1_3');
doBarData('#svg12_8','QID46_34');
//makeSvgRightClickable('svg1_4');
doBarData('#svg12_9','QID46_36');
//makeSvgRightClickable('svg1_5');
doBarData('#svg12_10','QID46_37');
//makeSvgRightClickable('svg1_5');
// Make sure that evreything is loaded!
setTimeout(() => {
console.log("Waited 8 seconds");
// We now have access to all of the averages, so can calculate the basic triangle.
//EO ROLES
let svg1_avg = (getAverage("svg1_")+3)/7;
let svg2_avg = (getAverage("svg2_")+3)/7;
let svg3_avg = (getAverage("svg3_")+3)/7;
let roles_avg = (7*(svg1_avg+svg2_avg+svg3_avg)/3)-3; // this converts the scales lengths to the correct value
console.log(svg1_avg,svg2_avg,svg3_avg, roles_avg);
doLittleWhiteTriangle('svg_roles');
//drawtriangle('#svg_roles','Roles','#008845',[0.25,0.5,0.75],'', { x: 0, y: 100 },roles_avg.toFixed(1));
drawtriangle('#svg_roles','Roles','#008845',[svg1_avg,svg2_avg,svg3_avg],'', { x: 0, y: 100 },roles_avg.toFixed(1));
//makeSvgRightClickable('svg_roles');
doLittleWhiteTriangle('svg_roles_RAG');
drawtriangle('#svg_roles_RAG','Roles','#008845',[svg1_avg,svg2_avg,svg3_avg],RAGGED(roles_avg), { x: 0, y: 100 },roles_avg.toFixed(1));
//makeSvgRightClickable('svg_roles_RAG');
doLittleWhiteTriangle('svg_roles_test');
drawtriangle('#svg_roles_test','Roles','#008845',[0.95,0.95,0.95],RAGGED(roles_avg), { x: 0, y: 100 },roles_avg.toFixed(1));
//makeSvgRightClickable('svg_roles_test');
//EO APPROACH
let svg4_avg = (getAverage("svg4_")+3)/7;
let svg5_avg = (getAverage("svg5_")+3)/7;
let svg6_avg = (getAverage("svg6_")+3)/7;
let approach_avg = (7*(svg4_avg+svg5_avg+svg6_avg)/3)-3; // this converts the scales lengths to the correct value
console.log(svg4_avg,svg5_avg,svg6_avg,approach_avg);
doLittleWhiteTriangle('svg_approach');
//drawtriangle('#svg_approach','Approach','#008845',[0.25,0.5,0.75],'', { x: 0, y: 100 },average_avg.toFixed(1));
drawtriangle('#svg_approach','Approach','#ed4c0c',[svg4_avg,svg5_avg,svg6_avg],'', { x: 0, y: 100 },approach_avg.toFixed(1));
//makeSvgRightClickable('svg_approach');
doLittleWhiteTriangle('svg_approach_RAG');
drawtriangle('#svg_approach_RAG','Approach','#ed4c0c',[svg4_avg,svg5_avg,svg6_avg],RAGGED(approach_avg), { x: 0, y: 100 },approach_avg.toFixed(1));
//makeSvgRightClickable('svg_approach_RAG');
//doLittleWhiteTriangle('svg_approach_test');
//drawtriangle('#svg_approach_test','Approach','#ed4c0c',[0.95,0.95,0.95],RAGGED(approach_avg), { x: 0, y: 100 },approach_avg.toFixed(1));
//makeSvgRightClickable('svg_approach_test');
//EO ACTIONS
let svg7_avg = (getAverage("svg7_")+3)/7;
let svg8_avg = (getAverage("svg8_")+3)/7;
let svg9_avg = (getAverage("svg9_")+3)/7;
let actions_avg = (7*(svg7_avg+svg8_avg+svg9_avg)/3)-3; // this converts the scales lengths to the correct value
console.log(svg7_avg,svg8_avg,svg9_avg,actions_avg);
doLittleWhiteTriangle('svg_actions');
//drawtriangle('#svg_actions','Actions','#b2c8c4',[0.25,0.5,0.75],'', { x: 0, y: 100 },actions_avg.toFixed(1));
drawtriangle('#svg_actions','Actions','#b2c8c4',[svg7_avg,svg8_avg,svg9_avg],'', { x: 0, y: 100 },actions_avg.toFixed(1));
//makeSvgRightClickable('svg_actions');
doLittleWhiteTriangle('svg_actions_RAG');
drawtriangle('#svg_actions_RAG','Actions','#b2c8c4',[svg7_avg,svg8_avg,svg9_avg],RAGGED(actions_avg), { x: 0, y: 100 },actions_avg.toFixed(1));
//makeSvgRightClickable('svg_actions_RAG');
//doLittleWhiteTriangle('svg_actions_test');
//drawtriangle('#svg_actions_test','Actions','#b2c8c4',[0.95,0.95,0.95],RAGGED(actions_avg), { x: 0, y: 100 },actions_avg.toFixed(1));
//makeSvgRightClickable('svg_actions_test');
//EO IMPACT
let svg10_avg = (getAverage("svg10_")+3)/7;
let svg11_avg = (getAverage("svg11_")+3)/7;
let svg12_avg = (getAverage("svg12_")+3)/7;
let results_avg = (7*(svg10_avg+svg11_avg+svg12_avg)/3)-3; // this converts the scales lengths to the correct value
console.log(svg10_avg,svg11_avg,svg12_avg,results_avg);
doLittleWhiteTriangle('svg_results');
//drawtriangle('#svg_results','Results','#74469',[0.25,0.5,0.75],'', { x: 0, y: 100 },impact_avg.toFixed(1));
drawtriangleinverted('#svg_results','Results','#74469c',[svg10_avg,svg11_avg,svg12_avg],'', { x: 0, y: 0 },results_avg.toFixed(1));
//makeSvgRightClickable('svg_results');
doLittleWhiteTriangle('svg_results_RAG');
drawtriangleinverted('#svg_results_RAG','Results','#74469c',[svg10_avg,svg11_avg,svg12_avg],RAGGED(results_avg), { x: 0, y: 0 },results_avg.toFixed(1));
//makeSvgRightClickable('svg_results_RAG');
doLittleWhiteTriangle('svg_results_test');
drawtriangleinverted('#svg_results_test','Results','#74469c',[0.95,0.95,0.95],RAGGED(results_avg), { x: 0, y: 0 },results_avg.toFixed(1));
//makeSvgRightClickable('svg_results_test');
doBigWhiteTriangle('svg_pyramid');
drawtriangle('#svg_pyramid','Roles','#008845',[svg1_avg,svg2_avg,svg3_avg],'', { x: 0, y: 350 },roles_avg.toFixed(1));
drawtriangle('#svg_pyramid','Actions','#b2c8c4',[svg4_avg,svg5_avg,svg6_avg],'',{ x: 370, y: 350 },actions_avg.toFixed(1));
drawtriangle('#svg_pyramid','Approach','#ed4c0c',[svg7_avg,svg8_avg,svg9_avg],'',{ x: 185, y: 30 },approach_avg.toFixed(1));
drawtriangleinverted('#svg_pyramid','Results','#74469c',[svg10_avg,svg11_avg,svg12_avg],'',{ x: 185, y: 243},results_avg.toFixed(1));
makeSvgRightClickable('svg_pyramid');
doBigWhiteTriangle('svg_pyramid_RAG');
drawtriangle('#svg_pyramid_RAG','Roles','#008845',[svg1_avg,svg2_avg,svg3_avg],RAGGED(roles_avg), { x: 0, y: 350 },roles_avg.toFixed(1));
drawtriangle('#svg_pyramid_RAG','Actions','#b2c8c4',[svg4_avg,svg5_avg,svg6_avg],RAGGED(actions_avg),{ x: 370, y: 350 },actions_avg.toFixed(1));
drawtriangle('#svg_pyramid_RAG','Approach','#ed4c0c',[svg7_avg,svg8_avg,svg9_avg],RAGGED(approach_avg),{ x: 185, y: 30 },approach_avg.toFixed(1));
drawtriangleinverted('#svg_pyramid_RAG','Results','#74469c',[svg10_avg,svg11_avg,svg12_avg],RAGGED(results_avg),{ x: 185, y: 243},results_avg.toFixed(1));
makeSvgRightClickable('svg_pyramid_RAG');
doBigWhiteTriangle('svg_pyramid_RAG_test');
drawtriangle('#svg_pyramid_RAG_test','Roles','#008845',[0.9,0.9,0.9],RAGGED(roles_avg), { x: 0, y: 350 },roles_avg.toFixed(1));
drawtriangle('#svg_pyramid_RAG_test','Actions','#b2c8c4',[0.9,0.9,0.9],RAGGED(actions_avg),{ x: 370, y: 350 },actions_avg.toFixed(1));
drawtriangle('#svg_pyramid_RAG_test','Approach','#ed4c0c',[0.9,0.9,0.9],RAGGED(approach_avg),{ x: 185, y: 30 },approach_avg.toFixed(1));
drawtriangleinverted('#svg_pyramid_RAG_test','Results','#74469c',[0.9,0.9,0.9],RAGGED(results_avg),{ x: 185, y: 243},results_avg.toFixed(1));
makeSvgRightClickable('svg_pyramid_RAG_test');
doBigWhiteTriangle('svg_pyramid_RAG_test2');
drawtriangle('#svg_pyramid_RAG_test2','Roles','#008845',[0.95,0.95,0.95],RAGGED(roles_avg), { x: 0, y: 350 },roles_avg.toFixed(1));
drawtriangle('#svg_pyramid_RAG_test2','Actions','#b2c8c4',[0.95,0.95,0.95],RAGGED(actions_avg),{ x: 370, y: 350 },actions_avg.toFixed(1));
drawtriangle('#svg_pyramid_RAG_test2','Approach','#ed4c0c',[0.95,0.95,0.95],RAGGED(approach_avg),{ x: 185, y: 30 },approach_avg.toFixed(1));
drawtriangleinverted('#svg_pyramid_RAG_test2','Results','#74469c',[0.95,0.95,0.95],RAGGED(results_avg),{ x: 185, y: 243},results_avg.toFixed(1));
makeSvgRightClickable('svg_pyramid_RAG_test2');
}, 800);
}

View File

@ -57,7 +57,7 @@ function doLittleWhiteTriangle(id){
/*
function inlineStyles(svgElement) {
const allElements = svgElement.querySelectorAll('*');
const computedStyles = window.getComputedStyle(svgElement);
@ -78,9 +78,46 @@ function inlineStyles(svgElement) {
});
}
*/
function inlineStyles(svgElement) {
const allElements = svgElement.querySelectorAll('*');
allElements.forEach(el => {
const computed = window.getComputedStyle(el);
const style = [];
for (let i = 0; i < computed.length; i++) {
const key = computed[i];
let value = computed.getPropertyValue(key);
// Replace currentColor with resolved color
if (value === 'currentcolor') {
value = computed.color;
}
style.push(`${key}:${value};`);
}
el.setAttribute('style', style.join(' '));
});
// Also inline root <svg>
const svgComputed = window.getComputedStyle(svgElement);
let rootStyle = '';
for (let i = 0; i < svgComputed.length; i++) {
const key = svgComputed[i];
let value = svgComputed.getPropertyValue(key);
if (value === 'currentcolor') {
value = svgComputed.color;
}
rootStyle += `${key}:${value};`;
}
svgElement.setAttribute('style', rootStyle);
}
/*
function makeSvgRightClickable(id) {
const svg = document.getElementById(id);
inlineStyles(svg);
@ -101,10 +138,48 @@ function makeSvgRightClickable(id) {
img.alt = "Right-click to save SVG image";
// Replace or insert after SVG
svg.style.display = "none"; // hide original
//svg.style.display = "none"; // hide original
svg.parentNode.insertBefore(img, svg.nextSibling);
}
}
// Call the function after D3 has drawn the SVG
//makeSvgRightClickable("id");
*/
function makeSvgRightClickable(id) {
const svg = document.getElementById(id);
inlineStyles(svg);
// Set namespace
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
// Ensure width and height are set
if (!svg.hasAttribute("width")) svg.setAttribute("width", svg.getBoundingClientRect().width);
if (!svg.hasAttribute("height")) svg.setAttribute("height", svg.getBoundingClientRect().height);
// Serialize
const svgData = new XMLSerializer().serializeToString(svg);
const svgBlob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
const url = URL.createObjectURL(svgBlob);
// Create image element
const img = document.createElement("img");
img.src = url;
img.width = svg.getAttribute("width");
img.height = svg.getAttribute("height");
img.alt = "Right-click to save SVG image";
if (svg.classList.contains("pyramid")) {
img.classList.add("pyramid");
}
if (svg.classList.contains("triangle")) {
img.classList.add("triangle");
}
svg.style.display = "none";
svg.parentNode.insertBefore(img, svg.nextSibling);
}