noUiSlider
noUiSlider copied to clipboard
Feature: update for merge tooltip function
Hello! Thank you for a good slider!
I needed to merge sliders if they overlapped and found a function in the documentation (https://refreshless.com/nouislider/examples/#section-merging-tooltips) that could help me achieve this. However, I had to set a hardcoded minimum proximity, which was not ideal since my tooltips have different sizes.
To address this issue, I updated the script for merging tooltips. Here's the code I used:
/**
* @param slider HtmlElement with an initialized slider
* @param separator String joining tooltips
*/
export function mergeTooltips(slider, separator) {
var textIsRtl = window.getComputedStyle(slider).direction === "rtl";
var isRtl = slider.noUiSlider.options.direction === "rtl";
var isVertical = slider.noUiSlider.options.orientation === "vertical";
var tooltips = slider.noUiSlider.getTooltips();
var origins = slider.noUiSlider.getOrigins();
// Move tooltips into the origin element. The default stylesheet handles this.
tooltips.forEach(function (tooltip, index) {
if (tooltip) {
origins[index].appendChild(tooltip);
}
});
slider.noUiSlider.on("update", function (
values,
handle,
unencoded,
tap,
positions
) {
var pools = [[]];
var poolPositions = [[]];
var poolValues = [[]];
var atPool = 0;
// Assign the first tooltip to the first pool, if the tooltip is configured
if (tooltips[0]) {
pools[0][0] = 0;
poolPositions[0][0] = positions[0];
poolValues[0][0] = values[0];
}
for (var i = 1; i < positions.length; i++) {
// HERE's MY CODE
const tooltipLeft = tooltips[i - 1].getBoundingClientRect();
const tooltipRight = tooltips[i].getBoundingClientRect();
if (
!(
tooltipLeft.x < tooltipRight.x &&
tooltipLeft.x + tooltipLeft.width > tooltipRight.x
)
) {
atPool++;
pools[atPool] = [];
poolValues[atPool] = [];
poolPositions[atPool] = [];
}
// HERE's MY CODE END
if (tooltips[i]) {
pools[atPool].push(i);
poolValues[atPool].push(values[i]);
poolPositions[atPool].push(positions[i]);
}
}
pools.forEach(function (pool, poolIndex) {
var handlesInPool = pool.length;
for (var j = 0; j < handlesInPool; j++) {
var handleNumber = pool[j];
if (j === handlesInPool - 1) {
var offset = 0;
poolPositions[poolIndex].forEach(function (value) {
offset += 1000 - value;
});
var direction = isVertical ? "bottom" : "right";
var last = isRtl ? 0 : handlesInPool - 1;
var lastOffset = 1000 - poolPositions[poolIndex][last];
offset =
(textIsRtl && !isVertical ? 100 : 0) +
offset / handlesInPool -
lastOffset;
// Center this tooltip over the affected handles
tooltips[handleNumber].innerHTML = poolValues[poolIndex].join(
separator
);
tooltips[handleNumber].style.removeProperty("visibility");
tooltips[handleNumber].style[direction] = offset + "%";
} else {
// Hide this tooltip
tooltips[handleNumber].style.visibility = "hidden";
}
}
});
});
}
My approach uses tooltip position and widths to determine which tooltips need to be merged, which I believe is an improvement over a hardcoded percentage.
Thank you for taking the time to read my issue and for any feedback you may have.
Thanks for your feedback! If you want to generalize the example in the documentation, I'd be open for a PR :)
@leongersen Of course, here is it! https://github.com/leongersen/noUiSlider/pull/1256
@leongersen Hello! Just remind you about the PR!
@leongersen Hi! Please take a look at the changed docs in this PR!