Improve Target SoC Selection (#3476)

This commit is contained in:
Michael Geers 2022-05-24 09:58:33 +02:00 • committed by GitHub
parent e00bcbf3c7
commit 1f22f3c290
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 129 additions and 66 deletions

View 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">
&nbsp;{{ 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>

View file

@ -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;
},

View file

@ -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
View file

@ -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>