Skip to content

Commit

Permalink
regions plugin: region dragging and resizing can now continue outside…
Browse files Browse the repository at this point in the history
… canvas (katspaugh#2012)

* fix region dragging and resizing can continue outside canvas

* fix region resizing beyond duration

* removing dangling commas
  • Loading branch information
adityakrshnn committed Jul 22, 2020
1 parent 50b9535 commit 6566071
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Next (unreleased)
- Removed 'col-resize' cursor when resize is disabled (#1985)
- Improved and unified loop playback logic (#1868)
- Check `minLength` before resizing region (#2001)
- Dragging and resizing will continue outside canvas (#2006)
- Microphone plugin: move to separate directory (#1997)
- Minimap plugin: move plugin to separate directory (#1999)
- Cursor plugin: move plugin to separate directory (#1998)
Expand Down
113 changes: 86 additions & 27 deletions src/plugin/regions/region.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class Region {
params.end == null
? // small marker-like region
this.start +
(4 / this.wrapper.scrollWidth) * this.wavesurfer.getDuration()
(4 / this.wrapper.scrollWidth) * this.wavesurfer.getDuration()
: Number(params.end);
this.resize =
params.resize === undefined ? true : Boolean(params.resize);
Expand Down Expand Up @@ -69,7 +69,8 @@ export class Region {
: -1;
if (channelCount >= 0 && channelIdx < channelCount) {
this.regionHeight = Math.floor((1 / channelCount) * 100) + '%';
this.marginTop = this.wavesurfer.getHeight() * channelIdx + 'px';
this.marginTop =
this.wavesurfer.getHeight() * channelIdx + 'px';
}
}

Expand Down Expand Up @@ -241,7 +242,7 @@ export class Region {
return this.formatTimeCallback(start, end);
}
return (start == end ? [start] : [start, end])
.map(time =>
.map((time) =>
[
Math.floor((time % 3600) / 60), // minutes
('00' + Math.floor(time % 60)).slice(-2) // seconds
Expand Down Expand Up @@ -308,7 +309,7 @@ export class Region {
this.firedIn = false;
this.firedOut = false;

const onProcess = time => {
const onProcess = (time) => {
let start = Math.round(this.start * 10) / 10;
let end = Math.round(this.end * 10) / 10;
time = Math.round(time * 10) / 10;
Expand Down Expand Up @@ -352,31 +353,31 @@ export class Region {
bindEvents() {
const preventContextMenu = this.preventContextMenu;

this.element.addEventListener('mouseenter', e => {
this.element.addEventListener('mouseenter', (e) => {
this.fireEvent('mouseenter', e);
this.wavesurfer.fireEvent('region-mouseenter', this, e);
});

this.element.addEventListener('mouseleave', e => {
this.element.addEventListener('mouseleave', (e) => {
this.fireEvent('mouseleave', e);
this.wavesurfer.fireEvent('region-mouseleave', this, e);
});

this.element.addEventListener('click', e => {
this.element.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
this.fireEvent('click', e);
this.wavesurfer.fireEvent('region-click', this, e);
});

this.element.addEventListener('dblclick', e => {
this.element.addEventListener('dblclick', (e) => {
e.stopPropagation();
e.preventDefault();
this.fireEvent('dblclick', e);
this.wavesurfer.fireEvent('region-dblclick', this, e);
});

this.element.addEventListener('contextmenu', e => {
this.element.addEventListener('contextmenu', (e) => {
if (preventContextMenu) {
e.preventDefault();
}
Expand All @@ -402,9 +403,11 @@ export class Region {
let updated = false;
let scrollDirection;
let wrapperRect;
let regionLeftHalfTime;
let regionRightHalfTime;

// Scroll when the user is dragging within the threshold
const edgeScroll = e => {
const edgeScroll = (e) => {
const duration = this.wavesurfer.getDuration();
if (!scrollDirection || (!drag && !resize)) {
return;
Expand Down Expand Up @@ -434,7 +437,7 @@ export class Region {
});
};

const onDown = e => {
const onDown = (e) => {
const duration = this.wavesurfer.getDuration();
if (e.touches && e.touches.length > 1) {
return;
Expand All @@ -452,6 +455,10 @@ export class Region {
this.wavesurfer.drawer.handleEvent(e, true) * duration
);

// Store the selected point of contact when we begin dragging
regionLeftHalfTime = startTime - this.start;
regionRightHalfTime = this.end - startTime;

// Store for scroll calculations
maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;
wrapperRect = this.wrapper.getBoundingClientRect();
Expand All @@ -469,7 +476,7 @@ export class Region {
resize = false;
}
};
const onUp = e => {
const onUp = (e) => {
if (e.touches && e.touches.length > 1) {
return;
}
Expand All @@ -489,7 +496,7 @@ export class Region {
this.wavesurfer.fireEvent('region-update-end', this, e);
}
};
const onMove = e => {
const onMove = (e) => {
const duration = this.wavesurfer.getDuration();

if (e.touches && e.touches.length > 1) {
Expand All @@ -503,11 +510,50 @@ export class Region {
}

const oldTime = startTime;
const time = this.regionsUtil.getRegionSnapToGridValue(
let time = this.regionsUtil.getRegionSnapToGridValue(
this.wavesurfer.drawer.handleEvent(e) * duration
);

const delta = time - startTime;
if (drag) {
// To maintain relative cursor start point while dragging
const maxEnd = this.wavesurfer.getDuration();
if (time > maxEnd - regionRightHalfTime) {
time = maxEnd - regionRightHalfTime;
}

if (time - regionLeftHalfTime < 0) {
time = regionLeftHalfTime;
}
}

if (resize) {
// To maintain relative cursor start point while resizing
// we have to handle for minLength
let minLength = this.minLength;
if (!minLength) {
minLength = 0;
}

if (resize === 'start') {
if (time > this.end - minLength) {
time = this.end - minLength;
}

if (time < 0) {
time = 0;
}
} else if (resize === 'end') {
if (time < this.start + minLength) {
time = this.start + minLength;
}

if (time > duration) {
time = duration;
}
}
}

let delta = time - startTime;
startTime = time;

// Drag
Expand Down Expand Up @@ -547,7 +593,7 @@ export class Region {
(scrollDirection === -1 && x > scrollThreshold) ||
(scrollDirection === 1 &&
x + regionRect.width <
wrapperRect.right - scrollThreshold)
wrapperRect.right - scrollThreshold)
) {
scrollDirection = null;
}
Expand All @@ -574,17 +620,17 @@ export class Region {
this.element.addEventListener('mousedown', onDown);
this.element.addEventListener('touchstart', onDown);

this.wrapper.addEventListener('mousemove', onMove);
this.wrapper.addEventListener('touchmove', onMove);
document.body.addEventListener('mousemove', onMove);
document.body.addEventListener('touchmove', onMove);

document.body.addEventListener('mouseup', onUp);
document.body.addEventListener('touchend', onUp);

this.on('remove', () => {
document.body.removeEventListener('mouseup', onUp);
document.body.removeEventListener('touchend', onUp);
this.wrapper.removeEventListener('mousemove', onMove);
this.wrapper.removeEventListener('touchmove', onMove);
document.body.removeEventListener('mousemove', onMove);
document.body.removeEventListener('touchmove', onMove);
});

this.wavesurfer.on('destroy', () => {
Expand All @@ -595,8 +641,12 @@ export class Region {

onDrag(delta) {
const maxEnd = this.wavesurfer.getDuration();
if (this.end + delta > maxEnd || this.start + delta < 0) {
return;
if (this.end + delta > maxEnd) {
delta = maxEnd - this.end;
}

if (this.start + delta < 0) {
delta = this.start * -1;
}

this.update({
Expand All @@ -614,11 +664,16 @@ export class Region {
* @param {string} direction 'start 'or 'end'
*/
onResize(delta, direction) {
const duration = this.wavesurfer.getDuration();
if (direction === 'start') {
// Check if changing the start by the given delta would result in the region being smaller than minLength
// Ignore cases where we are making the region wider rather than shrinking it
if (delta > 0 && this.end - (this.start + delta) < this.minLength) {
return;
delta = this.end - this.minLength - this.start;
}

if (delta < 0 && (this.start + delta) < 0) {
delta = this.start * -1;
}

this.update({
Expand All @@ -628,8 +683,12 @@ export class Region {
} else {
// Check if changing the end by the given delta would result in the region being smaller than minLength
// Ignore cases where we are making the region wider rather than shrinking it
if (delta < 0 && (this.end + delta) - this.start < this.minLength) {
return;
if (delta < 0 && this.end + delta - this.start < this.minLength) {
delta = this.start + this.minLength - this.end;
}

if (delta > 0 && (this.end + delta) > duration) {
delta = duration - this.end;
}

this.update({
Expand All @@ -642,7 +701,7 @@ export class Region {
updateHandlesResize(resize) {
const cursorStyle = resize ? 'col-resize' : 'auto';

this.handleLeftEl && this.style(this.handleLeftEl, {'cursor': cursorStyle});
this.handleRightEl && this.style(this.handleRightEl, {'cursor': cursorStyle});
this.handleLeftEl && this.style(this.handleLeftEl, { cursor: cursorStyle });
this.handleRightEl && this.style(this.handleRightEl, { cursor: cursorStyle });
}
}

0 comments on commit 6566071

Please sign in to comment.