Public
Edited
Aug 3, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
hoydeTopp = topph / Math.cos(degreesToRadians(helling))
Insert cell
hoydeStein = steinh / Math.cos(degreesToRadians(helling))
Insert cell
totHoyde = hoydeTopp + 3 * hoydeStein
Insert cell
Insert cell
kuttStein = steinh * Math.tan(degreesToRadians(helling))
Insert cell
kuttTopp = topph * Math.tan(degreesToRadians(helling))
Insert cell
hoydeX = (lenx, numbricks) => {
//Math.tan(16) = h / lenx
return (
lenx * Math.tan(degreesToRadians(helling)) +
(10 + 20 * numbricks) / Math.cos(degreesToRadians(helling))
);
}
Insert cell
Insert cell
helling = 16
Insert cell
shiftSecondRow = 15
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
chart = {
const xDomain = [-400, 40];
const yDomain = [-140, 10];
const aRatio = (xDomain[1] - xDomain[0]) / (yDomain[1] - yDomain[0]);
const height = width / aRatio;

const xScale = d3
.scaleLinear()
.domain(xDomain) // unit: cm
.range([0, width]); // unit: pixels
const yScale = d3
.scaleLinear()
.domain(yDomain) // unit: cm
.range([height, 0]); // unit: pixels
const wScale = (d) => xScale(d) - xScale(0);
const hScale = (d) => yScale(0) - yScale(d);
//return [xScale(0), yScale(0)];

const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto;");

let terrainPath = terrainMeasurement
.map(
(d, i) =>
(i == 0 ? "M" : "L") +
" " +
xScale(d[0]).toPrecision(5) +
" " +
yScale(d[1]).toPrecision(5)
)
.join(" ");
svg
.append("line")
.attr("x1", xScale(0))
.attr("y1", yScale(0))
.attr("x2", xScale(0))
.attr("y2", yScale(-90))
.attr("stroke", "red");

svg
.append("path")
.attr("d", terrainPath)
.attr("stroke", "brown")
.attr("fill", "none");

let helpLines = [
[95, 3],
[200, 2],
[295, 2],
[365, 1]
].map((d) => ({
x1: xScale(-d[0]),
y1: yScale(0),
x2: xScale(-d[0]),
y2: yScale(-hoydeX(d[0], d[1])),
h: hoydeX(d[0], d[1]),
lengx: d[0],
numbricks: d[1]
}));
//return helpLines;
let hg = svg.selectAll("g.hl").data(helpLines).join("g").attr("class", "hl");
hg.append("line")
.attr("x1", (d) => d.x1)
.attr("y1", (d) => d.y1)
.attr("x2", (d) => d.x2)
.attr("y2", (d) => d.y2)
.attr("stroke", "blue");
hg.append("text")
.attr("x", (d) => d.x1 + 10)
.attr("y", (d) => d.y1)
.attr("font-size", "10")
.attr("font-family", "sans-serif")
.attr("fill", "#777")f
.text((d) => "w: " + d.lengx + " cm");
hg.append("text")
.attr("x", (d) => d.x1 + 10)
.attr("y", (d) => d.y1 + 10)
.attr("font-size", "10")
.attr("font-family", "sans-serif")
.attr("fill", "#777")
.text((d) => "h: " + d.h.toFixed(0) + " cm");

let bSvg = svg.append("g").attr(
"transform",
`rotate(-${helling} ${xScale(0)} ${yScale(0)})`
// `rotate(-${helling} ${xScale(0)} ${yScale(0)}) translate(${xScale(0)} ${yScale(0)})`
);

bSvg
.selectAll("rect")
.data(blocks)
.join("rect")
.attr("x", (d) => xScale(d.x))
.attr("y", (d) => yScale(d.y))
.attr("width", (d) => wScale(d.width))
.attr("height", (d) => hScale(d.height))
.attr("fill", "#f8e9c7")
.attr("opacity", 0.7)
.attr("stroke", "#000000");

bSvg
.selectAll("text.l1")
.data(blocks)
.join("text")
.attr("class", "l1")
.attr("x", (d) => xScale(d.x) + wScale(d.width) / 2)
.attr("y", (d) => yScale(d.y) + wScale(d.height) / 2)
.attr("font-size", "10")
.attr("font-family", "sans-serif")
.attr("fill", "#227799")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.text((d) => d.label);

bSvg
.selectAll("line")
.data(blocksCut)
.join("line")

.attr("x1", (d) => xScale(d.x + d.cut)) // + d.cut
.attr("y1", (d) => yScale(d.y) + hScale(d.height))
.attr("x2", (d) =>
xScale(d.x + d.cut + d.height * Math.tan(degreesToRadians(helling)))
)
.attr("y2", (d) => yScale(d.y))
.attr("stroke", "red")
.attr("stroke-dasharray", "5,5");

bSvg
.selectAll("text.l2")
.data(blocksCut)
.join("text")
.attr("class", "l2")
.attr("x", (d) => xScale(d.x) + 2)
.attr("y", (d) => yScale(d.y) + (7 * wScale(d.height)) / 8)
.attr("font-size", "8")
.attr("font-family", "sans-serif")
.attr("fill", "#227799")
.attr("text-anchor", "left")
.attr("dominant-baseline", "middle")
.text((d) => d.label2);

svg
.append("circle")
.attr("cx", xScale(0))
.attr("cy", yScale(0))
.attr("r", 3)
.attr("stroke", "red");

return svg.node();
}
Insert cell
terrainMeasurement = [
[-0, -63],
[-20, -70],
[-100, -82],
[-130, -91],
[-250, -114],
[-400, -119]
]
Insert cell
topp = (x, y) => ({
xi: x,
yi: y,
width: 45,
height: 10,
x: -x * 45 - 45,
y: 0
})
Insert cell
blokk = (x, y) => ({
width: 45,
height: 20,
x: -x * 45 + (y % 2 == 1 ? shiftSecondRow : shiftSecondRow - 22.5) - 45,
y: -10 - (y - 1) * 20
})
Insert cell
blocksCut = blocks.filter((d) => d.cut)
Insert cell
blocks = {
let b = [];
b = b.concat(_.range(0, 9).map((x) => topp(x, 0)));
b = b.concat(_.range(0, 9).map((x) => blokk(x, 1)));
b = b.concat(_.range(0, 7).map((x) => blokk(x, 2)));
b = b.concat(_.range(0, 3).map((x) => blokk(x, 3)));

b.forEach((d, i) => {
if (d.height == 20) {
d.label = b.length - i;
} else {
d.label = "T " + (d.xi + 1);
}
});
const getBlockByLabel = (label) => {
for (let i in b) {
if (b[i].label === label) {
return b[i];
}
}
return null;
};

[
{ label: 19, cut: 21.4 },
{ label: 10, cut: 38.2 },
{ label: 3, cut: 10.0 }
].map((d) => {
let block = getBlockByLabel(d.label);
block.cut = d.cut;
block.label2 =
"cut " +
block.cut.toPrecision(3) +
" " +
(
block.cut +
block.height * Math.tan(degreesToRadians(helling))
).toPrecision(3);
});
return b;
}
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more