All triangle demos provided for approval

This commit is contained in:
Peter Edmond 2025-05-13 18:54:42 +01:00
parent 80f0a16a71
commit c11b0cee20
8 changed files with 1572 additions and 0 deletions

206
actions.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
//.area {
// fill: rgba(215, 96, 35, 0.1); /* steelblue with transparency */
// stroke: rgba(215, 96, 35, 0.6);
// stroke-width: 2;
//}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Define axes with A at the top (rotate -90 degrees)
const axes = [
{ name: "Feature A", angle: 0 },
{ name: "Feature B", angle: 120 },
{ name: "Feature C", angle: 240 }
];
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [1.0, 0.8, 0.95];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "#6e6e6e") // #d76a23 with 30% opacity (translucent)
.attr("fill-opacity", 0.3)
.attr("stroke", "#6e6e6e") // Outer line color
.attr("stroke-width", 1); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#6e6e6e") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle
const bottomLeft = outerPoints[1];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY - 15) // Alter for correct height
.attr("text-anchor", "middle")
.attr("fill", "#6e6e6e") /// My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Actions");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY -60)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("2.7");
// Add axis labels
/*
svg.selectAll(".label")
.data(axes)
.join("text")
.attr("class", "label")
.attr("x", d => center.x + (radius + 20) * Math.cos(d.angle))
.attr("y", (d,i) => {
if (i === 0) { //adjust for 1st access, rather than using d.name
return center.y + (radius + 20) * Math.sin(d.angle)
} else
return center.y + (radius + 20 + 30) * Math.sin(d.angle)
})
.text(d => d.name);
*/
</script>
</body>
</html>

206
amber.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
//.area {
// fill: rgba(215, 96, 35, 0.1); /* steelblue with transparency */
// stroke: rgba(215, 96, 35, 0.6);
// stroke-width: 2;
//}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Define axes with A at the top (rotate -90 degrees)
const axes = [
{ name: "Feature A", angle: 0 },
{ name: "Feature B", angle: 120 },
{ name: "Feature C", angle: 240 }
];
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [0.8, 0.4, 0.6];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "#ffbf00") // #d76a23 with 30% opacity (translucent)
.attr("fill-opacity", 0.6)
.attr("stroke", "#ffbf00") // Outer line color
.attr("stroke-width", 2); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#d76a23") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle
const bottomLeft = outerPoints[1];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY - 15) // Alter for correct height
.attr("text-anchor", "middle")
.attr("fill", "black") /// My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Approach");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY -60)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("-2.1");
// Add axis labels
/*
svg.selectAll(".label")
.data(axes)
.join("text")
.attr("class", "label")
.attr("x", d => center.x + (radius + 20) * Math.cos(d.angle))
.attr("y", (d,i) => {
if (i === 0) { //adjust for 1st access, rather than using d.name
return center.y + (radius + 20) * Math.sin(d.angle)
} else
return center.y + (radius + 20 + 30) * Math.sin(d.angle)
})
.text(d => d.name);
*/
</script>
</body>
</html>

206
approach.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
//.area {
// fill: rgba(215, 96, 35, 0.1); /* steelblue with transparency */
// stroke: rgba(215, 96, 35, 0.6);
// stroke-width: 2;
//}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Define axes with A at the top (rotate -90 degrees)
const axes = [
{ name: "Feature A", angle: 0 },
{ name: "Feature B", angle: 120 },
{ name: "Feature C", angle: 240 }
];
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [0.8, 0.4, 0.6];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "#d76a23") // #d76a23 with 30% opacity (translucent)
.attr("fill-opacity", 0.3)
.attr("stroke", "#d76a23") // Outer line color
.attr("stroke-width", 1); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#d76a23") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle
const bottomLeft = outerPoints[1];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY - 15) // Alter for correct height
.attr("text-anchor", "middle")
.attr("fill", "#d76a23") /// My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Approach");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY -60)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("-2.1");
// Add axis labels
/*
svg.selectAll(".label")
.data(axes)
.join("text")
.attr("class", "label")
.attr("x", d => center.x + (radius + 20) * Math.cos(d.angle))
.attr("y", (d,i) => {
if (i === 0) { //adjust for 1st access, rather than using d.name
return center.y + (radius + 20) * Math.sin(d.angle)
} else
return center.y + (radius + 20 + 30) * Math.sin(d.angle)
})
.text(d => d.name);
*/
</script>
</body>
</html>

