Skip to content

Commit f866b56

Browse files
committed
Slicer - Improve minimap
1 parent a40f16d commit f866b56

File tree

1 file changed

+111
-43
lines changed

1 file changed

+111
-43
lines changed

src/atoms/Slicer.vue

Lines changed: 111 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ const props = defineProps({
8181
minimapSelectedColorOpacity: {
8282
type: Number,
8383
default: 0.2
84+
},
85+
minimapSelectedIndex: {
86+
type: Number,
87+
default: null
88+
},
89+
minimapIndicatorColor: {
90+
type: String,
91+
default: '#2D353C'
8492
}
8593
});
8694
@@ -89,7 +97,7 @@ const endValue = ref(props.max);
8997
const hasMinimap = computed(() => !!props.minimap.length);
9098
const uid = ref(createUid());
9199
92-
const emit = defineEmits(['update:start', 'update:end', 'reset']);
100+
const emit = defineEmits(['update:start', 'update:end', 'reset', 'trapMouse']);
93101
94102
const highlightStyle = computed(() => {
95103
const range = props.max - props.min;
@@ -107,6 +115,14 @@ const backgroundColor = computed(() => props.background);
107115
const selectColorOpaque = computed(() => `${props.selectColor}33`);
108116
const borderColor = computed(() => props.borderColor);
109117
118+
const availableTraps = computed(() => {
119+
let arr = [];
120+
for (let i = 0; i < props.minimap.length; i += 1) {
121+
arr.push(i)
122+
}
123+
return arr;
124+
})
125+
110126
function reset() {
111127
emit('reset');
112128
}
@@ -175,16 +191,9 @@ onMounted(() => {
175191
176192
const unitWidthX = computed(() => {
177193
if(!props.minimap.length) return 0
178-
return svgMinimap.value.width / props.minimap.length;
194+
return svgMinimap.value.width / props.minimap.length
179195
});
180196
181-
const selectedMap = computed(() => {
182-
return {
183-
x: unitWidthX.value * props.valueStart,
184-
width: unitWidthX.value * (props.valueEnd - props.valueStart)
185-
}
186-
})
187-
188197
const minimapLine = computed(() => {
189198
if(!props.minimap.length) return [];
190199
const max = Math.max(...props.minimap);
@@ -193,7 +202,7 @@ const minimapLine = computed(() => {
193202
const points = props.minimap.map((dp, i) => {
194203
const normalizedVal = dp - min;
195204
return {
196-
x: svgMinimap.value.width / (props.minimap.length - 1) * (i),
205+
x: svgMinimap.value.width / (props.minimap.length) * (i) + (unitWidthX.value / 2),
197206
y: svgMinimap.value.height - (normalizedVal / diff * (svgMinimap.value.height * 0.9))
198207
}
199208
});
@@ -208,12 +217,10 @@ const minimapLine = computed(() => {
208217
}
209218
});
210219
211-
const range = computed(() => props.max - props.min)
212-
213-
const selectionRect = computed(() => {
220+
const selectionRectCoordinates = computed(() => {
214221
return {
215-
left: ((startValue.value - props.min) / range.value) * 100,
216-
width: ((endValue.value - startValue.value) / range.value) * 100
222+
x: unitWidthX.value * startValue.value + (unitWidthX.value / 2),
223+
width: svgMinimap.value.width * ((endValue.value - startValue.value) / props.max) - unitWidthX.value
217224
}
218225
})
219226
@@ -238,26 +245,42 @@ const rightLabelPosition = computed(() => {
238245
};
239246
});
240247
248+
249+
const selectedTrap = ref(props.minimapSelectedIndex)
250+
251+
watch(() => props.minimapSelectedIndex, (v) => {
252+
selectedTrap.value = v + props.valueStart
253+
}, { immediate: true })
254+
255+
function trapMouse(trap) {
256+
selectedTrap.value = trap;
257+
if (trap >= props.valueStart && trap < props.valueEnd) {
258+
emit('trapMouse', trap - props.valueStart)
259+
}
260+
}
261+
241262
</script>
242263

243264
<template>
244265
<div data-html2canvas-ignore style="padding: 0 24px">
245-
<div class="vue-data-ui-slicer-labels" style="position: relative; z-index: 1">
266+
<div class="vue-data-ui-slicer-labels" style="position: relative; z-index: 1; pointer-events: none;">
246267
<div v-if="valueStart > 0 || valueEnd < max" style="width: 100%; position: relative">
247268
<button
248269
v-if="!useResetSlot"
249270
data-cy-reset tabindex="0"
250271
role="button"
251272
class="vue-data-ui-refresh-button"
252273
:style="{
253-
top: hasMinimap ? '36px' : '-16px'
274+
top: hasMinimap ? '36px' : '-16px',
275+
pointerEvents: 'all !important'
254276
}"
255277
@click="reset">
256278
<BaseIcon name="refresh" :stroke="textColor" />
257279
</button>
258280
<slot v-else name="reset-action" :reset="reset" />
259281
</div>
260282
</div>
283+
261284
<div class="double-range-slider" ref="minimapWrapper" style="z-index: 0">
262285
<template v-if="hasMinimap">
263286
<div class="minimap" style="width: 100%">
@@ -268,17 +291,48 @@ const rightLabelPosition = computed(() => {
268291
<stop offset="100%" stop-color="transparent"/>
269292
</linearGradient>
270293
</defs>
294+
271295
<path
272-
:d="`M0,${svgMinimap.height} ${minimapLine.fullSet} L${svgMinimap.width},${svgMinimap.height}Z`"
296+
:d="`M${minimapLine.fullSet}`"
273297
:stroke="`${minimapLineColor}`"
274-
:fill="`url(#${uid})`"
298+
fill="none"
275299
stroke-width="1"
276300
stroke-linecap="round"
277301
stroke-linejoin="round"
278302
style="opacity: 1"
279303
/>
304+
305+
<!-- SELECTION RECT -->
306+
<rect
307+
:x="selectionRectCoordinates.x"
308+
:width="selectionRectCoordinates.width < 0 ? 0 : selectionRectCoordinates.width"
309+
:height="svgMinimap.height"
310+
:y="0"
311+
:fill="borderColor"
312+
:rx="minimapSelectionRadius"
313+
stroke="none"
314+
/>
315+
316+
<path
317+
:d="`M${unitWidthX / 2},${svgMinimap.height} ${minimapLine.fullSet} L${svgMinimap.width - (unitWidthX / 2)},${svgMinimap.height}Z`"
318+
:fill="`url(#${uid})`"
319+
stroke="none"
320+
style="opacity: 1"
321+
/>
322+
323+
<rect
324+
:x="selectionRectCoordinates.x"
325+
:width="selectionRectCoordinates.width < 0 ? 0 : selectionRectCoordinates.width"
326+
:height="svgMinimap.height"
327+
:y="0"
328+
:fill="minimapSelectedColor"
329+
:style="{
330+
opacity: minimapSelectedColorOpacity
331+
}"
332+
/>
333+
280334
<!-- This is not quite there yet: there's an annoying offset between input handles and plots -->
281-
<!-- <path
335+
<path
282336
:d="`M ${minimapLine.selectionSet}`"
283337
:stroke="`${minimapLineColor}`"
284338
fill="transparent"
@@ -301,34 +355,47 @@ const rightLabelPosition = computed(() => {
301355
:stroke="borderColor"
302356
r="3"
303357
:fill="minimapLineColor"
304-
/> -->
305-
<line :x1="0" :x2="svgMinimap.width < 0 ? 0 : svgMinimap.width" :y1="(svgMinimap.height < 0 ? 0 : svgMinimap.height)" :y2="(svgMinimap.height < 0 ? 0 : svgMinimap.height)" :stroke="borderColor" stroke-width="3"/>
306-
<line :x1="0" :x2="0" :y1="0" :y2="svgMinimap.height < 0 ? 0 : svgMinimap.height" :stroke="borderColor" stroke-width="5"/>
307-
<line :x1="svgMinimap.width < 0 ? 0 : svgMinimap.width" :x2="svgMinimap.width < 0 ? 0 : svgMinimap.width" :y1="0" :y2="svgMinimap.height < 0 ? 0 : svgMinimap.height" :stroke="borderColor" stroke-width="5"/>
358+
/>
359+
360+
<!-- SELECTION INDICATOR -->
361+
<template v-if="selectedTrap !== null">
362+
<g v-for="(trap, i) in availableTraps">
363+
<line
364+
:x1="unitWidthX * i + (unitWidthX / 2)"
365+
:x2="unitWidthX * i + (unitWidthX / 2)"
366+
:y1="0"
367+
:y2="svgMinimap.height"
368+
:stroke="minimapIndicatorColor"
369+
stroke-linecap="round"
370+
stroke-dasharray="2"
371+
stroke-width="1"
372+
v-if="selectedTrap === trap && trap >= valueStart && trap < valueEnd"
373+
/>
374+
</g>
375+
</template>
376+
377+
<!-- TOOLTIP TRAPS -->
378+
<rect
379+
v-for="(trap, i) in availableTraps"
380+
:x="unitWidthX * i"
381+
:y="0"
382+
:height="svgMinimap.height"
383+
:width="unitWidthX"
384+
fill="transparent"
385+
style="pointer-events: all !important;"
386+
@mouseenter="trapMouse(trap)"
387+
@mouseleave="selectedTrap = null; emit('trapMouse', null)"
388+
/>
308389
</svg>
309390
</div>
310-
<div
311-
class="sel"
312-
:style="{
313-
position: 'absolute',
314-
top: '-33px',
315-
left: `calc(${selectionRect.left}%)`,
316-
background: minimapSelectedColor,
317-
height: '40px',
318-
width: selectionRect.width + '%',
319-
borderRadius: `${minimapSelectionRadius}px ${minimapSelectionRadius}px 0 0`,
320-
opacity: minimapSelectedColorOpacity
321-
}"
322-
/>
323391
</template>
324-
325392
<div class="slider-track"></div>
326393
<div class="range-highlight" :style="highlightStyle"></div>
327-
<input type="range" :min="min" :max="max" v-model="startValue" @input="onStartInput" />
394+
<input type="range" class="range-left" :min="min" :max="max" v-model="startValue" @input="onStartInput" />
328395
<div class="thumb-label thumb-label-left" :style="leftLabelPosition">
329396
{{ labelLeft }}
330397
</div>
331-
<input type="range" :min="min" :max="max" v-model="endValue" @input="onEndInput" />
398+
<input type="range" class="range-right" :min="min" :max="max" v-model="endValue" @input="onEndInput" />
332399
<div class="thumb-label thumb-label-right" :style="rightLabelPosition">
333400
{{ labelRight }}
334401
</div>
@@ -359,8 +426,9 @@ const rightLabelPosition = computed(() => {
359426
360427
input[type="range"] {
361428
position: absolute;
362-
left: 0;
363-
width: 100%;
429+
left: -10px;
430+
width: calc(100% + 17px);
431+
right: 3px;
364432
appearance: none;
365433
background: transparent;
366434
pointer-events: none;
@@ -471,7 +539,7 @@ input[type="range"]::-ms-thumb {
471539
display: flex;
472540
flex-direction: row;
473541
align-items: center;
474-
padding: 0 24px;
542+
// padding: 0 24px;
475543
height: 40px;
476544
}
477545

0 commit comments

Comments
 (0)