Pitch
The pitch (trim) of the vessel in degrees on a side arc, with an average band and caution zones.
On this page
Code
import { ObcPitchType, Pitch, Priority, VesselImage } from "@bosunkit/instruments";
import { useEffect, useState, type CSSProperties, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"Motoring into a head sea on a live feed: the bow lifts and drops past the 8 degree caution threshold, the band " +
"of the last ten seconds follows, and three views show it on both arcs, zoomed onto a narrow arc, and as a number.";
const SAMPLE_SECONDS: number = 0.5;
const TREND_SECONDS: number = 10;
const CAUTION_DEGREES: number = 8;
const PANEL: CSSProperties = {
display: "flex",
flexWrap: "wrap",
alignItems: "flex-end",
justifyContent: "center",
gap: 24,
width: "100%",
maxWidth: 660,
};
const FIGURE: CSSProperties = { display: "flex", flexDirection: "column", alignItems: "center", gap: 6, margin: 0 };
const CAPTION: CSSProperties = { fontSize: 13, color: "var(--text-dim)", textAlign: "center", maxWidth: 200 };
/** Pitch in degrees at a time in seconds, positive bow up: the head sea's period under a building envelope. */
function pitchAt(time: number): number {
const envelope: number = 0.75 + 0.35 * Math.sin(time / 11);
return -1 + envelope * (7 * Math.sin((2 * Math.PI * time) / 5.5) + 2 * Math.sin((2 * Math.PI * time) / 3.1));
}
/** The lowest and highest pitch over the trend window ending at `time`. */
function bandAt(time: number): { low: number; high: number } {
let low: number = Number.POSITIVE_INFINITY;
let high: number = Number.NEGATIVE_INFINITY;
for (let past: number = 0; past <= TREND_SECONDS; past += SAMPLE_SECONDS) {
const value: number = pitchAt(time - past);
low = Math.min(low, value);
high = Math.max(high, value);
}
return { low, high };
}
export default function Showcase(): ReactElement {
const [sample, setSample]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
useEffect((): (() => void) => {
const interval: number = window.setInterval((): void => {
setSample((previous: number): number => previous + 1);
}, SAMPLE_SECONDS * 1000);
return (): void => {
window.clearInterval(interval);
};
}, []);
const time: number = sample * SAMPLE_SECONDS;
const pitch: number = pitchAt(time);
const { low, high }: { low: number; high: number } = bandAt(time);
const beyondCaution: boolean = Math.max(Math.abs(low), Math.abs(high)) > CAUTION_DEGREES;
return (
<div style={PANEL}>
<figure style={FIGURE}>
<div style={{ width: 260, height: 260 }}>
<Pitch
pitch={pitch}
minAvgPitch={low}
maxAvgPitch={high}
vesselImageSide={VesselImage.genericSide}
maxPitchAdvice={CAUTION_DEGREES}
triggerPitchAdvice={beyondCaution}
type={ObcPitchType.dualScale}
priority={Priority.enhanced}
/>
</div>
<figcaption style={CAPTION}>Both arcs, the vessel and the ten-second band</figcaption>
</figure>
<figure style={FIGURE}>
<div style={{ width: 170, height: 170 }}>
<Pitch
pitch={pitch}
minAvgPitch={low}
maxAvgPitch={high}
vesselImageSide={VesselImage.genericSide}
maxPitchAdvice={CAUTION_DEGREES}
triggerPitchAdvice={beyondCaution}
arcAngle={20}
zoomToFitArc
/>
</div>
<figcaption style={CAPTION}>A 40 degree arc, zoomed to fill the box</figcaption>
</figure>
<figure style={FIGURE}>
<div style={{ width: 150, height: 150 }}>
<Pitch
pitch={pitch}
minAvgPitch={low}
maxAvgPitch={high}
maxPitchAdvice={CAUTION_DEGREES}
triggerPitchAdvice={beyondCaution}
hasReadout
label="Pitch"
unit="DEG"
fractionDigits={1}
priority={Priority.enhanced}
/>
</div>
<figcaption style={CAPTION}>The same pitch as a number</figcaption>
</figure>
</div>
);
}
The pitch instrument shows the vessel's trim in degrees on an arc at the right, positive when the bow is up. A vessel
silhouette and an indicator line turn with the value, a band marks the recent average, and caution zones start at the
threshold the crew sets. It ports obc-pitch, which shares the single-axis inclinometer with
Roll; the overview lists the other instruments.
Examples
Pitch
Code
import { Pitch } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string = "A trim of 4 degrees bow down, with the indicator turned to match.";
export default function PitchExample(): ReactElement {
return (
<div style={{ width: 200, height: 200 }}>
<Pitch pitch={-4} />
</div>
);
}
Bow-up convention and limits
Pitch is positive when the bow rises. Align the sensor's sign and reference before rendering, and label the window used for the recent-average band. The band is a summary of supplied observations, not a predicted motion.
Choose caution thresholds for the equipment and task. The visual zone does not configure an alert service. Keep a numeric angle and source-quality indication available, including when the silhouette reaches the edge of its useful visual range.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| pitch | number | undefined | 0 | Pitch (trim) angle in degrees; positive pitches bow-up. |
| minAvgPitch | number | undefined | 0 | Lower edge of the average-pitch band, degrees. |
| maxAvgPitch | number | undefined | 0 | Upper edge of the average-pitch band, degrees. |
| vesselImageSide | VesselImage | undefined | VesselImage.psvSide | Side-view vessel silhouette pitching with the value. |
| maxPitchAdvice | number | undefined | – | Inner caution threshold in degrees; undefined hides the caution bands. |
| triggerPitchAdvice | boolean | undefined | false | Whether the caution bands are in the triggered state. |
| label | string | undefined | "Pitch" | Readout label. Default Pitch. |
| unit | string | undefined | "DEG" | Readout unit. Default DEG. |
| fractionDigits | number | undefined | 0 | Number of fraction digits shown in the readout. Default 0. |
| type | ObcPitchType | undefined | ObcPitchType.singleScale | single-scale shows one arc on the right (default); dual-scale also
shows the scale on the opposite (left) arc. |
| zoomToFitArc | boolean | undefined | false | Enlarges the visible arc to fill the container; the vessel and the indicator keep their natural size. Default
false. |
| hasReadout | boolean | undefined | false | Center readout instead of the horizon/indicator/vessel. |
| priority | Priority | undefined | Priority.regular | Color priority: regular (gray palette, default) or enhanced (blue palette) for the scale fill, the indicator
and the readout value. |
| arcAngle | number | undefined | 45 | Half-extent of the watch arc in degrees (default 45). |
| className | string | undefined | – | Class names added to the instrument's root element. |
Related
- Roll: the same instrument for heel.
- Single-axis inclinometer: the shared renderer.
- Heave: the vertical motion.