130 lines
2.9 KiB
Svelte
130 lines
2.9 KiB
Svelte
<script lang="ts">
|
|
const originPoint = -90;
|
|
const WIND_DIRS = {
|
|
N: originPoint,
|
|
NNE: originPoint + 45 / 2,
|
|
NE: originPoint + 45,
|
|
ENE: originPoint + 45 + 45 / 2,
|
|
E: originPoint + 90,
|
|
ESE: originPoint + 90 + 45 / 2,
|
|
SE: originPoint + 90 + 45,
|
|
SSE: originPoint + 90 + 45 + 45 / 2,
|
|
S: originPoint + 180,
|
|
SSW: originPoint + 180 + 45 / 2,
|
|
SW: originPoint + 180 + 45,
|
|
WSW: originPoint + 180 + 45 + 45 / 2,
|
|
W: originPoint - 90,
|
|
WNW: originPoint - (90 - 45 / 2),
|
|
NW: originPoint - (90 - 45),
|
|
NNW: originPoint - (90 - 45 - 45 / 2),
|
|
};
|
|
|
|
function calcPos(dir: string) {
|
|
const pad = 16;
|
|
const rem = 192 - pad;
|
|
const offset = pad * 0.4;
|
|
const angle = WIND_DIRS[dir];
|
|
const x = Math.cos(angle * (Math.PI / 180)) * (rem / 2) + rem / 2 + offset;
|
|
const y = Math.sin(angle * (Math.PI / 180)) * (rem / 2) + rem / 2 + offset;
|
|
return `translate(${x}px, ${y}px)`;
|
|
}
|
|
|
|
export let direction: string = 'N';
|
|
</script>
|
|
|
|
<div class="wind-radial-wrapper">
|
|
<div class="wind-radial-cardinals">
|
|
{#each Object.keys(WIND_DIRS) as dir}
|
|
<span
|
|
class="wind-cardinal wind-cardinal--{dir.toLowerCase()}"
|
|
style={`--pos: ${calcPos(dir)}`}>{dir}</span
|
|
>
|
|
{/each}
|
|
</div>
|
|
<div class="wind-radial">
|
|
<div
|
|
class="wind-direction"
|
|
style={`--angle: ${WIND_DIRS[direction || 'N']}deg`}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.wind {
|
|
&-radial {
|
|
position: relative;
|
|
width: 8rem;
|
|
height: 8rem;
|
|
|
|
&-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 12rem;
|
|
height: 12rem;
|
|
}
|
|
|
|
&-cardinals {
|
|
position: absolute;
|
|
width: 12rem;
|
|
height: 12rem;
|
|
}
|
|
}
|
|
&-direction {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: rotate(var(--angle));
|
|
|
|
&::before {
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
width: 0;
|
|
height: 0;
|
|
border-top: 10px solid transparent;
|
|
border-bottom: 10px solid transparent;
|
|
border-right: 10px solid #fff;
|
|
left: -5px;
|
|
top: -10px;
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
border-right: 10px solid #000;
|
|
}
|
|
}
|
|
|
|
&::after {
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
background-color: #fff;
|
|
width: 4rem;
|
|
height: 4px;
|
|
top: -2px;
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
background-color: #000;
|
|
}
|
|
}
|
|
}
|
|
|
|
&-cardinal {
|
|
position: absolute;
|
|
width: 8px;
|
|
height: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transform: var(--pos);
|
|
transform-origin: center center;
|
|
user-select: none;
|
|
|
|
&:nth-child(2n) {
|
|
color: rgb(184, 184, 184);
|
|
}
|
|
}
|
|
}
|
|
</style>
|