Radar <mv-radar>
用主题令牌绘制的 WebGL 雷达显示屏:波束从正北顺时针扫过虚线距离环和罗盘刻度,沿弧线拖开的回波在波束经过时亮起,并逐渐淡去直到下一圈,移动目标会留下航迹点和速度矢量,中心附近还有颗粒状的杂波。
工作原理
用主题令牌绘制的 WebGL 雷达显示屏:波束从正北顺时针扫过虚线距离环和罗盘刻度,沿弧线拖开的回波在波束经过时亮起,并逐渐淡去直到下一圈,移动目标会留下航迹点和速度矢量,中心附近还有颗粒状的杂波。指针带有距离环和方位线,并把波门锁定在其下方的目标上。应用可以绘制自己的目标,包括告警。适用于浅色和深色主题。
| 分类 | 背景 |
|---|---|
| 类型 | WebGL 元素(<mv-radar>) |
| 状态 | 稳定版 |
| 同时安装 | shader |
| Keywords | safe-rewrite, webgl, shader, radar, sweep, scope, monitoring, hud, tech, interactive |
When to use
- A monitoring, security or logistics hero wants a calm scanning scope behind the headline, in light or dark themes
- A status panel should plot a few real items (services, vehicles, sensors) by distance and direction, with alerts flagged
- A search or discovery screen needs a sense of scanning while results load
Avoid when
- Real places must be shown on a map; the scope only knows range and bearing → use World Map instead
- Concentric ripples over a grid are wanted without a rotating beam → use Ripple Grid instead
- The contacts are data that people must read; the canvas is decorative, so give the same data as text or a table
安装
node scripts/add.mjs radar --out ./src/marvelous使用 Marvelous UI MCP 服务器的 AI 智能体:install_components({ slugs: ["radar"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。
复制的文件(含依赖):tokens/tokens.css, core/base.css, core/canvas.js, core/dom.js, core/element.js, core/i18n.js, core/motion.js, core/observe.js, core/webgl.js, components/shader/shader.js, components/shader/shader.css, components/radar/radar.js, components/radar/radar.css。
用法
标准标记,可在此基础上通过属性、data-* 和 CSS 变量进行定制:
<div style="display:flex;flex-wrap:wrap;min-height:320px">
<section style="flex:1.6 1 22rem;position:relative;display:flex;align-items:center;overflow:hidden;padding:2rem 1.75rem;min-height:320px">
<mv-radar data-fill origin="0.74 0.5"></mv-radar>
<div style="position:relative;max-width:18rem">
<p style="margin:0;font:700 clamp(1.6rem,4vw,2.4rem)/1.1 var(--mv-font-sans);letter-spacing:-.03em">Nothing slips past</p>
<p style="margin:.6rem 0 1.2rem;color:var(--mv-fg-muted)">Every service, swept every six seconds. Point at a contact to lock on.</p>
<a class="mv-button" href="#radar">Start monitoring</a>
</div>
</section>
<section style="flex:1 1 14rem;position:relative;display:grid;place-items:end center;text-align:center;overflow:hidden;border-left:1px solid var(--mv-border);min-height:260px;padding:1rem">
<mv-radar data-fill origin="0.5 0.6" scale="0.78" rings="3" blips="0" clutter="0" targets="0.35 40, 0.62 128 1.4, 0.8 250 1 alert, 0.5 312"></mv-radar>
<div style="position:relative">
<strong style="display:block;font-size:.95rem">Your own contacts</strong>
<span style="font-size:.8rem;color:var(--mv-fg-muted)">targets="0.8 250 1 alert, …"</span>
</div>
</section>
</div>API
Attributes
| Name | 类型 | Default | Description |
|---|---|---|---|
color | CSS color | var(--mv-accent) | Accent of the beam, echoes, compass marker and pointer tools (tokens accepted, read again on theme change). |
background | CSS color | var(--mv-bg) | Paper color under the scope (tokens accepted). |
line-color | CSS color | var(--mv-fg) | Ink of the rings, spokes and compass scale, drawn at low opacity over the paper (tokens accepted). |
alert-color | CSS color | var(--mv-danger) | Color of contacts marked alert in targets (tokens accepted). |
rings | number | 4 | Number of range rings, the rim included (1 to 12). |
blips | number | 7 | Number of decorative contacts (0 to 12); about a third stay fixed, the others patrol. 0 keeps only targets. |
targets | string | Your own contacts, up to 8: "range bearing [strength] [alert]" separated by commas, e.g. "0.4 30, 0.8 250 1 alert". Range 0..1 of the scope, bearing in degrees clockwise from north, strength 0 to 2 (default 1). Also a JS property (array of { range, bearing, strength, alert }). | |
scale | number | 1 | Scope size relative to the element height. |
trail | number | 1 | Length of the beam's afterglow and how long echoes persist (0.1 to 3). |
clutter | number | 0.5 | Grainy returns around the center, 0 to 1 (0 turns them off). |
origin | x y | 0.5 0.5 | Scope center in 0..1 element coordinates (y pointing up), e.g. "0.7 0.5" to leave room for a headline. |
speed | number | 1 | Time multiplier (one turn takes 6 s at 1). |
paused | boolean | Freezes the animation on the current frame. | |
interactive | boolean | Pointer tools follow the pointer only over the element itself (otherwise across the window). | |
dpr | number | 1.5 | Max pixel density (capped at 2). |
data-fill | boolean | Fills the positioned parent (absolute, inset 0). |
Properties
| Name | 类型 | Description |
|---|---|---|
targets | Array<{ range, bearing, strength?, alert? }> | Reads or sets the app contacts; setting it rewrites the targets attribute. Values are clamped (range 0..1, strength 0..2) and only the first 8 are drawn. |
Events
| Name | Description |
|---|---|
mv-error | Inherited from <mv-shader>: the GLSL failed to compile. The element shows its still fallback scope. |
Content structure
| Name | Description |
|---|---|
children | Content placed inside the element sits above the scope. |
Accessibility
Decorative: the canvas is aria-hidden and never takes pointer events, so content placed above it stays clickable and in reading order. Contacts plotted with targets are not announced: give the same data as text (a list or table) when people need it. The loop stops off screen and in hidden tabs, and no WebGL context is created until the element nears the viewport. Reduced motion (OS or <html data-motion="reduce">) and paused keep a still frame with the beam to the north-east and the contacts painted. Without WebGL2 a still CSS scope is shown; forced colors and print hide the canvas. Keep headline text in the theme foreground, which the faint scope leaves readable; the beam passes behind it at low opacity.