11<script setup>
2- import { ref , computed , watch , onMounted , onBeforeUnmount , nextTick , onUpdated } from ' vue' ;
3- import BaseIcon from ' ./BaseIcon.vue' ;
4- import { useResponsive } from ' ../useResponsive' ;
2+ import {
3+ computed ,
4+ nextTick ,
5+ onBeforeUnmount ,
6+ onMounted ,
7+ onUpdated ,
8+ ref ,
9+ watch ,
10+ } from ' vue' ;
11+ import {
12+ adaptColorToBackground ,
13+ createSmoothPath ,
14+ createStraightPath ,
15+ createUid ,
16+ XMLNS ,
17+ } from ' ../lib' ;
518import { throttle } from ' ../canvas-lib' ;
6- import { XMLNS , adaptColorToBackground , createSmoothPath , createStraightPath , createUid } from ' ../lib' ;
19+ import { useResponsive } from ' ../useResponsive' ;
20+ import BaseIcon from ' ./BaseIcon.vue' ;
721
822const props = defineProps ({
923 background: {
@@ -355,13 +369,23 @@ const selectionWidth = computed(() => {
355369 return ((wrapperWidth .value - 48 ) / (props .max - props .min )) * currentRange .value ;
356370});
357371
358- const RA_SPECIAL_MAGIC_NUMBER = ref (2.5 );
372+ const TRACK_PADDING = 48 ;
373+
374+ const usablePx = computed (() => {
375+ return Math .max (1 , wrapperWidth .value - TRACK_PADDING - selectionWidth .value );
376+ });
359377
360- const flooredDatapointsToWidth = computed (() => {
361- const w = wrapperWidth .value - 48 ;
362- return Math .ceil ((props .max - props .min ) / ((w - selectionWidth .value ) / RA_SPECIAL_MAGIC_NUMBER .value ));
378+ const usableSteps = computed (() => {
379+ return Math .max (1 , (props .max - props .min ) - currentRange .value );
363380});
364381
382+ const indicesPerPixel = computed (() => usableSteps .value / usablePx .value );
383+
384+ const dragStartX = ref (0 );
385+ const dragStartStart = ref (0 );
386+ const dragStartEnd = ref (0 );
387+ const ippAtStart = ref (0 );
388+
365389let activeMoveEvent = null ;
366390let activeEndEvent = null ;
367391let activeMoveHandler = null ;
@@ -372,28 +396,30 @@ const startDragging = (event) => {
372396 if (! props .enableSelectionDrag ) return ;
373397
374398 const isTouch = event .type === ' touchstart' ;
399+ if (! isTouch) event .stopPropagation ();
375400
376- if (! isTouch) {
377- event .stopPropagation ();
378- }
379-
380- const touch0 =
381- isTouch && event .targetTouches && event .targetTouches [0 ] ? event .targetTouches [0 ] : null ;
401+ const touch0 = isTouch && event .targetTouches && event .targetTouches [0 ] ? event .targetTouches [0 ] : null ;
382402 const target = isTouch ? (touch0 ? touch0 .target : null ) : event .target ;
383403
384404 if (! target || ! (target instanceof Element )) return ;
385405 if (target .classList && target .classList .contains (' range-handle' )) return ;
386406
387407 isDragging .value = true ;
388- initialMouseX .value = isTouch ? (touch0 ? touch0 .clientX : 0 ) : event .clientX ;
389408
390- activeMoveEvent = isTouch ? ' touchmove' : ' mousemove' ;
391- activeEndEvent = isTouch ? ' touchend' : ' mouseup' ;
409+ const x = isTouch ? (touch0 ? touch0 .clientX : 0 ) : event .clientX ;
410+ initialMouseX .value = x;
411+ dragStartX .value = x;
412+ dragStartStart .value = Number (startValue .value );
413+ dragStartEnd .value = Number (endValue .value );
414+ ippAtStart .value = indicesPerPixel .value ;
415+
416+ activeMoveEvent = isTouch ? ' touchmove' : ' mousemove' ;
417+ activeEndEvent = isTouch ? ' touchend' : ' mouseup' ;
392418 activeMoveHandler = isTouch ? handleTouchDragging : handleDragging;
393- activeEndHandler = isTouch ? stopTouchDragging : stopDragging;
419+ activeEndHandler = isTouch ? stopTouchDragging : stopDragging;
394420
395421 window .addEventListener (activeMoveEvent, activeMoveHandler, { passive: false });
396- window .addEventListener (activeEndEvent, activeEndHandler);
422+ window .addEventListener (activeEndEvent, activeEndHandler);
397423};
398424
399425function handleDragging (event ) {
@@ -420,27 +446,14 @@ function handleTouchDragging(event) {
420446
421447function updateDragging (currentX ) {
422448 if (! isDragging .value ) return ;
423-
424- const deltaX = currentX - initialMouseX .value ;
425-
426- if (Math .abs (deltaX) > dragThreshold .value ) {
427- if (deltaX > 0 ) {
428- if (Number (endValue .value ) + 1 <= props .max ) {
429- const v = Math .min (props .max , Number (endValue .value ) + flooredDatapointsToWidth .value );
430- setEndValue (v);
431- setStartValue (v - currentRange .value );
432- }
433- } else {
434- if (Number (startValue .value ) - 1 >= props .min ) {
435- const v = Math .max (props .min , Number (startValue .value ) - flooredDatapointsToWidth .value );
436- setStartValue (v);
437- setEndValue (v + currentRange .value );
438- }
439- }
440- initialMouseX .value = currentX;
441- }
449+ const dx = currentX - dragStartX .value ;
450+ const shift = dx * ippAtStart .value ;
451+ let newStart = Math .round (dragStartStart .value + shift);
452+ newStart = Math .max (props .min , Math .min (newStart, props .max - currentRange .value ));
453+ const newEnd = newStart + currentRange .value ;
454+ setStartValue (newStart);
455+ setEndValue (newEnd);
442456}
443-
444457function stopDragging () {
445458 endDragging ();
446459}
@@ -571,28 +584,49 @@ onBeforeUnmount(() => {
571584 @touchstart =" startDragging"
572585 @touchend =" showTooltip = false"
573586 >
574- <div class =" vue-data-ui-slicer-labels" style =" position : relative ; z-index : 1 ; pointer-events : none ;" >
575- <div v-if =" valueStart !== refreshStartPoint || valueEnd !== endpoint" style =" width : 100% ; position : relative " >
587+ <div
588+ class =" vue-data-ui-slicer-labels"
589+ style =" position : relative ; z-index : 1 ; pointer-events : none ;"
590+ >
591+ <div
592+ v-if =" valueStart !== refreshStartPoint || valueEnd !== endpoint"
593+ style =" width : 100% ; position : relative "
594+ >
576595 <button
577596 v-if =" !useResetSlot"
578- data-cy =" slicer-reset" tabindex =" 0"
597+ data-cy =" slicer-reset"
598+ tabindex =" 0"
579599 role =" button"
580600 class =" vue-data-ui-refresh-button"
581601 :style =" {
582602 top: hasMinimap ? '36px' : '-16px',
583603 pointerEvents: 'all !important'
584604 }"
585- @click =" reset" >
605+ @click =" reset"
606+ >
586607 <BaseIcon name =" refresh" :stroke =" textColor" />
587608 </button >
588609 <slot v-else name =" reset-action" :reset =" reset" />
589610 </div >
590611 </div >
591612
592- <div class =" double-range-slider" ref =" minimapWrapper" style =" z-index : 0 " @mouseenter =" showTooltip = true" @mouseleave =" showTooltip = false" >
613+ <div
614+ class =" double-range-slider"
615+ ref =" minimapWrapper"
616+ style =" z-index : 0 "
617+ @mouseenter =" showTooltip = true"
618+ @mouseleave =" showTooltip = false"
619+ >
593620 <template v-if =" hasMinimap " >
594- <div class =" minimap" style =" width : 100% " data-cy =" minimap" >
595- <svg data-cy =" slicer-minimap-svg" :xmlns =" XMLNS" :viewBox =" `0 0 ${svgMinimap.width < 0 ? 0 : svgMinimap.width} ${svgMinimap.height < 0 ? 0 : svgMinimap.height}`" >
621+ <div
622+ class =" minimap"
623+ style =" width : 100% " data-cy =" minimap"
624+ >
625+ <svg
626+ data-cy =" slicer-minimap-svg"
627+ :xmlns =" XMLNS"
628+ :viewBox =" `0 0 ${svgMinimap.width < 0 ? 0 : svgMinimap.width} ${svgMinimap.height < 0 ? 0 : svgMinimap.height}`"
629+ >
596630 <defs >
597631 <linearGradient :id =" uid" x1 =" 0%" y1 =" 0%" x2 =" 0%" y2 =" 100%" >
598632 <stop offset =" 0%" :stop-color =" `${minimapLineColor}50`" />
0 commit comments