I am trying to create the shape of the image using d3js (if it’s any simpler way, please let me know)
I tried doing it but I don’t get it right, I don’t get the end and start position quite well, i tried adding numbers manually until it kinda looks good, and also i want to remove the gapangle, I think is useless:
This is the code that I used for getting the shape till now:
document.addEventListener("DOMContentLoaded", () => {
const width = 1000; // Canvas width
const height = 1000; // Canvas height
const innerOuterRadius = 280; // Outer radius of the inner segments
const outerInnerRadius = 295; // Inner radius of the outer segments
const segmentColor = "#265152"; // Color for the segments
const lineColor = "#FF0000"; // Color for the connecting lines
const gapAngle = 0.05; // Gap between segments (in radians)
const inclinationAngle = 0.06; // Small inclination for connectors (in radians)
// Segment sizes (in degrees)
const innerSegmentSizes = [133, 133]; // Inner segments
const outerSegmentSizes = [40, 40]; // Outer segments to fill gaps
// Convert degrees to radians
const innerSegmentSizesRadians = innerSegmentSizes.map((deg) => (deg * Math.PI) / 180);
const outerSegmentSizesRadians = outerSegmentSizes.map((deg) => (deg * Math.PI) / 180);
// Create the SVG canvas
const svg = d3
.select("#c4")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2})`);
// Function to calculate polar coordinates
const polarToCartesian = (radius, angle) => ({
x: radius * Math.cos(angle),
y: radius * Math.sin(angle),
});
// Draw inner segments (large, positioned symmetrically)
innerSegmentSizesRadians.forEach((segmentAngle, index) => {
const startAngle = index === 0 ? 0 : Math.PI; // Opposite sides
const endAngle = startAngle + segmentAngle;
const arc = d3
.arc()
.innerRadius(innerOuterRadius - 3)
.outerRadius(innerOuterRadius)
.startAngle(startAngle)
.endAngle(endAngle);
svg.append("path")
.attr("d", arc)
.attr("fill", segmentColor);
});
// Draw outer segments to fill spaces between inner segments
outerSegmentSizesRadians.forEach((segmentAngle, index) => {
const startAngle = index === 0
? innerSegmentSizesRadians[0] + gapAngle
: innerSegmentSizesRadians[0] + Math.PI + gapAngle;
const endAngle = startAngle + segmentAngle;
const arc = d3
.arc()
.innerRadius(outerInnerRadius)
.outerRadius(outerInnerRadius + 3)
.startAngle(startAngle)
.endAngle(endAngle);
svg.append("path")
.attr("d", arc)
.attr("fill", segmentColor);
});
// Add connecting lines between the start and end of inner segments
innerSegmentSizesRadians.forEach((segmentAngle, index) => {
const startAngle = index === 0
? innerSegmentSizesRadians[0] + gapAngle + 1.517
: innerSegmentSizesRadians[0] + Math.PI + 1.567; // Start of the inner segment
const endAngle = startAngle + segmentAngle * 0.357; // End of the inner segment
// Calculate the start and end points for the red lines
const pointsToConnect = [
{ angle: startAngle }, // Start of the segment
{ angle: endAngle }, // End of the segment
];
pointsToConnect.forEach(({ angle }) => {
const innerPoint = polarToCartesian(innerOuterRadius, angle);
// Shift the outer angle slightly to incline the connector
const inclinedOuterAngle = angle + (index === 0 ? -inclinationAngle : inclinationAngle);
const outerPoint = polarToCartesian(outerInnerRadius, inclinedOuterAngle);
svg.append("line")
.attr("x1", innerPoint.x)
.attr("y1", innerPoint.y)
.attr("x2", outerPoint.x)
.attr("y2", outerPoint.y)
.attr("stroke", lineColor)
.attr("stroke-width", 2);
});
});
});