Panels and layout
A WellRenderer draws into one or more panels, each an <svg> element described by an SvgInstance:
type SvgInstance = {
selector: string; // CSS selector of the <svg>
width: number; // drawing width in px, without margins
height: number; // drawing height in px, without margins
margins: { top: number; right: number; bottom: number; left: number };
depthRange?: [number, number]; // depth window in m
repeatedTo?: number; // end of a band repeated from the previous panel, in m
};
The SVG element is sized to width + left + right by height + top + bottom. Keep about 40 to 50 px on the left for the depth scale.
One panel
With one panel and no depthRange, the whole well is drawn to fit the height. The depth scale is linear, so a 1561 m well and a 10 m well both fill the panel.
Several panels
Long wells drawn in one panel lose detail. Give several panels and, by default, draw() splits the depth between them in proportion to their heights, back to back:
const margins = { top: 24, right: 16, bottom: 20, left: 48 };
new WellRenderer([
{ selector: '#part-1', width: 380, height: 700, margins },
{ selector: '#part-2', width: 380, height: 700, margins },
{ selector: '#part-3', width: 380, height: 700, margins },
]);
Place the three SVGs side by side to read the well as columns, as on a printed profile.
Choosing depth windows
Give every panel a depthRange to choose the windows yourself. Panels may then overlap or skip depths:
new WellRenderer([
{ selector: '#p1', width: 480, height: 600, margins, depthRange: [0, 124] },
{
selector: '#p2',
width: 480,
height: 700,
margins,
depthRange: [116, 292],
repeatedTo: 124,
},
]);
repeatedTo marks the band [116, 124] of the second panel as a repetition of the end of the first. It is hatched and labelled using renderConfig.overlap.label ({range} becomes 116–124 m). This is how paged PDF output repeats a few meters at the top of each page.
Stick-up and the top of the drawing
Depth zero is the ground surface. A casing, screen or surface case with a negative from sticks up above it (depths and intervals), and the renderer draws it to scale above the wellhead pad. The default split therefore starts at the highest stick-up, not at 0. getProfileTopDepth(well) returns that depth, so you can start your first depthRange there:
import { getProfileTopDepth } from '@welldot/render';
const top = getProfileTopDepth(well); // e.g. -0.5
const ranges: [number, number][] = [
[top, 120],
[120, 265],
];
Responsive width
The renderer does not observe its container. To follow the page width, create a new renderer when the container resizes (debounced), as the live previews on this site do:
const observer = new ResizeObserver(() => {
clearTimeout(timer);
timer = setTimeout(redraw, 150);
});
observer.observe(container);
where redraw builds a WellRenderer with the container's clientWidth minus the margins, calls prepareSvg() and draws.
Column proportions
renderConfig.layout sets how much of the width the construction column takes (pocoWidthRatio) and where it sits (pocoCenterRatio); renderConfig.geologic sets the lithology column's insets. The two presets differ here: INTERACTIVE_RENDER_CONFIG is laid out for a screen, STATIC_RENDER_CONFIG leaves room on the right for description annotations, as in printed reports.