Finish virtual profile

This commit is contained in:
Fuhrmann 2025-03-17 13:54:02 +01:00
parent 46db218492
commit 913af8fba6
3 changed files with 298 additions and 132 deletions

View file

@ -2,9 +2,10 @@ import * as d3 from "d3";
import { Extent } from "./build-scene";
// SVG dimensions
const margin = { top: 20, right: 250, bottom: 20, left: 20 };
const margin = { top: 20, right: 20, bottom: 20, left: 80 };
const barWidth = 30;
interface Data {
export interface Data {
depthStart: number;
depthEnd: number;
name: string;
@ -17,7 +18,6 @@ export function createSVG(
height: number = 800,
extent: Extent
) {
console.log(data);
const svg = d3
.create("svg")
.attr("width", width)
@ -27,34 +27,110 @@ export function createSVG(
// Scales: Invert Y-axis so depth increases downward
const zmax = d3.max(data, (d) => d.depthStart) ?? extent.zmax;
const zmin = d3.max(data, (d) => d.depthEnd) ?? extent.zmin;
const zmin = d3.min(data, (d) => d.depthEnd) ?? extent.zmin;
const zScale = d3
.scaleLinear()
.domain([zmax, zmin])
.range([margin.top, height - margin.bottom]);
// Create logical group
const barGroup = svg.append("g");
// Draw bars (formations)
svg
.append("g")
.selectAll()
barGroup
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", margin.left)
.attr("y", (d) => zScale(d.depthStart))
.attr("height", (d) => zScale(d.depthEnd) - zScale(d.depthStart))
.attr("width", width - margin.left - margin.right)
.attr("width", barWidth)
.attr("fill", (d) => d.color);
// Add labels (formation names)
svg
.selectAll(".label")
barGroup
.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.attr("x", width - margin.right + 5) // Place text slightly outside the bar
.attr("y", (d) => (zScale(d.depthStart) + zScale(d.depthEnd)) / 2) // Center in the bar
.text((d) => d.name);
.join("text")
.attr("x", margin.left + barWidth + 5)
.attr("y", (d) => (zScale(d.depthStart) + zScale(d.depthEnd)) / 2)
.attr("text-anchor", "start")
.attr("fill", "black")
.style("font-size", "12px")
.each(function (d) {
const textElement = d3.select(this);
textElement.selectAll("tspan").remove(); // Clear previous tspans
const groups = groupWordsByFour(d.name);
let dy = 0;
for (const group of groups) {
textElement
.append("tspan")
.attr("x", margin.left + barWidth + 5)
.attr("dy", dy)
.text(group.join(" "));
dy = 14;
}
});
// Add depth labels
svg
.append("g")
.selectAll("text")
.data(data)
.join("text")
.attr("x", margin.left - 5)
.attr("y", (d) =>
d.depthStart - d.depthEnd < 100
? zScale(d.depthStart) - 10
: zScale(d.depthStart)
)
.attr("dy", "0.35em")
.attr("text-anchor", "end")
.attr("fill", "black")
.style("font-size", "12px")
.text((d) => `${d.depthStart.toFixed(0)}m`);
// Add label for last depth
svg
.append("g")
.selectAll("text")
.data(data)
.join("text")
.attr("x", margin.left - 5)
.attr("y", (d, i) => (i === data.length - 1 ? zScale(d.depthEnd) : null))
.attr("dy", "0.35em")
.attr("text-anchor", "end")
.attr("fill", "black")
.style("font-size", "12px")
.text((d, i) => (i === data.length - 1 ? `${d.depthEnd.toFixed(0)}m` : ""));
return svg.node();
}
// Group words to split lines if necessary
function groupWordsByFour(inputString: string) {
const words = inputString.split(" ");
// Use reduce to group the words into chunks of four
const groups = words.reduce(
(result: string[][], word: string, index: number) => {
const groupIndex = Math.floor(index / 4);
// If the group doesn't exist yet, create an empty array for it
if (!result[groupIndex]) {
result[groupIndex] = [];
}
// Add the current word to the correct group
result[groupIndex].push(word);
return result;
},
[]
);
return groups;
}