function drawBar(id,data) { //console.log(id); const svg = d3.select(`${id}`); const backgroundwidth = +svg.attr("width"); const backgroundradius = 10; const width = 600; //+svg.attr("width"); const height = 200; //+svg.attr("height"); const margin = { top: 40, right: 30, bottom: 60, left: 30 }; // Draw the white background // Draw the rounded rectangle svg.append("rect") .attr("x", 0) .attr("y", 0) .attr("width", backgroundwidth) .attr("height", height) .attr("rx", backgroundradius) .attr("ry", backgroundradius) .attr("fill", "white"); // .attr("stroke", "white") // .attr("stroke-width", 2); //const data = { /* data = { "-3": 0, "-2": 1, "-1": 3, "0": 0, "1": 2, "2": 0, "3": 10 }; */ //console.log(data); const dataArray = Object.entries(data).map(([key, count]) => ({ key: +key, count: count })); const x = d3.scaleBand() .domain([-3,-2,-1,0,1,2,3]) .range([margin.left, width - margin.right]) .padding(0); const y = d3.scaleLinear() .domain([0, d3.max(dataArray, d => d.count)]) .nice() .range([height - margin.bottom, margin.top]); // X Axis svg.append("g") .attr("transform", `translate(0,${height - margin.bottom})`) .call(d3.axisBottom(x) .tickSize(0)) .selectAll("text") .attr("x", 0) .attr("y", 10) .style("text-anchor", "middle") .style("font-size", "12px"); // Add the required ticks const xTicks = d3.scaleLinear() .domain([-3.5, 3.5]) .range([margin.left, width - margin.right]); svg.append("g") .attr("transform", `translate(0,${height - margin.bottom})`) .call(d3.axisBottom(xTicks).tickValues(d3.range(-3.5, 4, 1))) .selectAll("text") .style("visibility", "hidden"); // This hides the labels // Y Axis //svg.append("g") // .attr("transform", `translate(${margin.left},0)`) // .call(d3.axisLeft(y).ticks(5)); // Bars svg.selectAll(".bar") .data(dataArray) .enter() .append("rect") .attr("class", "bar") .attr("x", d => x(d.key)) .attr("y", d => y(d.count)) .attr("width", x.bandwidth()) .attr("height", d => y(0) - y(d.count)) .attr("fill", "#003c4b"); // From brand guidelines // Labels svg.selectAll(".label") .data(dataArray) .enter() .append("text") .attr("x", d => x(d.key) + x.bandwidth() / 2) .attr("y", d => d.count > 0 ? y(d.count) - 5 : y(0)) .attr("text-anchor", "middle") .attr("font-size", "12px") .attr("font-style", "italic") .attr("fill", "black") .text(d => d.count > 0 ? d.count : ""); // Average line const format = d3.format(".2f"); const totalCount = d3.sum(dataArray, d => d.count); const weightedSum = d3.sum(dataArray, d => d.key * d.count); 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(-0.50); // Temporary for testing svg.append("line") .attr("x1", avgX) .attr("x2", avgX) .attr("y1", y(0)+20) .attr("y2", y(d3.max(dataArray, d => d.count)) - 20) .attr("stroke", "#e40074") // From brand guidelines .attr("stroke-width", 4) .attr("stroke-dasharray", "10,4"); /* svg.append("text") .attr("x", avgX) .attr("y", y(d3.max(dataArray, d => d.count)) - 30) .attr("text-anchor", "middle") .attr("fill", "#e40074") .attr("font-size", "12px") .text("Average ("+average+")"); */ // Title beneath the graph /* svg.append("text") .attr("x", width / 2) .attr("y", height - 10) // Just below the x-axis .attr("text-anchor", "middle") .attr("font-size", "14px") .attr("fill", "black") .text("Demo bar graph"); */ // Add info to right of bar chart // Oblong settings const boxx = 610; const boxy = 60; const boxwidth = 170; const boxheight = 80; const cornerRadius = 10; // Draw the rounded rectangle svg.append("rect") .attr("x", boxx) .attr("y", boxy) .attr("width", boxwidth) .attr("height", boxheight) .attr("rx", cornerRadius) .attr("ry", cornerRadius) .attr("fill", "white") .attr("stroke", "#333") .attr("stroke-width", 2); // Draw the horizontal divider svg.append("line") .attr("x1", boxx) .attr("x2", boxx + boxwidth) .attr("y1", boxy + boxheight / 2) .attr("y2", boxy + boxheight / 2) .attr("stroke", "#333") .attr("stroke-width", 1); // Add text to the top half svg.append("text") .attr("x", boxx + boxwidth / 2) .attr("y", boxy + boxheight / 4) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle") .attr("font-size", "20px") .attr("font-weight", "400") // 400 is normal, 700 is bold, 900 is extra-bold .attr("font-family", "sans-serif") .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") .attr("x", boxx + boxwidth / 2) .attr("y", boxy + 3 * boxheight / 4) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle") .attr("font-size", "20px") .attr("font-weight", "400") // 400 is normal, 700 is bold, 900 is extra-bold .attr("font-family", "sans-serif") .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 }] }); }