Improve Target SoC Selection (#3476)
This commit is contained in:
parent
e00bcbf3c7
commit
1f22f3c290
6 changed files with 129 additions and 66 deletions
79
assets/js/components/TargetSoCSelect.vue
Normal file
79
assets/js/components/TargetSoCSelect.vue
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<LabelAndValue class="flex-grow-1" :label="$t('main.vehicle.targetSoC')" :on-dark="true">
|
||||
<h3 class="value m-0">
|
||||
<label class="d-inline-block position-relative">
|
||||
<select :value="targetSoc" class="custom-select" @change="change">
|
||||
<option v-for="{ soc, text } in options" :key="soc" :value="soc">
|
||||
{{ text }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="text-decoration-underline">{{ targetSoc }}%</span>
|
||||
</label>
|
||||
|
||||
<span v-if="estimatedTargetRange" class="extraValue d-block d-sm-inline text-nowrap">
|
||||
{{ estimatedTargetRange }}km
|
||||
</span>
|
||||
</h3>
|
||||
</LabelAndValue>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LabelAndValue from "./LabelAndValue.vue";
|
||||
|
||||
export default {
|
||||
name: "TargetSoCSelect",
|
||||
components: { LabelAndValue },
|
||||
props: {
|
||||
targetSoc: Number,
|
||||
rangePerSoc: Number,
|
||||
},
|
||||
emits: ["target-soc-updated"],
|
||||
|
||||
computed: {
|
||||
options: function () {
|
||||
const result = [];
|
||||
for (let soc = 20; soc <= 100; soc += 5) {
|
||||
let text = `${soc}%`;
|
||||
const range = this.estimatedRange(soc);
|
||||
if (range) {
|
||||
text += ` (${range}km)`;
|
||||
}
|
||||
result.push({ soc, text });
|
||||
}
|
||||
return result;
|
||||
},
|
||||
estimatedTargetRange: function () {
|
||||
return this.estimatedRange(this.targetSoc);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
change: function (e) {
|
||||
return this.$emit("target-soc-updated", e.target.value);
|
||||
},
|
||||
estimatedRange: function (soc) {
|
||||
if (this.rangePerSoc) {
|
||||
return Math.round(soc * this.rangePerSoc);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.value {
|
||||
font-size: 18px;
|
||||
}
|
||||
.extraValue {
|
||||
color: var(--bs-gray-light);
|
||||
font-size: 14px;
|
||||
}
|
||||
.custom-select {
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -17,12 +17,11 @@
|
|||
:extraValue="vehicleRange ? `${vehicleRange} km` : null"
|
||||
on-dark
|
||||
/>
|
||||
<LabelAndValue
|
||||
<TargetSoCSelect
|
||||
class="flex-grow-1 text-center"
|
||||
:label="$t('main.vehicle.targetSoC')"
|
||||
:value="`${displayTargetSoC} %`"
|
||||
:extraValue="estimatedTargetRange"
|
||||
on-dark
|
||||
:target-soc="displayTargetSoC"
|
||||
:range-per-soc="rangePerSoC"
|
||||
@target-soc-updated="targetSocUpdated"
|
||||
/>
|
||||
<TargetCharge
|
||||
class="flex-grow-1 text-end target-charge"
|
||||
|
|
@ -46,10 +45,18 @@ import VehicleTitle from "./VehicleTitle.vue";
|
|||
import VehicleSoc from "./VehicleSoc.vue";
|
||||
import VehicleStatus from "./VehicleStatus.vue";
|
||||
import TargetCharge from "./TargetCharge.vue";
|
||||
import TargetSoCSelect from "./TargetSoCSelect.vue";
|
||||
|
||||
export default {
|
||||
name: "Vehicle",
|
||||
components: { VehicleTitle, VehicleSoc, VehicleStatus, LabelAndValue, TargetCharge },
|
||||
components: {
|
||||
VehicleTitle,
|
||||
VehicleSoc,
|
||||
VehicleStatus,
|
||||
LabelAndValue,
|
||||
TargetCharge,
|
||||
TargetSoCSelect,
|
||||
},
|
||||
mixins: [collector],
|
||||
props: {
|
||||
id: [String, Number],
|
||||
|
|
@ -91,12 +98,9 @@ export default {
|
|||
targetCharge: function () {
|
||||
return this.collectProps(TargetCharge);
|
||||
},
|
||||
estimatedTargetRange: function () {
|
||||
if (this.vehicleSoC > 10 && this.vehicleRange && this.displayTargetSoC) {
|
||||
return (
|
||||
Math.round(this.displayTargetSoC * (this.vehicleRange / this.vehicleSoC)) +
|
||||
" km"
|
||||
);
|
||||
rangePerSoC: function () {
|
||||
if (this.vehicleSoC > 10 && this.vehicleRange) {
|
||||
return this.vehicleRange / this.vehicleSoC;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -21,10 +21,6 @@
|
|||
></div>
|
||||
</div>
|
||||
<div class="target">
|
||||
<div
|
||||
class="target-label d-flex align-items-center justify-content-center"
|
||||
:style="{ left: `${visibleTargetSoC}%` }"
|
||||
></div>
|
||||
<input
|
||||
v-if="vehiclePresent && (connected || parked)"
|
||||
type="range"
|
||||
|
|
@ -33,9 +29,9 @@
|
|||
step="5"
|
||||
:value="visibleTargetSoC"
|
||||
class="target-slider"
|
||||
@input="movedTargetSoC"
|
||||
@mousedown="changeTargetSoCStart"
|
||||
@touchstart="changeTargetSoCStart"
|
||||
@input="movedTargetSoC"
|
||||
@mouseup="changeTargetSoCEnd"
|
||||
@touchend="changeTargetSoCEnd"
|
||||
/>
|
||||
|
|
@ -102,25 +98,16 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
changeTargetSoCStart: function (e) {
|
||||
const screenY = e.screenY || e.changedTouches[0].screenY;
|
||||
this.interactionStartScreenY = screenY;
|
||||
e.stopPropagation();
|
||||
},
|
||||
changeTargetSoCEnd: function (e) {
|
||||
const screenY = e.screenY || e.changedTouches[0].screenY;
|
||||
const yDiff = Math.abs(screenY - this.interactionStartScreenY);
|
||||
// horizontal scroll detected - revert slider change
|
||||
if (yDiff > 80) {
|
||||
e.preventDefault();
|
||||
e.target.value = this.targetSoC;
|
||||
this.selectedTargetSoC = this.targetSoC;
|
||||
return false;
|
||||
}
|
||||
// value changed
|
||||
if (e.target.value !== this.targetSoC) {
|
||||
this.$emit("target-soc-updated", e.target.value);
|
||||
}
|
||||
},
|
||||
movedTargetSoC: function (e) {
|
||||
e.stopPropagation();
|
||||
const minTargetSoC = 20;
|
||||
if (e.target.value < minTargetSoC) {
|
||||
e.target.value = minTargetSoC;
|
||||
|
|
@ -155,16 +142,6 @@ export default {
|
|||
.bg-light {
|
||||
color: var(--bs-gray-dark);
|
||||
}
|
||||
.target-label {
|
||||
width: 3em;
|
||||
margin-left: -1.5em;
|
||||
height: var(--label-height);
|
||||
position: absolute;
|
||||
top: calc((var(--label-height) + var(--thumb-overlap)) * -1);
|
||||
text-align: center;
|
||||
color: var(--bs-gray-dark);
|
||||
font-size: 1rem;
|
||||
}
|
||||
.target-slider {
|
||||
-webkit-appearance: none;
|
||||
position: absolute;
|
||||
|
|
@ -172,6 +149,7 @@ export default {
|
|||
height: calc(100% + 2 * var(--thumb-overlap));
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
.target-slider:focus {
|
||||
outline: none;
|
||||
|
|
@ -182,13 +160,13 @@ export default {
|
|||
background: transparent;
|
||||
border: none;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
cursor: auto;
|
||||
}
|
||||
.target-slider::-moz-range-track {
|
||||
background: transparent;
|
||||
border: none;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
cursor: auto;
|
||||
}
|
||||
.target-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
|
|
@ -202,6 +180,7 @@ export default {
|
|||
opacity: 1;
|
||||
border-radius: var(--thumb-overlap);
|
||||
box-shadow: 0 0 6px var(--bs-gray-dark);
|
||||
pointer-events: auto;
|
||||
}
|
||||
.target-slider::-moz-range-thumb {
|
||||
position: relative;
|
||||
|
|
@ -213,5 +192,6 @@ export default {
|
|||
opacity: 1;
|
||||
border-radius: var(--thumb-overlap);
|
||||
box-shadow: 0 0 6px var(--bs-gray-dark);
|
||||
pointer-events: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -20,8 +20,8 @@
|
|||
<meta name="theme-color" content="#28293e" />
|
||||
|
||||
<title>evcc</title>
|
||||
<script type="module" crossorigin src="./assets/index.77e636e1.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.1f9ca7ee.css">
|
||||
<script type="module" crossorigin src="./assets/index.61d9e798.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.a4ef9a54.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue