From 9e9e65720c632e6c53a288f780d1df99b3117897 Mon Sep 17 00:00:00 2001 From: simeydotme Date: Wed, 20 Jan 2021 00:06:16 +0800 Subject: [PATCH] bugfixes: previousValue, double events, handle overrun - fix a bug where `previousValue` was incorrectly set as `startValue` during change event when `previousValue` was `0` - fix a bug where if the handle was moved past the min/max then `values` would momentarily be set wrong, causing errors when bound with other sliders or `{each}` statements - reduce the amount of events/calls when changing values by setting `alignValueToStep()` as values are set, instead of read - add `startValue` in the `change` event - improve some comments, i must have been in a dream when i wrote those - edit some whitespace --- README.md | 2 +- dist/svelte-range-slider-pips.js | 56 +++++++++++++++---------- dist/svelte-range-slider-pips.mjs | 56 +++++++++++++++---------- package.json | 2 +- src/RangeSlider.svelte | 68 ++++++++++++++++++------------- test/package.json | 2 +- test/src/App.svelte | 23 ++++++++++- 7 files changed, 131 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index c58e7f5..5ccc0c3 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ prop | type | default | description event | example | `event.detail` | description ------|------------|--------|------------- **start** | `on:start={(e) => { ... }}` | `{ activeHandle: Integer, value: Float, values: Array }` | Event fired when the user begins interaction with the slider -**change** | `on:change={(e) => { ... }}` | `{ activeHandle: Integer, previousValue: Float, value: Float, values: Array }` | Event fired when the user changes the value; returns the previous value, also +**change** | `on:change={(e) => { ... }}` | `{ activeHandle: Integer, startValue: Float, previousValue: Float, value: Float, values: Array }` | Event fired when the user changes the value; returns the previous value, also **stop** | `on:stop={(e) => { ... }}` | `{ activeHandle: Integer, startValue: Float, value: Float, values: Array }` | Event fired when the user stops interacting with slider; returns the beginning value, also **[📔📘📖 _Full Documentation & Examples_](https://simeydotme.github.io/svelte-range-slider-pips/)** diff --git a/dist/svelte-range-slider-pips.js b/dist/svelte-range-slider-pips.js index 91b9d96..557d0f6 100644 --- a/dist/svelte-range-slider-pips.js +++ b/dist/svelte-range-slider-pips.js @@ -1,7 +1,7 @@ /** - * svelte-range-slider-pips ~ 1.6.0 + * svelte-range-slider-pips ~ 1.6.1 * Multi-Thumb, Accessible, Beautiful Range Slider with Pips - * © MPL-2.0 ~ Simon Goellner ~ 16/1/2021 + * © MPL-2.0 ~ Simon Goellner ~ 20/1/2021 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : @@ -1133,7 +1133,7 @@ return child_ctx; } - // (724:6) {#if float} + // (734:6) {#if float} function create_if_block_2$1(ctx) { let span; let t0; @@ -1166,7 +1166,7 @@ }; } - // (706:2) {#each values as value, index} + // (716:2) {#each values as value, index} function create_each_block$1(ctx) { let span1; let span0; @@ -1287,7 +1287,7 @@ }; } - // (729:2) {#if range} + // (739:2) {#if range} function create_if_block_1$1(ctx) { let span; let span_style_value; @@ -1312,7 +1312,7 @@ }; } - // (735:2) {#if pips} + // (745:2) {#if pips} function create_if_block$1(ctx) { let rangepips; let current; @@ -1614,6 +1614,8 @@ let { handleFormatter = formatter } = $$props; let { precision = 2 } = $$props; let { springValues = { stiffness: 0.15, damping: 0.4 } } = $$props; + + // prepare dispatched events const dispatch = createEventDispatcher(); // dom references @@ -1629,8 +1631,8 @@ let startValue; let previousValue; - // save spring-tweened copies of the values for use - // when changing values and animating the handle/range nicely + // copy the initial values in to a spring function which + // will update every time the values array is modified let springPositions = spring(values.map(v => parseFloat(((v - min) / (max - min) * 100).toFixed(precision))), springValues); component_subscribe($$self, springPositions, value => $$invalidate(24, $springPositions = value)); @@ -1648,8 +1650,8 @@ } /** - * take in the value from the "range" parameter and see if - * we should make a min/max/range slider. + * trim the values array based on whether the property + * for 'range' is 'min', 'max', or truthy. * @param {array} values the input values for the rangeSlider * @return {array} the range array for creating a rangeSlider **/ @@ -1757,6 +1759,11 @@ * @return {number} the value that was moved to (after alignment/clamping) **/ function moveHandle(index, value) { + // align & clamp the value so we're not doing extra + // calculation on an out-of-range value down below + value = alignValueToStep(value); + + // if this is a range slider if (range) { // restrict the handles of a range-slider from // going past one-another unless "pushy" is true @@ -1775,14 +1782,16 @@ } } - // set the value for the handle, and align/clamp it - $$invalidate(0, values[index] = value, values); + // if the value has changed, update it + if (values[index] !== value) { + $$invalidate(0, values[index] = value, values); + } // fire the change event when the handle moves, // and store the previous value for the next time - if (previousValue !== alignValueToStep(value)) { + if (previousValue !== value) { eChange(); - previousValue = alignValueToStep(value); + previousValue = value; } } @@ -1894,7 +1903,7 @@ $$invalidate(22, activeHandle = getClosestHandle(clientPos)); // fire the start event - startValue = values[activeHandle]; + startValue = previousValue = alignValueToStep(values[activeHandle]); eStart(); @@ -1992,7 +2001,7 @@ function eStart() { dispatch("start", { activeHandle, - value: alignValueToStep(startValue), + value: startValue, values: values.map(v => alignValueToStep(v)) }); } @@ -2000,8 +2009,8 @@ function eStop() { dispatch("stop", { activeHandle, - startValue: alignValueToStep(startValue), - value: alignValueToStep(values[activeHandle]), + startValue, + value: values[activeHandle], values: values.map(v => alignValueToStep(v)) }); } @@ -2009,8 +2018,11 @@ function eChange() { dispatch("change", { activeHandle, - previousValue: alignValueToStep(previousValue) || alignValueToStep(startValue) || alignValueToStep(values[activeHandle]), - value: alignValueToStep(values[activeHandle]), + startValue, + previousValue: typeof previousValue === "undefined" + ? startValue + : previousValue, + value: values[activeHandle], values: values.map(v => alignValueToStep(v)) }); } @@ -2102,8 +2114,8 @@ } if ($$self.$$.dirty[0] & /*values*/ 1 | $$self.$$.dirty[1] & /*alignValueToStep*/ 32768) { - // watch the values array, and trim / clamp the values to the steps - // and boundaries set up in the slider on change + // check the values array, and trim it if needed (range) + // and clamp the values to the steps and boundaries set up in the slider $$invalidate(0, values = trimRange(values).map(v => alignValueToStep(v))); } diff --git a/dist/svelte-range-slider-pips.mjs b/dist/svelte-range-slider-pips.mjs index 09b7d78..e1a6269 100644 --- a/dist/svelte-range-slider-pips.mjs +++ b/dist/svelte-range-slider-pips.mjs @@ -1,7 +1,7 @@ /** - * svelte-range-slider-pips ~ 1.6.0 + * svelte-range-slider-pips ~ 1.6.1 * Multi-Thumb, Accessible, Beautiful Range Slider with Pips - * © MPL-2.0 ~ Simon Goellner ~ 16/1/2021 + * © MPL-2.0 ~ Simon Goellner ~ 20/1/2021 */ function noop() { } function run(fn) { @@ -1127,7 +1127,7 @@ function get_each_context$1(ctx, list, i) { return child_ctx; } -// (724:6) {#if float} +// (734:6) {#if float} function create_if_block_2$1(ctx) { let span; let t0; @@ -1160,7 +1160,7 @@ function create_if_block_2$1(ctx) { }; } -// (706:2) {#each values as value, index} +// (716:2) {#each values as value, index} function create_each_block$1(ctx) { let span1; let span0; @@ -1281,7 +1281,7 @@ function create_each_block$1(ctx) { }; } -// (729:2) {#if range} +// (739:2) {#if range} function create_if_block_1$1(ctx) { let span; let span_style_value; @@ -1306,7 +1306,7 @@ function create_if_block_1$1(ctx) { }; } -// (735:2) {#if pips} +// (745:2) {#if pips} function create_if_block$1(ctx) { let rangepips; let current; @@ -1608,6 +1608,8 @@ function instance$1($$self, $$props, $$invalidate) { let { handleFormatter = formatter } = $$props; let { precision = 2 } = $$props; let { springValues = { stiffness: 0.15, damping: 0.4 } } = $$props; + + // prepare dispatched events const dispatch = createEventDispatcher(); // dom references @@ -1623,8 +1625,8 @@ function instance$1($$self, $$props, $$invalidate) { let startValue; let previousValue; - // save spring-tweened copies of the values for use - // when changing values and animating the handle/range nicely + // copy the initial values in to a spring function which + // will update every time the values array is modified let springPositions = spring(values.map(v => parseFloat(((v - min) / (max - min) * 100).toFixed(precision))), springValues); component_subscribe($$self, springPositions, value => $$invalidate(24, $springPositions = value)); @@ -1642,8 +1644,8 @@ function instance$1($$self, $$props, $$invalidate) { } /** - * take in the value from the "range" parameter and see if - * we should make a min/max/range slider. + * trim the values array based on whether the property + * for 'range' is 'min', 'max', or truthy. * @param {array} values the input values for the rangeSlider * @return {array} the range array for creating a rangeSlider **/ @@ -1751,6 +1753,11 @@ function instance$1($$self, $$props, $$invalidate) { * @return {number} the value that was moved to (after alignment/clamping) **/ function moveHandle(index, value) { + // align & clamp the value so we're not doing extra + // calculation on an out-of-range value down below + value = alignValueToStep(value); + + // if this is a range slider if (range) { // restrict the handles of a range-slider from // going past one-another unless "pushy" is true @@ -1769,14 +1776,16 @@ function instance$1($$self, $$props, $$invalidate) { } } - // set the value for the handle, and align/clamp it - $$invalidate(0, values[index] = value, values); + // if the value has changed, update it + if (values[index] !== value) { + $$invalidate(0, values[index] = value, values); + } // fire the change event when the handle moves, // and store the previous value for the next time - if (previousValue !== alignValueToStep(value)) { + if (previousValue !== value) { eChange(); - previousValue = alignValueToStep(value); + previousValue = value; } } @@ -1888,7 +1897,7 @@ function instance$1($$self, $$props, $$invalidate) { $$invalidate(22, activeHandle = getClosestHandle(clientPos)); // fire the start event - startValue = values[activeHandle]; + startValue = previousValue = alignValueToStep(values[activeHandle]); eStart(); @@ -1986,7 +1995,7 @@ function instance$1($$self, $$props, $$invalidate) { function eStart() { dispatch("start", { activeHandle, - value: alignValueToStep(startValue), + value: startValue, values: values.map(v => alignValueToStep(v)) }); } @@ -1994,8 +2003,8 @@ function instance$1($$self, $$props, $$invalidate) { function eStop() { dispatch("stop", { activeHandle, - startValue: alignValueToStep(startValue), - value: alignValueToStep(values[activeHandle]), + startValue, + value: values[activeHandle], values: values.map(v => alignValueToStep(v)) }); } @@ -2003,8 +2012,11 @@ function instance$1($$self, $$props, $$invalidate) { function eChange() { dispatch("change", { activeHandle, - previousValue: alignValueToStep(previousValue) || alignValueToStep(startValue) || alignValueToStep(values[activeHandle]), - value: alignValueToStep(values[activeHandle]), + startValue, + previousValue: typeof previousValue === "undefined" + ? startValue + : previousValue, + value: values[activeHandle], values: values.map(v => alignValueToStep(v)) }); } @@ -2096,8 +2108,8 @@ function instance$1($$self, $$props, $$invalidate) { } if ($$self.$$.dirty[0] & /*values*/ 1 | $$self.$$.dirty[1] & /*alignValueToStep*/ 32768) { - // watch the values array, and trim / clamp the values to the steps - // and boundaries set up in the slider on change + // check the values array, and trim it if needed (range) + // and clamp the values to the steps and boundaries set up in the slider $$invalidate(0, values = trimRange(values).map(v => alignValueToStep(v))); } diff --git a/package.json b/package.json index c160b43..1e2b112 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte-range-slider-pips", - "version": "1.6.0", + "version": "1.6.1", "svelte": "src/index.js", "module": "dist/svelte-range-slider-pips.mjs", "main": "dist/svelte-range-slider-pips.js", diff --git a/src/RangeSlider.svelte b/src/RangeSlider.svelte index 45534ed..b4867f0 100644 --- a/src/RangeSlider.svelte +++ b/src/RangeSlider.svelte @@ -33,6 +33,7 @@ export let precision = 2; export let springValues = { stiffness: 0.15, damping: 0.4 }; + // prepare dispatched events const dispatch = createEventDispatcher(); // dom references @@ -47,8 +48,8 @@ let startValue; let previousValue; - // save spring-tweened copies of the values for use - // when changing values and animating the handle/range nicely + // copy the initial values in to a spring function which + // will update every time the values array is modified let springPositions = spring( values.map((v) => parseFloat((((v - min) / (max - min)) * 100).toFixed(precision)) @@ -56,8 +57,8 @@ springValues ); - // watch the values array, and trim / clamp the values to the steps - // and boundaries set up in the slider on change + // check the values array, and trim it if needed (range) + // and clamp the values to the steps and boundaries set up in the slider $: values = trimRange(values).map((v) => alignValueToStep(v)); // update the spring function so that movement can happen in the UI @@ -165,8 +166,8 @@ } /** - * take in the value from the "range" parameter and see if - * we should make a min/max/range slider. + * trim the values array based on whether the property + * for 'range' is 'min', 'max', or truthy. * @param {array} values the input values for the rangeSlider * @return {array} the range array for creating a rangeSlider **/ @@ -269,6 +270,10 @@ * @return {number} the value that was moved to (after alignment/clamping) **/ function moveHandle(index, value) { + // align & clamp the value so we're not doing extra + // calculation on an out-of-range value down below + value = alignValueToStep(value); + // if this is a range slider if (range) { // restrict the handles of a range-slider from // going past one-another unless "pushy" is true @@ -286,14 +291,17 @@ } } } - // set the value for the handle, and align/clamp it - values[index] = value; + + // if the value has changed, update it + if (values[index] !== value) { + values[index] = value; + } // fire the change event when the handle moves, // and store the previous value for the next time - if ( previousValue !== alignValueToStep(value) ) { + if (previousValue !== value) { eChange(); - previousValue = alignValueToStep(value); + previousValue = value; } } @@ -402,7 +410,7 @@ activeHandle = getClosestHandle(clientPos); // fire the start event - startValue = values[activeHandle]; + startValue = previousValue = alignValueToStep(values[activeHandle]); eStart(); // for touch devices we want the handle to instantly @@ -419,7 +427,7 @@ **/ function sliderInteractEnd(e) { // fire the stop event for touch devices - if( e.type === "touchend" ) { + if (e.type === "touchend") { eStop(); } handlePressed = false; @@ -491,29 +499,31 @@ } function eStart() { - dispatch("start", { - activeHandle, - value: alignValueToStep(startValue), - values: values.map((v) => alignValueToStep(v)) - }); + dispatch("start", { + activeHandle, + value: startValue, + values: values.map((v) => alignValueToStep(v)), + }); } function eStop() { - dispatch("stop", { - activeHandle, - startValue: alignValueToStep(startValue), - value: alignValueToStep(values[activeHandle]), - values: values.map((v) => alignValueToStep(v)) - }); + dispatch("stop", { + activeHandle, + startValue: startValue, + value: values[activeHandle], + values: values.map((v) => alignValueToStep(v)), + }); } function eChange() { - dispatch("change", { - activeHandle, - previousValue: alignValueToStep(previousValue) || alignValueToStep(startValue) || alignValueToStep(values[activeHandle]), - value: alignValueToStep(values[activeHandle]), - values: values.map((v) => alignValueToStep(v)) - }); + dispatch("change", { + activeHandle, + startValue: startValue, + previousValue: + typeof previousValue === "undefined" ? startValue : previousValue, + value: values[activeHandle], + values: values.map((v) => alignValueToStep(v)), + }); } diff --git a/test/package.json b/test/package.json index cdd73a5..b2e22a4 100644 --- a/test/package.json +++ b/test/package.json @@ -1,7 +1,7 @@ { "name": "svelte-range-slider-pips-testing", "private": true, - "version": "1.3.0", + "version": "1.4.0", "scripts": { "build": "rollup -c", "dev": "rollup -c -w", diff --git a/test/src/App.svelte b/test/src/App.svelte index caf54e9..5a91534 100644 --- a/test/src/App.svelte +++ b/test/src/App.svelte @@ -2,7 +2,7 @@ import RangeSlider from "../../src/RangeSlider.svelte"; const num = new Intl.NumberFormat("en-US"); const numzh = new Intl.NumberFormat("zh-Hans-CN-u-nu-hanidec"); - let values = [20, 40, 60, 80]; + let values = [21.3, 40, 60, 80]; let day = [3]; let hue = [244]; let dynamic = [0,50]; @@ -28,6 +28,11 @@ }; $: lightColor = `hsl(${Math.round(hue[0]) - 10}, 65%, 70%)`; $: color = `hsl(${Math.round(hue[0])}, 63%, 54%)`; + + let perc1 = [5]; + let perc2 = [100 - perc1]; + $: perc2max = 100 - perc1[0]; + @@ -76,7 +81,11 @@ - + { console.log("start",e.detail)}} + on:stop={(e) => { console.log("stop",e.detail)}} + on:change={(e) => { console.log("change",e.detail)}} + />
@@ -102,6 +111,13 @@
{dayFormatCn(day[0])} | {dayFormat(day[0])}

color} /> + + + + +
+ percent1: {perc1}
percent2: {perc2} + @@ -125,4 +141,7 @@ input { width: 100px; } + :global(.rangeSlider ) { + margin: 60px!important; + } \ No newline at end of file