forked from Ivasoft/geovisio-website
161 lines
4.3 KiB
Vue
161 lines
4.3 KiB
Vue
<template>
|
|
<div class="wrapper-orientation">
|
|
<h2 class="orientation-title">
|
|
{{ $t('pages.sequence.orientation_panel_title') }}
|
|
</h2>
|
|
<div class="entry-information-card">
|
|
<InformationCard>
|
|
<template v-slot:title>
|
|
<h3 class="subtitle">
|
|
{{ $t('pages.sequence.orientation_panel_tooltip') }}
|
|
</h3>
|
|
</template>
|
|
</InformationCard>
|
|
<div class="wrapper-input-angle">
|
|
<label for="inputAngle" name="inputAngle">{{
|
|
$t('pages.sequence.orientation_input_label')
|
|
}}</label>
|
|
<Input
|
|
id="inputAngle"
|
|
name="inputAngle"
|
|
type="number"
|
|
min="-180"
|
|
max="180"
|
|
:text="Number(angleInputValue)"
|
|
:placeholder="$t('pages.sequence.orientation_input_placeholder')"
|
|
@input="captureAngle"
|
|
/>
|
|
<span v-if="errorAngleValue" class="errorValue">{{
|
|
$t('pages.sequence.orientation_input_error_value')
|
|
}}</span>
|
|
</div>
|
|
</div>
|
|
<div class="entry-compass">
|
|
<WidgetOrientation
|
|
:road-degrees="roadDegrees"
|
|
:seq-brute-deg="angleValue"
|
|
@triggerAngle="captureAngle"
|
|
@triggerMovingAngle="triggerMovingAngle"
|
|
/>
|
|
</div>
|
|
<div class="entry-button">
|
|
<Button
|
|
look="button--blue"
|
|
:text="$t('pages.sequence.orientation_panel_button')"
|
|
:disabled="isDisabled(Number(angleInputValue)) || isLoading"
|
|
@trigger="triggerAngle"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, watchEffect, onMounted, onUnmounted } from 'vue'
|
|
import InformationCard from '@/components/InformationCard.vue'
|
|
import Button from '@/components/Button.vue'
|
|
import Input from '@/components/Input.vue'
|
|
import WidgetOrientation from '@/components/sequence/WidgetOrientation.vue'
|
|
import { modulo180 } from '@/utils/calc'
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'triggerAngle', value: number): void
|
|
(e: 'triggerMovingAngle', value: number): void
|
|
}>()
|
|
let angleValue = ref<number>(0)
|
|
let angleInputValue = ref<number>(0)
|
|
let errorAngleValue = ref<boolean>(false)
|
|
const props = defineProps({
|
|
roadDegrees: { type: Number, default: 0 },
|
|
seqBruteDeg: { type: Number, default: 0 },
|
|
isLoading: { type: Boolean, default: false }
|
|
})
|
|
|
|
onMounted(() => {
|
|
triggerMovingAngle(angleInputValue.value)
|
|
})
|
|
onUnmounted(() => {
|
|
triggerMovingAngle(angleInputValue.value)
|
|
})
|
|
watchEffect(() => {
|
|
angleValue.value = props.seqBruteDeg
|
|
angleInputValue.value = Math.round(props.seqBruteDeg - props.roadDegrees)
|
|
})
|
|
function isDisabled(value: number): boolean {
|
|
return value < -180 || value > 180
|
|
}
|
|
function captureAngle(value: number | string) {
|
|
errorAngleValue.value = false
|
|
const valueNum = Number(value)
|
|
angleInputValue.value = valueNum
|
|
angleValue.value = valueNum + props.roadDegrees
|
|
const movingAngle = modulo180(angleValue.value, Math.round(props.roadDegrees))
|
|
emit('triggerMovingAngle', movingAngle)
|
|
if (isDisabled(valueNum)) return (errorAngleValue.value = true)
|
|
}
|
|
function triggerMovingAngle(value: number) {
|
|
emit('triggerMovingAngle', value)
|
|
}
|
|
function triggerAngle() {
|
|
const valueToSend = angleValue.value - Number(props.roadDegrees)
|
|
if (isDisabled(valueToSend)) return
|
|
emit('triggerAngle', valueToSend)
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.wrapper-orientation {
|
|
background-color: var(--blue-semi-pale);
|
|
}
|
|
.orientation-title {
|
|
@include text(h4);
|
|
margin-bottom: toRem(2);
|
|
}
|
|
.subtitle {
|
|
@include text(m-r-regular);
|
|
color: var(--blue-dark);
|
|
margin-bottom: 0;
|
|
}
|
|
.entry-compass {
|
|
width: 100%;
|
|
margin-bottom: toRem(2);
|
|
}
|
|
.entry-information-card {
|
|
margin-top: toRem(2);
|
|
margin-bottom: toRem(2.5);
|
|
display: flex;
|
|
}
|
|
.wrapper-input-angle {
|
|
margin-left: toRem(1);
|
|
width: 45%;
|
|
background-color: var(--white);
|
|
padding: toRem(1);
|
|
border-radius: toRem(1);
|
|
}
|
|
.entry-button {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
.errorValue {
|
|
color: var(--red);
|
|
@include text(xs-r-regular);
|
|
text-align: center;
|
|
}
|
|
@media (max-width: toRem(102.4)) {
|
|
.entry-information-card {
|
|
flex-direction: column;
|
|
}
|
|
.wrapper-input-angle {
|
|
margin-left: 0;
|
|
width: 100%;
|
|
margin-top: toRem(1);
|
|
}
|
|
}
|
|
@media (max-width: toRem(50)) {
|
|
.orientation-title {
|
|
@include text(m-regular);
|
|
margin-bottom: toRem(2);
|
|
}
|
|
}
|
|
</style>
|