Map Compass
terrae/compassFreeComponent
Interactive compass overlay with bearing display and click-to-reset.
Install it
npx shadcn@latest add https://www.terrae.dev/compass.jsonSource
1"use client"23import { useEffect, useRef, useState } from "react"4import { cn } from "@/lib/utils"5import { useMap } from "./hooks"67type MapControlPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right"8type MapCompassSize = "sm" | "md" | "lg" | "xl"910type MapCompassProps = {11 size?: MapCompassSize | number12 position?: MapControlPosition13 showCardinals?: boolean14 showRing?: boolean15 showBearing?: boolean16 autoRotate?: boolean17 autoRotateSpeed?: number18 className?: string19}2021const DEFAULT_SIZE: MapCompassSize = "md"22const DEFAULT_POSITION: MapControlPosition = "top-right"23const DEFAULT_SHOW_CARDINALS = true24const DEFAULT_SHOW_RING = true25const DEFAULT_SHOW_BEARING = false26const DEFAULT_AUTO_ROTATE = false27const DEFAULT_AUTO_ROTATE_SPEED = 22829const SIZE_MAP: Record<MapCompassSize, number> = {30 sm: 48,31 md: 64,32 lg: 80,33 xl: 96,34}3536const POSITION_CLASSES: Record<MapControlPosition, string> = {37 "top-left": "top-2 left-2",38 "top-right": "top-2 right-2",39 "bottom-left": "bottom-2 left-2",40 "bottom-right": "bottom-10 right-2",41}4243const resolveSize = (size: MapCompassSize | number): number => {44 if (typeof size === "number") {45 return size46 }47 return SIZE_MAP[size]48}4950const CompassRing = () => {51 const majorAngles = [0, 45, 90, 135, 180, 225, 270, 315]52 const minorAngles = [15, 30, 60, 75, 105, 120, 150, 165, 195, 210, 240, 255, 285, 300, 330, 345]5354 const createTick = (angle: number, isMajor: boolean) => {55 const rad = (angle * Math.PI) / 18056 const innerRadius = isMajor ? 40 : 4257 const outerRadius = 4658 const x1 = 50 + innerRadius * Math.sin(rad)59 const y1 = 50 - innerRadius * Math.cos(rad)60 const x2 = 50 + outerRadius * Math.sin(rad)61 const y2 = 50 - outerRadius * Math.cos(rad)6263 return (64 <line key={angle} x1={x1} y1={y1} x2={x2} y2={y2} className="stroke-border" strokeWidth={isMajor ? 1.5 : 0.75} />65 )66 }6768 return (69 <g>70 <circle cx="50" cy="50" r="46" fill="none" className="stroke-border" strokeWidth="1" />71 {majorAngles.map((angle) => {72 return createTick(angle, true)73 })}74 {minorAngles.map((angle) => {75 return createTick(angle, false)76 })}77 </g>78 )79}8081const CompassRose = () => {82 return (83 <g>84 <path d="M50 14 L56 50 L50 46 Z" className="fill-red-500" />85 <path d="M50 14 L44 50 L50 46 Z" className="fill-red-400" />8687 <path d="M50 86 L56 50 L50 54 Z" className="fill-muted-foreground/50" />88// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from terrae
All 40 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Map Animated Circleanimated-circle | terrae | Components | Free | 1 dep | |
| Map Animated Footprintanimated-footprint | terrae | Components | Free | 2 deps | |
| Map Animated Polygonanimated-polygon | terrae | Components | Free | 1 dep | |
| Map Animated Pulseanimated-pulse | terrae | Components | Free | 1 dep | |
| Map Arc Animatedarc-animated | terrae | Components | Free | 1 dep | |
| Map Blur Areablur-area | terrae | Components | Free | 1 dep | |
| Map Camera Followcamera-follow | terrae | Components | Free | 1 dep | |
| Map Choroplethchoropleth | terrae | Components | Free | 1 dep |
