Skip to content

Fix slider change event issue with tapping #3617

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions packages/controls/src/widget_float.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import { CoreDescriptionModel } from './widget_core';

import {
IntSliderView,
BaseIntSliderView,
IntRangeSliderView,
IntSliderView,
IntTextView,
BaseIntSliderView,
} from './widget_int';

import { format } from 'd3-format';
Expand Down Expand Up @@ -166,13 +166,14 @@ export class FloatLogSliderView extends BaseIntSliderView {
},
});

// Using noUiSlider's event handler
// Using noUiSlider's 'update' and 'change' events.
// See reference: https://refreshless.com/nouislider/events-callbacks/
this.$slider.noUiSlider.on('update', (values: any, handle: any) => {
this.handleSliderChange(values, handle);
this.handleSliderUpdateEvent(values, handle);
});

this.$slider.noUiSlider.on('end', (values: any, handle: any) => {
this.handleSliderChanged(values, handle);
this.$slider.noUiSlider.on('change', (values: any, handle: any) => {
this.handleSliderChangeEvent(values, handle);
});
}

Expand Down Expand Up @@ -222,10 +223,11 @@ export class FloatLogSliderView extends BaseIntSliderView {
}
}
}

/**
* Called when the slider value is changing.
* Called whilst the slider is dragged, tapped or moved by the arrow keys.
*/
handleSliderChange(values: number[], handle: number): void {
handleSliderUpdateEvent(values: number[], handle: number): void {
const base = this.model.get('base');
const actual_value = Math.pow(base, this._validate_slide_value(values[0]));
this.readout.textContent = this.valueToString(actual_value);
Expand All @@ -237,6 +239,18 @@ export class FloatLogSliderView extends BaseIntSliderView {
}
}

/**
* Called when the slider handle is released after dragging,
* or by tapping or moving by the arrow keys.
*/
handleSliderChangeEvent(values: number[], handle: number): void {
const base = this.model.get('base');
const actual_value = Math.pow(base, this._validate_slide_value(values[0]));
this.readout.textContent = this.valueToString(actual_value);

this.handleSliderChanged(values, handle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess one problem that can occur is that when you tap or move by the arrow keys, you will get two events: one from the update event, and one from the change event. If we wanted to avoid this, we could conditionally only pass the event on if continuous_update is false here (and other similar event handlers). I'm just not sure how bad of an issue this duplicate is, and if it can lead to some issues with multiple users, or if backbone will automatically discard the second change as a no-op.

}

/**
* Called when the slider value has changed.
*
Expand Down
48 changes: 38 additions & 10 deletions packages/controls/src/widget_int.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { CoreDescriptionModel } from './widget_core';

import { DescriptionView, DescriptionStyleModel } from './widget_description';
import { DescriptionStyleModel, DescriptionView } from './widget_description';

import { DOMWidgetView, WidgetView } from '@jupyter-widgets/base';

Expand Down Expand Up @@ -223,13 +223,14 @@ export abstract class BaseIntSliderView extends DescriptionView {
},
});

// Using noUiSlider's event handler
// Using noUiSlider's 'update' and 'change' events.
// See reference: https://refreshless.com/nouislider/events-callbacks/
this.$slider.noUiSlider.on('update', (values: any, handle: any) => {
this.handleSliderChange(values, handle);
this.handleSliderUpdateEvent(values, handle);
});

this.$slider.noUiSlider.on('end', (values: any, handle: any) => {
this.handleSliderChanged(values, handle);
this.$slider.noUiSlider.on('change', (values: any, handle: any) => {
this.handleSliderChangeEvent(values, handle);
});
}

Expand Down Expand Up @@ -268,9 +269,15 @@ export abstract class BaseIntSliderView extends DescriptionView {
abstract handleTextChange(): void;

/**
* Called when the slider value is changing.
* Called when the slider handle is released after dragging,
* or by tapping or moving by the arrow keys.
*/
abstract handleSliderChange(value: any, handle: any): void;
abstract handleSliderChangeEvent(value: any, handle: any): void;

/**
* Called whilst the slider is dragged, tapped or moved by the arrow keys.
*/
abstract handleSliderUpdateEvent(value: any, handle: any): void;

/**
* Called when the slider value has changed.
Expand Down Expand Up @@ -366,7 +373,21 @@ export class IntRangeSliderView extends BaseIntSliderView {
}
}

handleSliderChange(values: any, handle: any): void {
/**
* Called when the slider handle is released after dragging,
* or by tapping or moving by the arrow keys.
*/
handleSliderChangeEvent(values: any, handle: any): void {
const actual_value = values.map(this._validate_slide_value);
this.readout.textContent = this.valueToString(actual_value);

this.handleSliderChanged(values, handle);
}

/**
* Called whilst the slider is dragged, tapped or moved by the arrow keys.
*/
handleSliderUpdateEvent(values: any, handle: any): void {
const actual_value = values.map(this._validate_slide_value);
this.readout.textContent = this.valueToString(actual_value);

Expand Down Expand Up @@ -460,8 +481,15 @@ export class IntSliderView extends BaseIntSliderView {
}
}

handleSliderChange(values: any, handle: any): void {
const actual_value = this._validate_slide_value(values[handle]);
handleSliderChangeEvent(values: any, handle: any): void {
const actual_value = values.map(this._validate_slide_value);
this.readout.textContent = this.valueToString(actual_value);

this.handleSliderChanged(values, handle);
}

handleSliderUpdateEvent(values: any, handle: any): void {
const actual_value = values.map(this._validate_slide_value);
this.readout.textContent = this.valueToString(actual_value);

// Only persist the value while sliding if the continuous_update
Expand Down
30 changes: 21 additions & 9 deletions packages/controls/src/widget_selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { WidgetView } from '@jupyter-widgets/base';

import { CoreDescriptionModel } from './widget_core';

import { DescriptionView, DescriptionStyleModel } from './widget_description';
import { DescriptionStyleModel, DescriptionView } from './widget_description';

import { uuid } from './utils';

import * as utils from './utils';
import noUiSlider from 'nouislider';
import * as utils from './utils';

export class SelectionModel extends CoreDescriptionModel {
defaults(): Backbone.ObjectHash {
Expand Down Expand Up @@ -769,13 +769,14 @@ export class SelectionSliderView extends DescriptionView {
},
});

// Using noUiSlider's event handler
// Using noUiSlider's 'update' and 'change' events.
// See reference: https://refreshless.com/nouislider/events-callbacks/
this.$slider.noUiSlider.on('update', (values: number[], handle: number) => {
this.handleSliderChange(values, handle);
this.handleSliderUpdateEvent(values, handle);
});

this.$slider.noUiSlider.on('end', (values: number[], handle: number) => {
this.handleSliderChanged(values, handle);
this.$slider.noUiSlider.on('change', (values: number[], handle: number) => {
this.handleSliderChangeEvent(values, handle);
});
}

Expand All @@ -797,9 +798,9 @@ export class SelectionSliderView extends DescriptionView {
}

/**
* Called when the slider value is changing.
* Called whilst the slider is dragged, tapped or moved by the arrow keys.
*/
handleSliderChange(values: number[], handle: number): void {
handleSliderUpdateEvent(values: number[], handle: number): void {
const index = values[0];
this.updateReadout(index);

Expand All @@ -810,6 +811,17 @@ export class SelectionSliderView extends DescriptionView {
}
}

/**
* Called when the slider handle is released after dragging,
* or by tapping or moving by the arrow keys.
*/
handleSliderChangeEvent(values: number[], handle: number): void {
const index = values[0];
this.updateReadout(index);

this.handleSliderChanged(values, handle);
}

/**
* Called when the slider value has changed.
*
Expand Down Expand Up @@ -951,7 +963,7 @@ export class SelectionRangeSliderView extends SelectionSliderView {
/**
* Called when the slider value is changing.
*/
handleSliderChange(values: number[], handle: any): void {
handleSliderUpdateEvent(values: number[], handle: any): void {
const intValues = values.map(Math.trunc);
this.updateReadout(intValues);

Expand Down