Nautical chart
A nautical chart with the server's geometry underneath and a React layer drawn over it.
On this page
Code
import { NauticalChart } from "@bosunkit/components/nautical-chart";
import type { ReactElement } from "react";
import harbor from "./harbor.svg?raw";
export const description: string =
"A harbor approach from the chart renderer, with the vessel, her track and an AIS target drawn over it.";
export default function WithGeometry(): ReactElement {
return (
<div style={{ width: "100%", maxWidth: 720 }}>
<NauticalChart staticSvg={harbor} width={800} height={600}>
{/* The track the vessel has made good, oldest first. */}
<polyline
points="474,600 470,560 464,520 458,486 455,452"
fill="none"
stroke="var(--accent)"
strokeWidth={2}
strokeDasharray="4 4"
opacity={0.7}
/>
{/* An AIS target leaving harbor, with its course vector. */}
<g transform="translate(438 196) rotate(170)">
<line x1={0} x2={0} y1={-8} y2={-48} stroke="var(--amber)" strokeWidth={1.5} />
<path d="M 0 -8 L 5 7 L 0 4 L -5 7 Z" fill="var(--amber)" stroke="var(--bg)" />
</g>
{/* Own vessel inbound on the channel: hull on heading, six-minute course vector. */}
<g transform="translate(455 452) rotate(352)">
<line x1={0} x2={0} y1={-12} y2={-84} stroke="var(--accent)" strokeWidth={2} />
<path d="M 0 -12 L 7 10 L 0 6 L -7 10 Z" fill="var(--accent)" stroke="var(--bg)" />
</g>
</NauticalChart>
</div>
);
}
A chart is an SVG in two layers. The static layer holds the geometry the server renders and the chart inserts as raw
markup. The dynamic layer holds the React children, such as the vessel, AIS targets and the track, which change as
the data does. Both share one viewBox, so the chart scales to the width of its container and keeps its proportions.
On a screen whose height is known, a phone on its side among them, the chart is never taller than the screen.
The chart is announced to assistive technology as an image with a translated label.
The hero's geometry is the chart renderer's own output for a fixed harbor scene, written by a test in
packages/bosun/ui/chartsvg that fails when the renderer and the file part. The vessel, her track and the AIS target
are the React layer.
Examples
Without geometry
When the server has no geometry for the area, staticSvg is null and the overlay says so.
Code
import { NauticalChart } from "@bosunkit/components/nautical-chart";
import type { ReactElement } from "react";
export const description: string = "A chart with no geometry for the area shows a message drawn by the overlay.";
export default function WithoutGeometry(): ReactElement {
return (
<div style={{ width: "100%", maxWidth: 720 }}>
<NauticalChart staticSvg={null} width={800} height={600}>
<text
x={400}
y={300}
textAnchor="middle"
fill="var(--text-dim)"
fontFamily="var(--font-mono)"
fontSize="14"
opacity="0.5"
>
No chart data for this area
</text>
</NauticalChart>
</div>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| staticSvgrequired | string | null | – | Server-rendered SVG geometry, inserted as raw HTML (safe — server-generated). |
| width | number | undefined | 800 | SVG viewBox width (default 800). |
| height | number | undefined | 600 | SVG viewBox height (default 600). |
| children | ReactNode | – | Dynamic overlay components rendered as SVG children (vessel, AIS, track). |
| className | string | undefined | – | Optional additional CSS class. |
Related
- Data visualization: the rules for drawing readings on a chart.
- Color: the colors the overlay draws in.