style(pfd): align core instrument visuals with Airbus reference

This commit is contained in:
itsrubberduck
2026-02-21 00:10:37 +01:00
parent 06f277e3ee
commit 719f4efad3
5 changed files with 88 additions and 53 deletions

View File

@@ -40,6 +40,10 @@ const readoutText = computed(() => Math.round(props.altitude).toString())
const readoutBoxHeight = 24
const readoutBoxWidth = computed(() => props.width - 8)
const tapeInnerX = 2
const tapeInnerY = 2
const tapeInnerWidth = computed(() => props.width - 4)
const tapeInnerHeight = computed(() => props.height - 4)
</script>
<template>
@@ -55,14 +59,23 @@ const readoutBoxWidth = computed(() => props.width - 8)
</clipPath>
</defs>
<!-- Background -->
<!-- Airbus-style tape body -->
<rect
x="0"
y="0"
:width="width"
:height="height"
fill="rgba(10,10,30,0.95)"
rx="2"
fill="#8f9198"
rx="1"
/>
<rect
:x="tapeInnerX"
:y="tapeInnerY"
:width="tapeInnerWidth"
:height="tapeInnerHeight"
fill="#93959c"
stroke="#d2d4da"
stroke-width="0.8"
/>
<!-- Scrolling tape (clipped) -->
@@ -70,24 +83,24 @@ const readoutBoxWidth = computed(() => props.width - 8)
<g v-for="mark in marks" :key="mark.alt">
<!-- Tick mark -->
<line
x1="0"
:x1="width - 10"
:y1="mark.y"
x2="8"
:x2="width - 1"
:y2="mark.y"
stroke="white"
stroke="#f4f6fb"
stroke-width="1"
/>
<!-- Label -->
<text
v-if="mark.isLabel"
x="12"
x="4"
:y="mark.y + 4"
fill="white"
fill="#f4f6fb"
font-size="12"
text-anchor="start"
font-family="monospace"
>
{{ mark.alt }}
{{ Math.round(mark.alt / 100) }}
</text>
</g>
</g>
@@ -98,15 +111,15 @@ const readoutBoxWidth = computed(() => props.width - 8)
:y="centerY - readoutBoxHeight / 2"
:width="readoutBoxWidth"
:height="readoutBoxHeight"
fill="rgba(10,10,30,0.95)"
stroke="#22d3ee"
stroke-width="1.5"
rx="2"
fill="#02040b"
stroke="#2fe5ff"
stroke-width="1.4"
rx="1.5"
/>
<text
:x="width / 2"
:y="centerY + 5"
fill="#22d3ee"
fill="#2fe5ff"
font-size="14"
font-weight="bold"
text-anchor="middle"

View File

@@ -82,12 +82,12 @@ const dotRadius = computed(() => 4)
<circle :cx="cx" :cy="cy" :r="size * 0.46" />
</clipPath>
<linearGradient :id="skyGradId" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#1a5fb4" />
<stop offset="100%" stop-color="#62a0ea" />
<stop offset="0%" stop-color="#26aef0" />
<stop offset="100%" stop-color="#1e9ddf" />
</linearGradient>
<linearGradient :id="groundGradId" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#8b6914" />
<stop offset="100%" stop-color="#5e4108" />
<stop offset="0%" stop-color="#b56517" />
<stop offset="100%" stop-color="#9b5312" />
</linearGradient>
</defs>
@@ -118,7 +118,7 @@ const dotRadius = computed(() => 4)
:x2="size * 2"
:y2="0"
stroke="white"
stroke-width="1.5"
stroke-width="2"
/>
<!-- Pitch ladder -->
@@ -135,7 +135,7 @@ const dotRadius = computed(() => 4)
<text
:x="-mark.width / 2 - 6"
:y="mark.y + 4"
fill="white"
fill="#f4f6fb"
font-size="11"
text-anchor="end"
font-family="monospace"
@@ -145,7 +145,7 @@ const dotRadius = computed(() => 4)
<text
:x="mark.width / 2 + 6"
:y="mark.y + 4"
fill="white"
fill="#f4f6fb"
font-size="11"
text-anchor="start"
font-family="monospace"
@@ -165,21 +165,21 @@ const dotRadius = computed(() => 4)
:y1="tick.y1"
:x2="tick.x2"
:y2="tick.y2"
stroke="white"
stroke="#f4f6fb"
stroke-width="1.5"
/>
<!-- Zero-bank reference triangle (fixed, top center) -->
<polygon
:points="`${cx},${cy - size * 0.42} ${cx - 6},${cy - size * 0.42 - 10} ${cx + 6},${cy - size * 0.42 - 10}`"
fill="white"
fill="#f4f6fb"
/>
<!-- Bank pointer (rotates with bank) -->
<polygon
:points="bankPointer"
:transform="bankPointerTransform"
fill="#22d3ee"
fill="#facc15"
/>
<!-- Fixed aircraft reference symbol -->

View File

