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:
Charles Hacskaylo
2021-05-11 12:07:44 -07:00
committed by GitHub
parent 9920e67c83
commit 12416b8079
3 changed files with 363 additions and 289 deletions

View File

@ -23,7 +23,7 @@
<template>
<div
class="c-compass"
:style="compassDimensionsStyle"
:style="`width: ${ sizedImageDimensions.width }px; height: ${ sizedImageDimensions.height }px`"
>
<CompassHUD
v-if="hasCameraFieldOfView"
@ -34,6 +34,7 @@
<CompassRose
v-if="hasCameraFieldOfView"
:heading="heading"
:sized-image-width="sizedImageDimensions.width"
:sun-heading="sunHeading"
:camera-angle-of-view="cameraAngleOfView"
:camera-pan="cameraPan"
@ -77,6 +78,20 @@ export default {
}
},
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() {
return this.cameraPan !== undefined && this.cameraAngleOfView > 0;
},
@ -94,25 +109,6 @@ export default {
},
cameraAngleOfView() {
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: {

View File

@ -22,9 +22,13 @@
<template>
<div
class="w-direction-rose"
:class="compassRoseSizingClasses"
>
<div
class="c-direction-rose"
@click="toggleLockCompass"
>
>
<div
class="c-nsew"
:style="compassRoseStyle"
@ -70,7 +74,7 @@
>
<polygon
class="c-nsew__tick c-tick-n"
points="50,0 57,5 43,5"
points="50,0 60,10 40,10"
/>
<rect
class="c-nsew__tick c-tick-e"
@ -147,6 +151,7 @@
></div>
</div>
</div>
</div>
</div>
</template>
@ -155,6 +160,10 @@ import { rotate } from './utils';
export default {
props: {
sizedImageWidth: {
type: Number,
required: true
},
heading: {
type: Number,
required: true
@ -177,12 +186,24 @@ export default {
}
},
computed: {
north() {
return this.lockCompass ? rotate(-this.cameraPan) : 0;
compassRoseSizingClasses() {
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() {
return { transform: `rotate(${ this.north }deg)` };
},
north() {
return this.lockCompass ? rotate(-this.cameraPan) : 0;
},
northTextTransform() {
return this.cardinalPointsTextTransform.north;
},
@ -204,10 +225,10 @@ export default {
const rotation = `rotate(${ -this.north })`;
return {
north: `translate(50,15) ${ rotation }`,
east: `translate(87,50) ${ rotation }`,
south: `translate(13,50) ${ rotation }`,
west: `translate(50,87) ${ rotation }`
north: `translate(50,23) ${ rotation }`,
east: `translate(82,50) ${ rotation }`,
south: `translate(18,50) ${ rotation }`,
west: `translate(50,82) ${ rotation }`
};
},
hasHeading() {

View File

@ -27,7 +27,9 @@ $elemBg: rgba(black, 0.7);
color: $interfaceKeyColor;
font-size: 0.8em;
position: absolute;
top: $m; right: $m; left: $m;
top: $m;
right: $m;
left: $m;
height: 18px;
svg, div {
@ -47,7 +49,10 @@ $elemBg: rgba(black, 0.7);
border: 1px solid $interfaceKeyColor;
border-top-color: transparent;
position: absolute;
top: 50%; right: $padLR; bottom: $padTB; left: $padLR;
top: 50%;
right: $padLR;
bottom: $padTB;
left: $padLR;
}
[class*="__dir"] {
@ -56,7 +61,7 @@ $elemBg: rgba(black, 0.7);
font-weight: bold;
text-shadow: 0 1px 2px black;
top: 50%;
transform: translate(-50%,-50%);
transform: translate(-50%, -50%);
z-index: 2;
}
@ -69,7 +74,8 @@ $elemBg: rgba(black, 0.7);
$s: 10px;
@include sun('circle farthest-side at bottom');
bottom: $padTB + 2px;
height: $s; width: $s*2;
height: $s;
width: $s*2;
opacity: 0.8;
transform: translateX(-50%);
z-index: 1;
@ -80,10 +86,13 @@ $elemBg: rgba(black, 0.7);
/***************************** COMPASS DIRECTIONS */
.c-nsew {
$color: $interfaceKeyColor;
$inset: 7%;
$inset: 5%;
$tickHeightPerc: 15%;
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;
&__tick,
@ -99,19 +108,19 @@ $elemBg: rgba(black, 0.7);
&__label {
dominant-baseline: central;
font-size: 0.8em;
font-size: 1.25em;
font-weight: bold;
}
.c-label-n {
font-size: 1.1em;
font-size: 2em;
}
}
/***************************** CAMERA FIELD ANGLE */
.c-cam-field {
$color: white;
opacity: 0.2;
opacity: 0.3;
top: 0;
right: 0;
bottom: 0;
@ -135,6 +144,7 @@ $elemBg: rgba(black, 0.7);
// clip-paths overlap a bit to avoid a gap between halves
&-l {
clip-path: polygon(0 0, 50.5% 0, 50.5% 100%, 0 100%);
.cam-field-area {
transform-origin: left center;
}
@ -142,6 +152,7 @@ $elemBg: rgba(black, 0.7);
&-r {
clip-path: polygon(49.5% 0, 100% 0, 100% 100%, 49.5% 100%);
.cam-field-area {
transform-origin: right center;
}
@ -155,10 +166,13 @@ $elemBg: rgba(black, 0.7);
$s: 30%;
background: $color;
border-radius: 3px;
height: $s; width: $s;
left: 50%; top: 50%;
height: $s;
width: $s;
left: 50%;
top: 50%;
opacity: 0.4;
transform-origin: center top;
transform: translateX(-50%); // center by default, overridden by CompassRose.vue / headingStyle()
&:before {
// Direction arrow
@ -169,22 +183,63 @@ $elemBg: rgba(black, 0.7);
content: '';
display: block;
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);
}
}
/***************************** 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 {
$d: 100px;
$c2: rgba(white, 0.1);
background: $elemBg;
background-image: radial-gradient(circle closest-side, transparent, transparent 80%, $c2);
width: $d;
height: $d;
transform-origin: 0 0;
position: absolute;
bottom: 10px; left: 10px;
top: 0;
right: 0;
bottom: 0;
left: 0;
clip-path: circle(50% at 50% 50%);
border-radius: 100%;
@ -206,8 +261,10 @@ $elemBg: rgba(black, 0.7);
display: block;
position: absolute;
opacity: 0.7;
top: 0; left: 50%;
height:$s; width: $s;
top: 0;
left: 50%;
height: $s;
width: $s;
transform: translate(-50%, -60%);
}
}