163 lines
3.8 KiB
HTML
163 lines
3.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>Bar Chart - Fixed Height Bars</title>
|
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: sans-serif;
|
|
margin: 40px;
|
|
}
|
|
|
|
.bar {
|
|
fill: steelblue;
|
|
stroke: black;
|
|
stroke-width: 1px;
|
|
}
|
|
|
|
.axis path,
|
|
.axis line {
|
|
stroke: black;
|
|
shape-rendering: crispEdges;
|
|
}
|
|
|
|
#tooltip {
|
|
position: absolute;
|
|
visibility: hidden;
|
|
background-color: white;
|
|
border: 1px solid black;
|
|
padding: 4px;
|
|
font-size: 12px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<svg width="600" height="250"></svg>
|
|
|
|
<script>
|
|
const svg = d3.select("svg");
|
|
const width = +svg.attr("width");
|
|
const height = +svg.attr("height");
|
|
const margin = { top: 40, right: 30, bottom: 100, left: 30 };
|
|
|
|
const data = {
|
|
"-3": 0,
|
|
"-2": 1,
|
|
"-1": 3,
|
|
"0": 0,
|
|
"1": 2,
|
|
"2": 0,
|
|
"3": 6
|
|
};
|
|
|
|
const categories = ["Extremely Bad", "Very Bad", "Bad", "Neutral", "Good", "Very Good", "Extremely Good"];
|
|
|
|
|
|
// Convert object to array of {key, value}
|
|
const dataArray = Object.entries(data).map(([key, count]) => ({
|
|
key: +key,
|
|
count: count,
|
|
show: count > 0
|
|
}));
|
|
|
|
// Scales
|
|
const x = d3.scaleBand()
|
|
.domain(categories) // [-3, -2, ..., 3]
|
|
.range([margin.left, width - margin.right])
|
|
.padding(0); //space between bars
|
|
|
|
const y = d3.scaleLinear()
|
|
.domain([0, 1]) // fixed height of 1
|
|
.range([height - margin.bottom, margin.top]);
|
|
|
|
// X-axis
|
|
const tickValues = d3.range(-3.5, 3.5, 0.5);
|
|
svg.append("g")
|
|
.attr("transform", `translate(0,${height - margin.bottom})`)
|
|
.call(d3.axisBottom(x).tickFormat(d => d))
|
|
.selectAll("text")
|
|
.attr("transform", "rotate(-45)") // Rotate them
|
|
.attr("x", -10) // Adjust x position for rotation
|
|
.attr("y", 5) // Adjust y position for rotation
|
|
.style("text-anchor", "end") // Anchor text to the start for rotation
|
|
.style("font-size", "12px"); // Adjust font size as needed
|
|
|
|
// Draw bars
|
|
svg.selectAll(".bar")
|
|
.data(dataArray)
|
|
.enter()
|
|
.append("rect")
|
|
.attr("class", "bar")
|
|
.attr("x", d => x(categories[d.key+3]))
|
|
.attr("y", d => d.show ? y(1) : y(0))
|
|
.attr("width", x.bandwidth())
|
|
.attr("height", d => d.show ? y(0) - y(1) : 0);
|
|
|
|
//Add values above bars:
|
|
svg.selectAll(".bar-label")
|
|
.data(dataArray)
|
|
.enter()
|
|
.append("text")
|
|
.attr("class", "bar-label")
|
|
.attr("x", d => x(categories[d.key+3]) + x.bandwidth() / 2)
|
|
.attr("y", d => d.count > 0 ? y(1) - 5 : y(0)) // 5px above the bar
|
|
.attr("text-anchor", "middle")
|
|
.attr("font-size", "12px")
|
|
.attr("fill", "black")
|
|
.text(d => d.count > 0 ? d.count : "");
|
|
|
|
// Display average line
|
|
|
|
const totalCount = d3.sum(dataArray, d => d.count);
|
|
const weightedSum = d3.sum(dataArray, d => d.key * d.count);
|
|
const 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 averageX = xLinear(average);
|
|
|
|
// Draw the vertical red line
|
|
svg.append("line")
|
|
.attr("x1", averageX)
|
|
.attr("x2", averageX)
|
|
.attr("y1", y(0))
|
|
.attr("y2", y(1) - 20) //raise by 20px
|
|
.attr("stroke", "red")
|
|
.attr("stroke-width", 2)
|
|
.attr("stroke-dasharray", "4,2"); // Optional dashed line
|
|
|
|
// Add "Average" label above the line
|
|
const formatAvg = d3.format(".2f");
|
|
svg.append("text")
|
|
.attr("x", averageX)
|
|
.attr("y", y(1) - 30) //was -10
|
|
.attr("text-anchor", "middle")
|
|
.attr("fill", "red")
|
|
.attr("font-size", "12px")
|
|
//.text(`Average(mean): ${formatAvg(average)}`);
|
|
.text(`Average(mean)`);
|
|
|
|
// Title beneath the graph
|
|
svg.append("text")
|
|
.attr("x", width / 2)
|
|
.attr("y", height - 5) // Just below the x-axis
|
|
.attr("text-anchor", "middle")
|
|
.attr("font-size", "14px")
|
|
.attr("fill", "black")
|
|
.text("Demo bar graph");
|
|
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|
|
|
|
|