@@ -66,7 +66,7 @@ const readoutText = computed(() => {
return normalized.toString().padStart(3, '0')
})
const readoutBoxWidth = 36
const readoutBoxWidth = 40
const readoutBoxHeight = 18
</script>
@@ -83,14 +83,23 @@ const readoutBoxHeight = 18
</clipPath>
</defs>
<!-- Background -->
<!-- Airbus-style heading tape -->
<rect
x="0"
y="0"
:width="width"
:height="height"
fill="rgba(10,10,30,0.95)"
rx="2"
fill="#8f9198"
rx="1"
/>
<rect
x="1.5"
y="1.5"
:width="width - 3"
:height="height - 3"
fill="#94969d"
stroke="#d4d6dc"
stroke-width="0.8"
/>
<!-- Readout box at top center (yellow heading value) -->
@@ -99,7 +108,7 @@ const readoutBoxHeight = 18
y="2"
:width="readoutBoxWidth"
:height="readoutBoxHeight"
fill="rgba(10,10,30,0.95)"
fill="#02040b"
stroke="#facc15"
stroke-width="1"
rx="2"
@@ -131,7 +140,7 @@ const readoutBoxHeight = 18
:y1="height"
:x2="mark.x"
:y2="mark.isMajor ? height - 12 : height - 7"
stroke="white"
stroke="#f4f6fb"
:stroke-width="mark.isMajor ? 1.5 : 1"
/>
<!-- Label (above tick) -->
@@ -139,7 +148,7 @@ const readoutBoxHeight = 18
v-if="mark.isMajor"
:x="mark.x"
:y="height - 15"
fill="white"
fill="#f4f6fb"
font-size="11"
text-anchor="middle"
font-family="monospace"

View File

@@ -71,6 +71,10 @@ const trendLineEndY = computed(() => {
const readoutBoxHeight = 24
const readoutBoxWidth = computed(() => props.width - 8)
const tapeInnerX = 2
const tapeInnerY = 2
const tapeInnerWidth = computed(() => props.width - 4)
const tapeInnerHeight = computed(() => props.height - 4)
</script>
<template>
@@ -86,14 +90,23 @@ const readoutBoxWidth = computed(() => props.width - 8)
</clipPath>
</defs>
<!-- Background -->
<!-- Airbus-style tape body -->
<rect
x="0"
y="0"
:width="width"
:height="height"
fill="rgba(10,10,30,0.95)"
rx="2"
fill="#8f9198"
rx="1"
/>
<rect
:x="tapeInnerX"
:y="tapeInnerY"
:width="tapeInnerWidth"
:height="tapeInnerHeight"
fill="#93959c"
stroke="#d2d4da"
stroke-width="0.8"
/>
<!-- Scrolling tape (clipped) -->
@@ -130,19 +143,19 @@ const readoutBoxWidth = computed(() => props.width - 8)
<g v-for="mark in marks" :key="mark.spd">
<!-- Tick mark -->
<line
:x1="width - 8"
:x1="width - 10"
:y1="mark.y"
:x2="width"
:x2="width - 1"
:y2="mark.y"
stroke="white"
stroke="#f4f6fb"
stroke-width="1"
/>
<!-- Label -->
<text
v-if="mark.isLabel"
:x="width - 12"
:x="width - 14"
:y="mark.y + 4"
fill="white"
fill="#f4f6fb"
font-size="12"
text-anchor="end"
font-family="monospace"
@@ -158,7 +171,7 @@ const readoutBoxWidth = computed(() => props.width - 8)
:y1="centerY"
:x2="width / 2"
:y2="trendLineEndY"
stroke="#22d3ee"
stroke="#30e3ff"
stroke-width="2"
opacity="0.8"
/>
@@ -170,15 +183,15 @@ const readoutBoxWidth = computed(() => props.width - 8)
:y="centerY - readoutBoxHeight / 2"
:width="readoutBoxWidth"
:height="readoutBoxHeight"
fill="rgba(10,10,30,0.95)"
stroke="#22d3ee"
stroke-width="1.5"
rx="2"
fill="#02040b"
stroke="#2fe5ff"
stroke-width="1.4"
rx="1.5"
/>
<text
:x="width / 2"
:y="centerY + 5"
fill="#22d3ee"
fill="#2fe5ff"
font-size="15"
font-weight="bold"
text-anchor="middle"

View File

@@ -57,14 +57,14 @@ const bandHeight = computed(() => Math.abs(needleY.value - centerY.value))
</clipPath>
</defs>
<!-- Background -->
<!-- Airbus-like VS channel -->
<rect
x="0"
y="0"
:width="width"
:height="height"
fill="rgba(10,10,30,0.95)"
rx="2"
fill="#0b1126"
rx="1"
/>
<g :clip-path="`url(#${clipId})`">
@@ -86,14 +86,14 @@ const bandHeight = computed(() => Math.abs(needleY.value - centerY.value))
:y1="mark.y"
:x2="width * 0.45"
:y2="mark.y"
stroke="white"
stroke="#f4f6fb"
:stroke-width="mark.fpm === 0 ? 1.5 : 1"
/>
<text
v-if="mark.fpm !== 0"
:x="width * 0.55"
:y="mark.y + 4"
fill="white"
fill="#f4f6fb"
font-size="9"
text-anchor="start"
font-family="monospace"
@@ -109,14 +109,14 @@ const bandHeight = computed(() => Math.abs(needleY.value - centerY.value))
:y="bandY"
:width="width * 0.3"
:height="Math.max(bandHeight, 1)"
fill="#22d3ee"
fill="#2fe5ff"
opacity="0.7"
/>
<!-- Needle indicator -->
<polygon
:points="`${width * 0.05},${needleY} ${width * 0.3},${needleY - 4} ${width * 0.3},${needleY + 4}`"
fill="#22d3ee"
fill="#2fe5ff"
/>
</g>
@@ -125,7 +125,7 @@ const bandHeight = computed(() => Math.abs(needleY.value - centerY.value))
v-if="Math.abs(verticalSpeed) > 50"
:x="width / 2"
:y="height - 6"
fill="#22d3ee"
fill="#2fe5ff"
font-size="9"
font-weight="bold"
text-anchor="middle"