fix(skewt): clip grid + traces to the plot box

Skewed isotherms, dry adiabats, and mixing-ratio lines were drifting
outside the frame at the corners — most visibly the warm-side
isotherms exiting the right edge near the top of the diagram. The
existing `clip_polyline/1` only filtered with a ±200 px slack, so
segments crossing the boundary still drew past the frame.

Wrap every grid layer + the T/Td/parcel polylines in a
`<g clip-path="url(#skewt-plot-clip)">`. The clipPath defines a
rectangle from (left, top) to (right, bottom). Frame outline and
axis labels stay outside the clip group so they keep rendering at
the box edge unchanged. The hover-cursor crosshair also lives
outside the clip so its readout box can sit flush against the plot
corner without being trimmed.

mix test: 2,902 / 2,902 + 221 properties green. mix credo --strict
clean.
This commit is contained in:
Graham McIntire 2026-04-25 13:30:23 -05:00
parent e255fcf3b6
commit b34b186e61
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59

View file

@ -43,18 +43,29 @@ defmodule MicrowavepropWeb.SkewtSvg do
cleaned = clean_profile(profile)
parcel = Keyword.get(opts, :parcel_trace, [])
plot_w = @right - @left
plot_h = @bottom - @top
[
~s|<svg viewBox="0 0 #{@width} #{@height}" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="Skew-T-Log-P diagram">|,
style_block(),
# Define a rectangular clip the plot interior shares so any
# grid/trace polyline whose vertices stretch past the frame
# (e.g. skewed isotherms exiting the right edge near the top)
# is visually cropped. The frame and axis labels live *outside*
# this group, so the box outline still reads clean.
~s|<clipPath id="skewt-plot-clip"><rect x="#{@left}" y="#{@top}" width="#{plot_w}" height="#{plot_h}"/></clipPath>|,
~s|<g clip-path="url(#skewt-plot-clip)">|,
isobars(),
isotherms(),
dry_adiabats(),
moist_adiabats(),
mixing_ratio_lines(),
frame(),
axis_labels(),
profile_traces(cleaned),
parcel_trace_line(parcel),
"</g>",
frame(),
axis_labels(),
cursor_layer(),
"</svg>"
]