206
green.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
//.area {
// fill: rgba(215, 96, 35, 0.1); /* steelblue with transparency */
// stroke: rgba(215, 96, 35, 0.6);
// stroke-width: 2;
//}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Define axes with A at the top (rotate -90 degrees)
const axes = [
{ name: "Feature A", angle: 0 },
{ name: "Feature B", angle: 120 },
{ name: "Feature C", angle: 240 }
];
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [0.8, 0.4, 0.6];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "green") // #d76a23 with 30% opacity (translucent)
.attr("fill-opacity", 0.6)
.attr("stroke", "green") // Outer line color
.attr("stroke-width", 2); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#d76a23") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle
const bottomLeft = outerPoints[1];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY - 15) // Alter for correct height
.attr("text-anchor", "middle")
.attr("fill", "black") /// My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Approach");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY -60)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("-2.1");
// Add axis labels
/*
svg.selectAll(".label")
.data(axes)
.join("text")
.attr("class", "label")
.attr("x", d => center.x + (radius + 20) * Math.cos(d.angle))
.attr("y", (d,i) => {
if (i === 0) { //adjust for 1st access, rather than using d.name
return center.y + (radius + 20) * Math.sin(d.angle)
} else
return center.y + (radius + 20 + 30) * Math.sin(d.angle)
})
.text(d => d.name);
*/
</script>
</body>
</html>

159
index4bar.html Normal file
View File

@ -0,0 +1,159 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Bar Chart - Numeric Keys</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;
}
</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: 60, left: 30 };
const data = {
"-3": 0,
"-2": 1,
"-1": 3,
"0": 0,
"1": 2,
"2": 0,
"3": 10
};
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));
// 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("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);
const average = totalCount > 0 ? format(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);
svg.append("line")
.attr("x1", avgX)
.attr("x2", avgX)
.attr("y1", y(0))
.attr("y2", y(d3.max(dataArray, d => d.count)) - 20)
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("stroke-dasharray", "4,2");
svg.append("text")
.attr("x", avgX)
.attr("y", y(d3.max(dataArray, d => d.count)) - 30)
.attr("text-anchor", "middle")
.attr("fill", "red")
.attr("font-size", "12px")
.text("Average ("+average+")");
// 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>

177
inverted3axis.html Normal file
View File

@ -0,0 +1,177 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Update angles for flat top triangle
const axes = [
{ name: "Feature A", angle: 60 }, // Left axis
{ name: "Feature B", angle: 180 }, // Top axis (flat)
{ name: "Feature C", angle: 300 } // Right axis
];
// Convert angles to radians (subtract 90 degrees to rotate the whole chart)
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [0.8, 0.1, 0.76];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "#9f84b8") // #9f84b8
.attr("fill-opacity", 0.3) // with 30% opacity (translucent)
.attr("stroke", "#9f84b8") // Outer line color
.attr("stroke-width", 1); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#9f84b8") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle (adjust for flat top)
const bottomLeft = outerPoints[0];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY + 30) // Adjust for correct height (moved to bottom)
.attr("text-anchor", "middle")
.attr("fill", "#9f84b8") // My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Impact");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY + 80)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("1.9");
</script>
</body>
</html>

206
red.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
//.area {
// fill: rgba(215, 96, 35, 0.1); /* steelblue with transparency */
// stroke: rgba(215, 96, 35, 0.6);
// stroke-width: 2;
//}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Define axes with A at the top (rotate -90 degrees)
const axes = [
{ name: "Feature A", angle: 0 },
{ name: "Feature B", angle: 120 },
{ name: "Feature C", angle: 240 }
];
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [0.8, 0.4, 0.6];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "red") // #d76a23 with 30% opacity (translucent)
.attr("fill-opacity", 0.6)
.attr("stroke", "red") // Outer line color
.attr("stroke-width", 2); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#d76a23") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle
const bottomLeft = outerPoints[1];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY - 15) // Alter for correct height
.attr("text-anchor", "middle")
.attr("fill", "black") /// My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Approach");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY -60)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("-2.1");
// Add axis labels
/*
svg.selectAll(".label")
.data(axes)
.join("text")
.attr("class", "label")
.attr("x", d => center.x + (radius + 20) * Math.cos(d.angle))
.attr("y", (d,i) => {
if (i === 0) { //adjust for 1st access, rather than using d.name
return center.y + (radius + 20) * Math.sin(d.angle)
} else
return center.y + (radius + 20 + 30) * Math.sin(d.angle)
})
.text(d => d.name);
*/
</script>
</body>
</html>

