Skip to content

Commit 4a0be0b

Browse files
committed
Atoms - Slicer - Improve design with tooltips above range handles
1 parent eb61e3f commit 4a0be0b

File tree

1 file changed

+160
-12
lines changed

1 file changed

+160
-12
lines changed

src/atoms/Slicer.vue

Lines changed: 160 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<script setup>
2-
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue';
2+
import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick, onUpdated } from 'vue';
33
import BaseIcon from './BaseIcon.vue';
44
import { useResponsive } from '../useResponsive';
55
import { throttle } from '../canvas-lib';
6-
import { XMLNS, createSmoothPath, createStraightPath, createUid } from '../lib';
6+
import { XMLNS, adaptColorToBackground, createSmoothPath, createStraightPath, createUid } from '../lib';
77
88
const props = defineProps({
99
background: {
@@ -128,13 +128,28 @@ const highlightStyle = computed(() => {
128128
const range = props.max - props.min;
129129
const startPercent = ((startValue.value - props.min) / range) * 100;
130130
const endPercent = ((endValue.value - props.min) / range) * 100;
131+
131132
return {
132133
left: `${startPercent}%`,
133134
width: `${endPercent - startPercent}%`,
134-
background: props.selectColor
135+
background: props.selectColor,
136+
tooltipLeft: `calc(${startPercent}% - ${overflowsLeft.value ? 0 : tooltipLeftWidth.value / 2}px)`,
137+
tooltipRight: `calc(${endPercent}% - ${overflowsRight.value ? tooltipRightWidth.value : tooltipRightWidth.value / 2}px)`,
138+
arrowLeft: !overflowsLeft.value,
139+
arrowRight: !overflowsRight.value
135140
};
136141
});
137142
143+
const overflowsLeft = computed(() => {
144+
if (!zoomWrapper.value) return false;
145+
return zoomWrapper.value.getBoundingClientRect().width * ((startValue.value - props.min) / (props.max - props.min)) - tooltipLeftWidth.value / 2 < 0
146+
});
147+
148+
const overflowsRight = computed(() => {
149+
if (!zoomWrapper.value) return false;
150+
return zoomWrapper.value.getBoundingClientRect().width * ((endValue.value - props.min) / (props.max - props.min)) + tooltipRightWidth.value / 2 > zoomWrapper.value.getBoundingClientRect().width;
151+
})
152+
138153
const slicerColor = computed(() => props.inputColor);
139154
const backgroundColor = computed(() => props.background);
140155
const selectColorOpaque = computed(() => `${props.selectColor}33`);
@@ -336,6 +351,7 @@ const flooredDatapointsToWidth = computed(() => {
336351
})
337352
338353
const startDragging = (event) => {
354+
showTooltip.value = true;
339355
if (!props.enableSelectionDrag) {
340356
return;
341357
}
@@ -408,6 +424,39 @@ function endDragging(moveEvent, endEvent) {
408424
window.removeEventListener(endEvent, stopDragging);
409425
};
410426
427+
const isMouseDown = ref(false)
428+
const tooltipLeft = ref(null);
429+
const tooltipRight = ref(null);
430+
const tooltipLeftWidth = ref(1);
431+
const tooltipRightWidth = ref(1);
432+
const showTooltip = ref(false);
433+
434+
function setTooltipLeft() {
435+
if(tooltipLeft.value) {
436+
tooltipLeftWidth.value = tooltipLeft.value.getBoundingClientRect().width;
437+
}
438+
}
439+
440+
function setTooltipRight() {
441+
if (tooltipRight.value) {
442+
tooltipRightWidth.value = tooltipRight.value.getBoundingClientRect().width;
443+
}
444+
}
445+
446+
onUpdated(() => {
447+
setTooltipLeft();
448+
setTooltipRight();
449+
})
450+
451+
watch(() => props.labelLeft, () => {
452+
nextTick(setTooltipLeft);
453+
}, { deep: true });
454+
455+
watch(() => props.labelRight, () => {
456+
nextTick(setTooltipRight);
457+
}, { deep: true });
458+
459+
411460
defineExpose({
412461
setStartValue,
413462
setEndValue
@@ -423,6 +472,7 @@ defineExpose({
423472
ref="zoomWrapper"
424473
@mousedown="startDragging"
425474
@touchstart="startDragging"
475+
@touchend="showTooltip = false"
426476
>
427477
<div class="vue-data-ui-slicer-labels" style="position: relative; z-index: 1; pointer-events: none;">
428478
<div v-if="valueStart !== refreshStartPoint || valueEnd !== endpoint" style="width: 100%; position: relative">
@@ -442,7 +492,7 @@ defineExpose({
442492
</div>
443493
</div>
444494

445-
<div class="double-range-slider" ref="minimapWrapper" style="z-index: 0">
495+
<div class="double-range-slider" ref="minimapWrapper" style="z-index: 0" @mouseenter="showTooltip = true" @mouseleave="showTooltip = false">
446496
<template v-if="hasMinimap">
447497
<div class="minimap" style="width: 100%" data-cy="minimap">
448498
<svg :xmlns="XMLNS" :viewBox="`0 0 ${svgMinimap.width < 0 ? 0 : svgMinimap.width} ${svgMinimap.height < 0 ? 0 : svgMinimap.height}`">
@@ -563,19 +613,30 @@ defineExpose({
563613
fill="transparent"
564614
style="pointer-events: all !important;"
565615
:style="{
566-
cursor: trap >= valueStart && trap < valueEnd && enableSelectionDrag ? 'move' : 'default',
616+
cursor: trap >= valueStart && trap < valueEnd && enableSelectionDrag ? isMouseDown ? 'grabbing' : 'grab' : 'default',
567617
}"
618+
@mousedown="isMouseDown = true"
619+
@mouseup="isMouseDown = false"
568620
@mouseenter="trapMouse(trap)"
569621
@mouseleave="selectedTrap = null; emit('trapMouse', null)"
570622
/>
571623
</svg>
572624
</div>
573625
</template>
574626
<div class="slider-track"></div>
575-
<div :class="{
576-
'range-highlight': true,
577-
'move': enableSelectionDrag
578-
}" :style="highlightStyle"></div>
627+
<div
628+
:class="{
629+
'range-highlight': true,
630+
'move': enableSelectionDrag
631+
}"
632+
@mousedown="isMouseDown = true"
633+
@mouseup="isMouseDown = false"
634+
:style="{
635+
...highlightStyle,
636+
cursor: isMouseDown ? 'grabbing' : 'grab'
637+
}"
638+
/>
639+
579640
<input
580641
v-if="enableRangeHandles"
581642
ref="rangeStart"
@@ -587,9 +648,9 @@ defineExpose({
587648
v-model="startValue"
588649
@input="onStartInput"
589650
/>
590-
<div class="thumb-label thumb-label-left" :style="leftLabelPosition">
651+
<!-- <div class="thumb-label thumb-label-left" :style="leftLabelPosition">
591652
{{ labelLeft }}
592-
</div>
653+
</div> -->
593654
<input
594655
v-if="enableRangeHandles"
595656
ref="rangeEnd"
@@ -600,7 +661,43 @@ defineExpose({
600661
v-model="endValue"
601662
@input="onEndInput"
602663
/>
603-
<div class="thumb-label thumb-label-right" :style="rightLabelPosition">
664+
<!-- <div class="thumb-label thumb-label-right" :style="rightLabelPosition">
665+
{{ labelRight }}
666+
</div> -->
667+
<div
668+
v-if="labelLeft"
669+
ref="tooltipLeft"
670+
:class="{
671+
'range-tooltip': true,
672+
'range-tooltip-visible': showTooltip,
673+
'range-tooltip-arrow': highlightStyle.arrowLeft && !verticalHandles,
674+
'range-tooltip-arrow-left': !highlightStyle.arrowLeft && !verticalHandles
675+
}"
676+
:style="{
677+
left: highlightStyle.tooltipLeft,
678+
color: adaptColorToBackground(selectColor),
679+
backgroundColor: selectColor,
680+
border: `1px solid ${borderColor}`
681+
}"
682+
>
683+
{{ labelLeft }}
684+
</div>
685+
<div
686+
v-if="labelRight"
687+
ref="tooltipRight"
688+
:class="{
689+
'range-tooltip': true,
690+
'range-tooltip-visible': showTooltip,
691+
'range-tooltip-arrow': highlightStyle.arrowRight && !verticalHandles,
692+
'range-tooltip-arrow-right': !highlightStyle.arrowRight && !verticalHandles
693+
}"
694+
:style="{
695+
left: highlightStyle.tooltipRight,
696+
color: adaptColorToBackground(selectColor),
697+
backgroundColor: selectColor,
698+
border: `1px solid ${borderColor}`
699+
}"
700+
>
604701
{{ labelRight }}
605702
</div>
606703
</div>
@@ -787,4 +884,55 @@ input[type="range"]::-ms-thumb {
787884
width: 1px;
788885
white-space: nowrap;
789886
}
887+
888+
.range-tooltip {
889+
z-index: 4;
890+
padding: 2px 4px;
891+
font-size: 10px;
892+
border-radius: 3px;
893+
opacity: 0;
894+
transition: opacity 0.3s ease-in-out;
895+
text-align:center;
896+
pointer-events: none;
897+
position: absolute;
898+
top: -100%;
899+
width: fit-content;
900+
}
901+
902+
.range-tooltip-arrow,
903+
.range-tooltip-arrow-left,
904+
.range-tooltip-arrow-right {
905+
&::after {
906+
content: '';
907+
position: absolute;
908+
top: 100%;
909+
border-width: 4px;
910+
border-style: solid;
911+
border-color: v-bind(selectColor) transparent transparent transparent;
912+
}
913+
}
914+
915+
.range-tooltip-arrow {
916+
&::after {
917+
left: 50%;
918+
transform: translateX(-50%);
919+
}
920+
}
921+
922+
.range-tooltip-arrow-left {
923+
&::after {
924+
left: 3px;
925+
}
926+
}
927+
928+
.range-tooltip-arrow-right {
929+
&::after {
930+
right: 3px;
931+
}
932+
}
933+
934+
.range-tooltip-visible {
935+
opacity: 1;
936+
transition: opacity 0.3s ease-in-out;
937+
}
790938
</style>

0 commit comments

Comments
 (0)