mirror of
https://github.com/nasa/openmct.git
synced 2025-06-19 07:38:15 +00:00
Dynamic sizing for compass rose based on image size (#3826)
* Dynamic sizing for compass rose based on image size - Compass rose now sizes and positions proportionally to the containing image, with min and max sizes; - Refactored computed `compassDimensionsStyle` as `sizedImageDimensions` for reusability; - Tweaked sizing of compass ordinals text and North arrow for better legibility; - Minor tweaks to element positioning and opacity for better legibility; - TODO: add unit tests; * Fix linting and code style - Fixed lint errors; - Better variable names; * Address comments from PR #3826 review: - Renamed `compassRoseSizing` to `compassRoseSizingClasses` and fixed function logic; - Fixed line breaks for code style;
This commit is contained in:
committed by
GitHub
parent
9920e67c83
commit
12416b8079
@ -23,7 +23,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="c-compass"
|
class="c-compass"
|
||||||
:style="compassDimensionsStyle"
|
:style="`width: ${ sizedImageDimensions.width }px; height: ${ sizedImageDimensions.height }px`"
|
||||||
>
|
>
|
||||||
<CompassHUD
|
<CompassHUD
|
||||||
v-if="hasCameraFieldOfView"
|
v-if="hasCameraFieldOfView"
|
||||||
@ -34,6 +34,7 @@
|
|||||||
<CompassRose
|
<CompassRose
|
||||||
v-if="hasCameraFieldOfView"
|
v-if="hasCameraFieldOfView"
|
||||||
:heading="heading"
|
:heading="heading"
|
||||||
|
:sized-image-width="sizedImageDimensions.width"
|
||||||
:sun-heading="sunHeading"
|
:sun-heading="sunHeading"
|
||||||
:camera-angle-of-view="cameraAngleOfView"
|
:camera-angle-of-view="cameraAngleOfView"
|
||||||
:camera-pan="cameraPan"
|
:camera-pan="cameraPan"
|
||||||
@ -77,6 +78,20 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
sizedImageDimensions() {
|
||||||
|
let sizedImageDimensions = {};
|
||||||
|
if ((this.containerWidth / this.containerHeight) > this.naturalAspectRatio) {
|
||||||
|
// container is wider than image
|
||||||
|
sizedImageDimensions.width = this.containerHeight * this.naturalAspectRatio;
|
||||||
|
sizedImageDimensions.height = this.containerHeight;
|
||||||
|
} else {
|
||||||
|
// container is taller than image
|
||||||
|
sizedImageDimensions.width = this.containerWidth;
|
||||||
|
sizedImageDimensions.height = this.containerWidth * this.naturalAspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sizedImageDimensions;
|
||||||
|
},
|
||||||
hasCameraFieldOfView() {
|
hasCameraFieldOfView() {
|
||||||
return this.cameraPan !== undefined && this.cameraAngleOfView > 0;
|
return this.cameraPan !== undefined && this.cameraAngleOfView > 0;
|
||||||
},
|
},
|
||||||
@ -94,25 +109,6 @@ export default {
|
|||||||
},
|
},
|
||||||
cameraAngleOfView() {
|
cameraAngleOfView() {
|
||||||
return CAMERA_ANGLE_OF_VIEW;
|
return CAMERA_ANGLE_OF_VIEW;
|
||||||
},
|
|
||||||
compassDimensionsStyle() {
|
|
||||||
const containerAspectRatio = this.containerWidth / this.containerHeight;
|
|
||||||
|
|
||||||
let width;
|
|
||||||
let height;
|
|
||||||
|
|
||||||
if (containerAspectRatio < this.naturalAspectRatio) {
|
|
||||||
width = '100%';
|
|
||||||
height = `${ this.containerWidth / this.naturalAspectRatio }px`;
|
|
||||||
} else {
|
|
||||||
width = `${ this.containerHeight * this.naturalAspectRatio }px`;
|
|
||||||
height = '100%';
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
width: width,
|
|
||||||
height: height
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div
|
||||||
|
class="w-direction-rose"
|
||||||
|
:class="compassRoseSizingClasses"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="c-direction-rose"
|
class="c-direction-rose"
|
||||||
@click="toggleLockCompass"
|
@click="toggleLockCompass"
|
||||||
@ -70,7 +74,7 @@
|
|||||||
>
|
>
|
||||||
<polygon
|
<polygon
|
||||||
class="c-nsew__tick c-tick-n"
|
class="c-nsew__tick c-tick-n"
|
||||||
points="50,0 57,5 43,5"
|
points="50,0 60,10 40,10"
|
||||||
/>
|
/>
|
||||||
<rect
|
<rect
|
||||||
class="c-nsew__tick c-tick-e"
|
class="c-nsew__tick c-tick-e"
|
||||||
@ -148,6 +152,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -155,6 +160,10 @@ import { rotate } from './utils';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
sizedImageWidth: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
heading: {
|
heading: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
@ -177,12 +186,24 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
north() {
|
compassRoseSizingClasses() {
|
||||||
return this.lockCompass ? rotate(-this.cameraPan) : 0;
|
let compassRoseSizingClasses = '';
|
||||||
|
if (this.sizedImageWidth < 300) {
|
||||||
|
compassRoseSizingClasses = '--rose-small --rose-min';
|
||||||
|
} else if (this.sizedImageWidth < 500) {
|
||||||
|
compassRoseSizingClasses = '--rose-small';
|
||||||
|
} else if (this.sizedImageWidth > 1000) {
|
||||||
|
compassRoseSizingClasses = '--rose-max';
|
||||||
|
}
|
||||||
|
|
||||||
|
return compassRoseSizingClasses;
|
||||||
},
|
},
|
||||||
compassRoseStyle() {
|
compassRoseStyle() {
|
||||||
return { transform: `rotate(${ this.north }deg)` };
|
return { transform: `rotate(${ this.north }deg)` };
|
||||||
},
|
},
|
||||||
|
north() {
|
||||||
|
return this.lockCompass ? rotate(-this.cameraPan) : 0;
|
||||||
|
},
|
||||||
northTextTransform() {
|
northTextTransform() {
|
||||||
return this.cardinalPointsTextTransform.north;
|
return this.cardinalPointsTextTransform.north;
|
||||||
},
|
},
|
||||||
@ -204,10 +225,10 @@ export default {
|
|||||||
const rotation = `rotate(${ -this.north })`;
|
const rotation = `rotate(${ -this.north })`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
north: `translate(50,15) ${ rotation }`,
|
north: `translate(50,23) ${ rotation }`,
|
||||||
east: `translate(87,50) ${ rotation }`,
|
east: `translate(82,50) ${ rotation }`,
|
||||||
south: `translate(13,50) ${ rotation }`,
|
south: `translate(18,50) ${ rotation }`,
|
||||||
west: `translate(50,87) ${ rotation }`
|
west: `translate(50,82) ${ rotation }`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
hasHeading() {
|
hasHeading() {
|
||||||
|
@ -27,7 +27,9 @@ $elemBg: rgba(black, 0.7);
|
|||||||
color: $interfaceKeyColor;
|
color: $interfaceKeyColor;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: $m; right: $m; left: $m;
|
top: $m;
|
||||||
|
right: $m;
|
||||||
|
left: $m;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
||||||
svg, div {
|
svg, div {
|
||||||
@ -47,7 +49,10 @@ $elemBg: rgba(black, 0.7);
|
|||||||
border: 1px solid $interfaceKeyColor;
|
border: 1px solid $interfaceKeyColor;
|
||||||
border-top-color: transparent;
|
border-top-color: transparent;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%; right: $padLR; bottom: $padTB; left: $padLR;
|
top: 50%;
|
||||||
|
right: $padLR;
|
||||||
|
bottom: $padTB;
|
||||||
|
left: $padLR;
|
||||||
}
|
}
|
||||||
|
|
||||||
[class*="__dir"] {
|
[class*="__dir"] {
|
||||||
@ -69,7 +74,8 @@ $elemBg: rgba(black, 0.7);
|
|||||||
$s: 10px;
|
$s: 10px;
|
||||||
@include sun('circle farthest-side at bottom');
|
@include sun('circle farthest-side at bottom');
|
||||||
bottom: $padTB + 2px;
|
bottom: $padTB + 2px;
|
||||||
height: $s; width: $s*2;
|
height: $s;
|
||||||
|
width: $s*2;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -80,10 +86,13 @@ $elemBg: rgba(black, 0.7);
|
|||||||
/***************************** COMPASS DIRECTIONS */
|
/***************************** COMPASS DIRECTIONS */
|
||||||
.c-nsew {
|
.c-nsew {
|
||||||
$color: $interfaceKeyColor;
|
$color: $interfaceKeyColor;
|
||||||
$inset: 7%;
|
$inset: 5%;
|
||||||
$tickHeightPerc: 15%;
|
$tickHeightPerc: 15%;
|
||||||
text-shadow: black 0 0 10px;
|
text-shadow: black 0 0 10px;
|
||||||
top: $inset; right: $inset; bottom: $inset; left: $inset;
|
top: $inset;
|
||||||
|
right: $inset;
|
||||||
|
bottom: $inset;
|
||||||
|
left: $inset;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
|
||||||
&__tick,
|
&__tick,
|
||||||
@ -99,19 +108,19 @@ $elemBg: rgba(black, 0.7);
|
|||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
dominant-baseline: central;
|
dominant-baseline: central;
|
||||||
font-size: 0.8em;
|
font-size: 1.25em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-label-n {
|
.c-label-n {
|
||||||
font-size: 1.1em;
|
font-size: 2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************** CAMERA FIELD ANGLE */
|
/***************************** CAMERA FIELD ANGLE */
|
||||||
.c-cam-field {
|
.c-cam-field {
|
||||||
$color: white;
|
$color: white;
|
||||||
opacity: 0.2;
|
opacity: 0.3;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@ -135,6 +144,7 @@ $elemBg: rgba(black, 0.7);
|
|||||||
// clip-paths overlap a bit to avoid a gap between halves
|
// clip-paths overlap a bit to avoid a gap between halves
|
||||||
&-l {
|
&-l {
|
||||||
clip-path: polygon(0 0, 50.5% 0, 50.5% 100%, 0 100%);
|
clip-path: polygon(0 0, 50.5% 0, 50.5% 100%, 0 100%);
|
||||||
|
|
||||||
.cam-field-area {
|
.cam-field-area {
|
||||||
transform-origin: left center;
|
transform-origin: left center;
|
||||||
}
|
}
|
||||||
@ -142,6 +152,7 @@ $elemBg: rgba(black, 0.7);
|
|||||||
|
|
||||||
&-r {
|
&-r {
|
||||||
clip-path: polygon(49.5% 0, 100% 0, 100% 100%, 49.5% 100%);
|
clip-path: polygon(49.5% 0, 100% 0, 100% 100%, 49.5% 100%);
|
||||||
|
|
||||||
.cam-field-area {
|
.cam-field-area {
|
||||||
transform-origin: right center;
|
transform-origin: right center;
|
||||||
}
|
}
|
||||||
@ -155,10 +166,13 @@ $elemBg: rgba(black, 0.7);
|
|||||||
$s: 30%;
|
$s: 30%;
|
||||||
background: $color;
|
background: $color;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
height: $s; width: $s;
|
height: $s;
|
||||||
left: 50%; top: 50%;
|
width: $s;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
transform-origin: center top;
|
transform-origin: center top;
|
||||||
|
transform: translateX(-50%); // center by default, overridden by CompassRose.vue / headingStyle()
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
// Direction arrow
|
// Direction arrow
|
||||||
@ -169,22 +183,63 @@ $elemBg: rgba(black, 0.7);
|
|||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10%; right: 20%; bottom: 50%; left: 20%;
|
top: 10%;
|
||||||
|
right: 20%;
|
||||||
|
bottom: 50%;
|
||||||
|
left: 20%;
|
||||||
clip-path: polygon(50% 0, 100% $arwPointerY, 100%-$arwBodyOffset $arwPointerY, 100%-$arwBodyOffset 100%, $arwBodyOffset 100%, $arwBodyOffset $arwPointerY, 0 $arwPointerY);
|
clip-path: polygon(50% 0, 100% $arwPointerY, 100%-$arwBodyOffset $arwPointerY, 100%-$arwBodyOffset 100%, $arwBodyOffset 100%, $arwBodyOffset $arwPointerY, 0 $arwPointerY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************** DIRECTION ROSE */
|
/***************************** DIRECTION ROSE */
|
||||||
|
.w-direction-rose {
|
||||||
|
$s: 10%;
|
||||||
|
$m: 2%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: $m;
|
||||||
|
left: $m;
|
||||||
|
width: $s;
|
||||||
|
padding-top: $s;
|
||||||
|
|
||||||
|
&.--rose-min {
|
||||||
|
$s: 30px;
|
||||||
|
width: $s;
|
||||||
|
padding-top: $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--rose-small {
|
||||||
|
.c-nsew__minor-ticks,
|
||||||
|
.c-tick-w,
|
||||||
|
.c-tick-s,
|
||||||
|
.c-tick-e,
|
||||||
|
.c-label-w,
|
||||||
|
.c-label-s,
|
||||||
|
.c-label-e {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-label-n {
|
||||||
|
font-size: 2.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--rose-max {
|
||||||
|
$s: 100px;
|
||||||
|
width: $s;
|
||||||
|
padding-top: $s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.c-direction-rose {
|
.c-direction-rose {
|
||||||
$d: 100px;
|
|
||||||
$c2: rgba(white, 0.1);
|
$c2: rgba(white, 0.1);
|
||||||
background: $elemBg;
|
background: $elemBg;
|
||||||
background-image: radial-gradient(circle closest-side, transparent, transparent 80%, $c2);
|
background-image: radial-gradient(circle closest-side, transparent, transparent 80%, $c2);
|
||||||
width: $d;
|
|
||||||
height: $d;
|
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px; left: 10px;
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
clip-path: circle(50% at 50% 50%);
|
clip-path: circle(50% at 50% 50%);
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
|
|
||||||
@ -206,8 +261,10 @@ $elemBg: rgba(black, 0.7);
|
|||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
top: 0; left: 50%;
|
top: 0;
|
||||||
height:$s; width: $s;
|
left: 50%;
|
||||||
|
height: $s;
|
||||||
|
width: $s;
|
||||||
transform: translate(-50%, -60%);
|
transform: translate(-50%, -60%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user