@@ -97,9 +97,18 @@ const props = defineProps({
9797 refreshEndPoint: {
9898 type: Number ,
9999 default: null
100+ },
101+ enableRangeHandles: {
102+ type: Boolean ,
103+ default: false
104+ },
105+ enableSelectionDrag: {
106+ type: Boolean ,
107+ default: true
100108 }
101109});
102110
111+ const zoomWrapper = ref (null );
103112const startValue = ref (props .min );
104113const endValue = ref (props .max );
105114const hasMinimap = computed (() => !! props .minimap .length );
@@ -296,6 +305,87 @@ function setEndValue(value) {
296305 emit (' update:end' , Number (endValue .value ));
297306}
298307
308+ const currentRange = computed (() => {
309+ return props .valueEnd - props .valueStart ;
310+ });
311+
312+ const isDragging = ref (false );
313+ let initialMouseX = ref (null );
314+
315+ const dragThreshold = computed (() => {
316+ if (! zoomWrapper .value ) return 20 ;
317+ const w = zoomWrapper .value .getBoundingClientRect ().width - 48 ;
318+ return w / (props .max - props .min );
319+ });
320+
321+ const startDragging = (event ) => {
322+ if (! props .enableSelectionDrag ) {
323+ return ;
324+ }
325+ const isTouch = event .type === ' touchstart' ;
326+ const target = isTouch ? event .targetTouches [0 ].target : event .target ;
327+ if (target .classList .contains (' range-handle' )) {
328+ return ;
329+ }
330+ isDragging .value = true ;
331+ initialMouseX .value = isTouch ? event .targetTouches [0 ].clientX : event .clientX ;
332+
333+ const moveHandler = isTouch ? handleTouchDragging : handleDragging;
334+ const endHandler = isTouch ? stopTouchDragging : stopDragging;
335+
336+ window .addEventListener (isTouch ? ' touchmove' : ' mousemove' , moveHandler, { passive: false });
337+ window .addEventListener (isTouch ? ' touchend' : ' mouseup' , endHandler);
338+ };
339+
340+ function handleDragging (event ) {
341+ updateDragging (event .clientX );
342+ };
343+
344+ function handleTouchDragging (event ) {
345+ if (event .target .classList .contains (' range-handle' )) {
346+ return ;
347+ }
348+ event .preventDefault ();
349+ updateDragging (event .targetTouches [0 ].clientX );
350+ };
351+
352+ function updateDragging (currentX ) {
353+ if (! isDragging .value ) return ;
354+
355+ const deltaX = currentX - initialMouseX .value ;
356+
357+ if (Math .abs (deltaX) > dragThreshold .value ) {
358+ if (deltaX > 0 ) {
359+ if (Number (endValue .value ) + 1 <= props .max ) {
360+ const v = Number (endValue .value ) + 1 ;
361+ setEndValue (v);
362+ setStartValue (v - currentRange .value );
363+ }
364+ } else {
365+ if (Number (startValue .value ) - 1 >= props .min ) {
366+ const v = Number (startValue .value ) - 1 ;
367+ setStartValue (v);
368+ setEndValue (v + currentRange .value );
369+ }
370+ }
371+ initialMouseX .value = currentX;
372+ }
373+ };
374+
375+ function stopDragging () {
376+ endDragging (' mousemove' , ' mouseup' );
377+ };
378+
379+ function stopTouchDragging () {
380+ endDragging (' touchmove' , ' touchend' );
381+ };
382+
383+ function endDragging (moveEvent , endEvent ) {
384+ isDragging .value = false ;
385+ window .removeEventListener (moveEvent, handleDragging);
386+ window .removeEventListener (endEvent, stopDragging);
387+ };
388+
299389defineExpose ({
300390 setStartValue,
301391 setEndValue
@@ -304,7 +394,14 @@ defineExpose({
304394 </script >
305395
306396<template >
307- <div data-html2canvas-ignore data-cy =" slicer" style =" padding : 0 24px " class =" vue-data-ui-zoom" >
397+ <div
398+ data-html2canvas-ignore data-cy =" slicer"
399+ style =" padding : 0 24px "
400+ class =" vue-data-ui-zoom"
401+ ref =" zoomWrapper"
402+ @mousedown =" startDragging"
403+ @touchstart =" startDragging"
404+ >
308405 <div class =" vue-data-ui-slicer-labels" style =" position : relative ; z-index : 1 ; pointer-events : none ;" >
309406 <div v-if =" valueStart !== refreshStartPoint || valueEnd !== endpoint" style =" width : 100% ; position : relative " >
310407 <button
@@ -443,19 +540,44 @@ defineExpose({
443540 :width =" unitWidthX < 0 ? 0 : unitWidthX"
444541 fill =" transparent"
445542 style =" pointer-events : all !important ;"
543+ :style =" {
544+ cursor: trap >= valueStart && trap < valueEnd && enableSelectionDrag ? 'move' : 'default',
545+ }"
446546 @mouseenter =" trapMouse(trap)"
447547 @mouseleave =" selectedTrap = null; emit('trapMouse', null)"
448548 />
449549 </svg >
450550 </div >
451551 </template >
452552 <div class =" slider-track" ></div >
453- <div class =" range-highlight" :style =" highlightStyle" ></div >
454- <input ref =" rangeStart" :key =" `range-min${inputStep}`" type =" range" class =" range-left" :min =" min" :max =" max" v-model =" startValue" @input =" onStartInput" />
553+ <div :class =" {
554+ 'range-highlight': true,
555+ 'move': enableSelectionDrag
556+ }" :style =" highlightStyle" ></div >
557+ <input
558+ v-if =" enableRangeHandles"
559+ ref =" rangeStart"
560+ :key =" `range-min${inputStep}`"
561+ type =" range"
562+ class =" range-left range-handle"
563+ :min =" min"
564+ :max =" max"
565+ v-model =" startValue"
566+ @input =" onStartInput"
567+ />
455568 <div class =" thumb-label thumb-label-left" :style =" leftLabelPosition" >
456569 {{ labelLeft }}
457570 </div >
458- <input ref =" rangeEnd" type =" range" class =" range-right" :min =" min" :max =" max" v-model =" endValue" @input =" onEndInput" />
571+ <input
572+ v-if =" enableRangeHandles"
573+ ref =" rangeEnd"
574+ type =" range"
575+ class =" range-right range-handle"
576+ :min =" min"
577+ :max =" max"
578+ v-model =" endValue"
579+ @input =" onEndInput"
580+ />
459581 <div class =" thumb-label thumb-label-right" :style =" rightLabelPosition" >
460582 {{ labelRight }}
461583 </div >
@@ -571,6 +693,10 @@ input[type="range"]::-ms-thumb {
571693 border-radius : 4px ;
572694}
573695
696+ .move {
697+ cursor : move ;
698+ }
699+
574700.vue-data-ui-refresh-button {
575701 position : absolute ;
576702 left : 50% ;
0 commit comments