primevue-mirror/components/lib/slider/Slider.vue

333 lines
12 KiB
Vue
Raw Normal View History

2022-09-06 12:03:37 +00:00
<template>
2023-05-29 09:19:55 +00:00
<div :class="cx('root')" @click="onBarClick" v-bind="ptm('root')" :data-p-sliding="false" data-pc-name="slider">
2023-05-24 14:09:28 +00:00
<span :class="cx('range')" :style="[sx('range'), rangeStyle]" v-bind="ptm('range')"></span>
2022-09-14 11:26:01 +00:00
<span
v-if="!range"
2023-05-24 14:09:28 +00:00
:class="cx('handle')"
:style="[sx('handle'), handleStyle]"
2022-09-14 11:26:01 +00:00
@touchstart="onDragStart($event)"
@touchmove="onDrag($event)"
@touchend="onDragEnd($event)"
@mousedown="onMouseDown($event)"
@keydown="onKeyDown($event)"
:tabindex="tabindex"
role="slider"
:aria-valuemin="min"
:aria-valuenow="modelValue"
:aria-valuemax="max"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-orientation="orientation"
2023-05-07 10:54:26 +00:00
v-bind="ptm('handle')"
2022-09-14 11:26:01 +00:00
></span>
<span
v-if="range"
2023-05-24 14:09:28 +00:00
:class="cx('handle')"
:style="[sx('handle'), rangeStartHandleStyle]"
2022-09-14 11:26:01 +00:00
@touchstart="onDragStart($event, 0)"
@touchmove="onDrag($event)"
@touchend="onDragEnd($event)"
@mousedown="onMouseDown($event, 0)"
@keydown="onKeyDown($event, 0)"
:tabindex="tabindex"
role="slider"
:aria-valuemin="min"
:aria-valuenow="modelValue ? modelValue[0] : null"
:aria-valuemax="max"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-orientation="orientation"
2023-05-07 10:54:26 +00:00
v-bind="ptm('startHandler')"
2022-09-14 11:26:01 +00:00
></span>
<span
v-if="range"
2023-05-24 14:09:28 +00:00
:class="cx('handle')"
:style="[sx('handle'), rangeEndHandleStyle]"
2022-09-14 11:26:01 +00:00
@touchstart="onDragStart($event, 1)"
@touchmove="onDrag($event)"
@touchend="onDragEnd($event)"
@mousedown="onMouseDown($event, 1)"
@keydown="onKeyDown($event, 1)"
:tabindex="tabindex"
role="slider"
:aria-valuemin="min"
:aria-valuenow="modelValue ? modelValue[1] : null"
:aria-valuemax="max"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-orientation="orientation"
2023-05-07 10:54:26 +00:00
v-bind="ptm('endHandler')"
2022-09-14 11:26:01 +00:00
></span>
2022-09-06 12:03:37 +00:00
</div>
</template>
<script>
2022-09-14 11:26:01 +00:00
import { DomHandler } from 'primevue/utils';
2023-05-24 14:09:28 +00:00
import BaseSlider from './BaseSlider.vue';
2022-09-06 12:03:37 +00:00
export default {
name: 'Slider',
2023-05-24 14:09:28 +00:00
extends: BaseSlider,
2022-09-06 12:03:37 +00:00
emits: ['update:modelValue', 'change', 'slideend'],
dragging: false,
handleIndex: null,
initX: null,
initY: null,
barWidth: null,
barHeight: null,
dragListener: null,
dragEndListener: null,
beforeUnmount() {
this.unbindDragListeners();
},
methods: {
updateDomData() {
let rect = this.$el.getBoundingClientRect();
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
this.initX = rect.left + DomHandler.getWindowScrollLeft();
this.initY = rect.top + DomHandler.getWindowScrollTop();
this.barWidth = this.$el.offsetWidth;
this.barHeight = this.$el.offsetHeight;
},
setValue(event) {
let handleValue;
let pageX = event.touches ? event.touches[0].pageX : event.pageX;
let pageY = event.touches ? event.touches[0].pageY : event.pageY;
2022-09-14 11:26:01 +00:00
if (this.orientation === 'horizontal') handleValue = ((pageX - this.initX) * 100) / this.barWidth;
else handleValue = ((this.initY + this.barHeight - pageY) * 100) / this.barHeight;
2022-09-06 12:03:37 +00:00
let newValue = (this.max - this.min) * (handleValue / 100) + this.min;
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
if (this.step) {
const oldValue = this.range ? this.value[this.handleIndex] : this.value;
2022-09-14 11:26:01 +00:00
const diff = newValue - oldValue;
2023-10-16 11:47:21 +00:00
if (diff < 0) newValue = oldValue + Math.ceil(newValue / this.step - oldValue / this.step) * this.step;
else if (diff > 0) newValue = oldValue + Math.floor(newValue / this.step - oldValue / this.step) * this.step;
2022-09-14 11:26:01 +00:00
} else {
2022-09-06 12:03:37 +00:00
newValue = Math.floor(newValue);
}
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
this.updateModel(event, newValue);
},
updateModel(event, value) {
let newValue = parseFloat(value.toFixed(10));
let modelValue;
if (this.range) {
modelValue = this.value ? [...this.value] : [];
2022-09-06 12:03:37 +00:00
if (this.handleIndex == 0) {
2022-09-14 11:26:01 +00:00
if (newValue < this.min) newValue = this.min;
2022-12-08 11:04:25 +00:00
else if (newValue >= this.max) newValue = this.max;
2022-09-06 12:03:37 +00:00
modelValue[0] = newValue;
2022-12-08 11:04:25 +00:00
} else {
2022-09-14 11:26:01 +00:00
if (newValue > this.max) newValue = this.max;
2022-12-08 11:04:25 +00:00
else if (newValue <= this.min) newValue = this.min;
2022-09-06 12:03:37 +00:00
modelValue[1] = newValue;
2022-09-06 12:03:37 +00:00
}
2022-09-14 11:26:01 +00:00
} else {
if (newValue < this.min) newValue = this.min;
else if (newValue > this.max) newValue = this.max;
2022-09-06 12:03:37 +00:00
modelValue = newValue;
}
this.$emit('update:modelValue', modelValue);
this.$emit('change', modelValue);
},
onDragStart(event, index) {
if (this.disabled) {
return;
}
2023-05-24 14:09:28 +00:00
this.$el.setAttribute('data-p-sliding', true);
2022-09-06 12:03:37 +00:00
this.dragging = true;
this.updateDomData();
if (this.range && this.value[0] === this.max) {
2022-09-06 12:03:37 +00:00
this.handleIndex = 0;
2022-09-14 11:26:01 +00:00
} else {
2022-09-06 12:03:37 +00:00
this.handleIndex = index;
}
event.currentTarget.focus();
2022-09-06 12:03:37 +00:00
event.preventDefault();
},
onDrag(event) {
if (this.dragging) {
this.setValue(event);
event.preventDefault();
}
},
onDragEnd(event) {
if (this.dragging) {
this.dragging = false;
2023-05-24 14:09:28 +00:00
this.$el.setAttribute('data-p-sliding', false);
this.$emit('slideend', { originalEvent: event, value: this.value });
2022-09-06 12:03:37 +00:00
}
},
onBarClick(event) {
if (this.disabled) {
return;
}
2022-09-14 11:26:01 +00:00
2023-05-24 14:09:28 +00:00
if (DomHandler.getAttribute(event.target, 'data-pc-section') !== 'handle') {
2022-09-06 12:03:37 +00:00
this.updateDomData();
this.setValue(event);
}
},
onMouseDown(event, index) {
this.bindDragListeners();
this.onDragStart(event, index);
},
onKeyDown(event, index) {
this.handleIndex = index;
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
switch (event.code) {
case 'ArrowDown':
case 'ArrowLeft':
this.decrementValue(event, index);
event.preventDefault();
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
case 'ArrowUp':
case 'ArrowRight':
this.incrementValue(event, index);
event.preventDefault();
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
case 'PageDown':
this.decrementValue(event, index, true);
event.preventDefault();
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
case 'PageUp':
this.incrementValue(event, index, true);
event.preventDefault();
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
case 'Home':
this.updateModel(event, this.min);
event.preventDefault();
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
case 'End':
this.updateModel(event, this.max);
event.preventDefault();
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
default:
2022-09-14 11:26:01 +00:00
break;
2022-09-06 12:03:37 +00:00
}
},
decrementValue(event, index, pageKey = false) {
let newValue;
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
if (this.range) {
if (this.step) newValue = this.value[index] - this.step;
else newValue = this.value[index] - 1;
2022-09-14 11:26:01 +00:00
} else {
if (this.step) newValue = this.value - this.step;
else if (!this.step && pageKey) newValue = this.value - 10;
else newValue = this.value - 1;
2022-09-06 12:03:37 +00:00
}
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
this.updateModel(event, newValue);
event.preventDefault();
},
incrementValue(event, index, pageKey = false) {
let newValue;
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
if (this.range) {
if (this.step) newValue = this.value[index] + this.step;
else newValue = this.value[index] + 1;
2022-09-14 11:26:01 +00:00
} else {
if (this.step) newValue = this.value + this.step;
else if (!this.step && pageKey) newValue = this.value + 10;
else newValue = this.value + 1;
2022-09-06 12:03:37 +00:00
}
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
this.updateModel(event, newValue);
event.preventDefault();
},
bindDragListeners() {
if (!this.dragListener) {
this.dragListener = this.onDrag.bind(this);
document.addEventListener('mousemove', this.dragListener);
}
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
if (!this.dragEndListener) {
this.dragEndListener = this.onDragEnd.bind(this);
document.addEventListener('mouseup', this.dragEndListener);
}
},
unbindDragListeners() {
if (this.dragListener) {
document.removeEventListener('mousemove', this.dragListener);
this.dragListener = null;
}
2022-09-14 11:26:01 +00:00
2022-09-06 12:03:37 +00:00
if (this.dragEndListener) {
document.removeEventListener('mouseup', this.dragEndListener);
this.dragEndListener = null;
}
}
},
computed: {
value() {
if (this.range) {
return [this.modelValue?.[0] ?? this.min, this.modelValue?.[1] ?? this.max];
}
return this.modelValue ?? this.min;
},
2022-09-06 12:03:37 +00:00
horizontal() {
return this.orientation === 'horizontal';
},
vertical() {
return this.orientation === 'vertical';
},
rangeStyle() {
if (this.range) {
2022-12-08 11:04:25 +00:00
const rangeSliderWidth = this.rangeEndPosition > this.rangeStartPosition ? this.rangeEndPosition - this.rangeStartPosition : this.rangeStartPosition - this.rangeEndPosition;
const rangeSliderPosition = this.rangeEndPosition > this.rangeStartPosition ? this.rangeStartPosition : this.rangeEndPosition;
if (this.horizontal) return { left: rangeSliderPosition + '%', width: rangeSliderWidth + '%' };
else return { bottom: rangeSliderPosition + '%', height: rangeSliderWidth + '%' };
2022-09-14 11:26:01 +00:00
} else {
if (this.horizontal) return { width: this.handlePosition + '%' };
else return { height: this.handlePosition + '%' };
2022-09-06 12:03:37 +00:00
}
},
handleStyle() {
2022-09-14 11:26:01 +00:00
if (this.horizontal) return { left: this.handlePosition + '%' };
else return { bottom: this.handlePosition + '%' };
2022-09-06 12:03:37 +00:00
},
handlePosition() {
if (this.value < this.min) return 0;
else if (this.value > this.max) return 100;
else return ((this.value - this.min) * 100) / (this.max - this.min);
2022-09-06 12:03:37 +00:00
},
rangeStartPosition() {
if (this.value && this.value[0]) return ((this.value[0] < this.min ? 0 : this.value[0] - this.min) * 100) / (this.max - this.min);
2022-09-14 11:26:01 +00:00
else return 0;
2022-09-06 12:03:37 +00:00
},
rangeEndPosition() {
if (this.value && this.value.length === 2) return ((this.value[1] > this.max ? 100 : this.value[1] - this.min) * 100) / (this.max - this.min);
2022-09-14 11:26:01 +00:00
else return 100;
2022-09-06 12:03:37 +00:00
},
rangeStartHandleStyle() {
2022-09-14 11:26:01 +00:00
if (this.horizontal) return { left: this.rangeStartPosition + '%' };
else return { bottom: this.rangeStartPosition + '%' };
2022-09-06 12:03:37 +00:00
},
rangeEndHandleStyle() {
2022-09-14 11:26:01 +00:00
if (this.horizontal) return { left: this.rangeEndPosition + '%' };
else return { bottom: this.rangeEndPosition + '%' };
}
2022-09-06 12:03:37 +00:00
}
2022-09-14 11:26:01 +00:00
};
2022-09-06 12:03:37 +00:00
</script>