206
roles.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3-Axis Radar Chart with Ticks</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
background-color: white;
}
svg {
background: white;
display: block;
margin: auto;
}
.axis line {
stroke: black;
stroke-width: 1.5px;
}
line.tick {
stroke: black;
stroke-width: 1;
}
polygon.grid {
fill: none;
stroke: rgba(200, 200, 200, 0.5); /* light grey with 50% opacity */
stroke-dasharray: 2,2;
}
//.area {
// fill: rgba(215, 96, 35, 0.1); /* steelblue with transparency */
// stroke: rgba(215, 96, 35, 0.6);
// stroke-width: 2;
//}
.label {
font-size: 12px;
font-weight: bold;
text-anchor: middle;
}
</style>
</head>
<body>
<svg width="500" height="500"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
const radius = 200;
const center = { x: width / 2, y: height / 2 };
// Define axes with A at the top (rotate -90 degrees)
const axes = [
{ name: "Feature A", angle: 0 },
{ name: "Feature B", angle: 120 },
{ name: "Feature C", angle: 240 }
];
axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180);
// Sample data: [0-1] scale
const values = [0.2, 0.4, 0.6];
// Draw axis lines
svg.append("g")
.attr("class", "axis")
.selectAll("line")
.data(axes)
.join("line")
.attr("x1", center.x)
.attr("y1", center.y)
.attr("x2", d => center.x + radius * Math.cos(d.angle))
.attr("y2", d => center.y + radius * Math.sin(d.angle));
// Draw grid rings (polygons)
const levels = 7;
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const points = axes.map(d => {
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
svg.append("polygon")
.attr("class", "grid")
.attr("points", points.map(p => p.join(",")).join(" "));
}
// Draw axis ticks
const tickLength = 5;
axes.forEach(axis => {
for (let i = 1; i <= levels; i++) {
const r = (radius / levels) * i;
const angle = axis.angle;
const x1 = center.x + r * Math.cos(angle);
const y1 = center.y + r * Math.sin(angle);
// Perpendicular tick
const perpAngle = angle + Math.PI / 2;
const x2 = x1 + tickLength * Math.cos(perpAngle);
const y2 = y1 + tickLength * Math.sin(perpAngle);
svg.append("line")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2)
.attr("class", "tick");
}
});
// Convert values to coordinates
const valuePoints = axes.map((d, i) => {
const r = radius * values[i];
return [
center.x + r * Math.cos(d.angle),
center.y + r * Math.sin(d.angle)
];
});
// Draw data area
svg.append("polygon")
.attr("class", "area")
.attr("points", valuePoints.map(p => p.join(",")).join(" "))
.attr("fill", "#316443") // #d76a23 with 30% opacity (translucent)
.attr("fill-opacity", 0.3)
.attr("stroke", "#316443") // Outer line color
.attr("stroke-width", 1); // Thin outer line
// Draw outer triangle border (goes to edge of chart)
const outerPoints = axes.map(d => [
center.x + radius * Math.cos(d.angle),
center.y + radius * Math.sin(d.angle)
]);
// Draw border separately (on top)
svg.append("polygon")
.attr("points", outerPoints.map(p => p.join(",")).join(" "))
.attr("fill","none")
.attr("stroke", "#316443") // Outer line color
.attr("stroke-width", 3); // Thin outer line
// Put label in bottom centre of triangle
const bottomLeft = outerPoints[1];
const bottomRight = outerPoints[2];
const midX = (bottomLeft[0] + bottomRight[0]) / 2;
const midY = (bottomLeft[1] + bottomRight[1]) / 2;
svg.append("text")
.attr("x", midX)
.attr("y", midY - 15) // Alter for correct height
.attr("text-anchor", "middle")
.attr("fill", "#316443") /// My Colour
.attr("font-size", "24px")
.attr("font-weight", "bold")
.text("Roles");
// And now a central number
svg.append("text")
.attr("x", midX)
.attr("y", midY -60)
.attr("text-anchor", "middle")
.attr("fill", "black") // 🎨 customize color
.attr("font-size", "22px")
.attr("font-weight", "bold")
.attr("font-family", "Courier New, monospace")
.text("1.1");
// Add axis labels
/*
svg.selectAll(".label")
.data(axes)
.join("text")
.attr("class", "label")
.attr("x", d => center.x + (radius + 20) * Math.cos(d.angle))
.attr("y", (d,i) => {
if (i === 0) { //adjust for 1st access, rather than using d.name
return center.y + (radius + 20) * Math.sin(d.angle)
} else
return center.y + (radius + 20 + 30) * Math.sin(d.angle)
})
.text(d => d.name);
*/
</script>
</body>
</html>