Fix range selector
This commit is contained in:
parent
63bec056c7
commit
b6a9c02c5c
@ -1,8 +1,8 @@
|
|||||||
import { ColorHsla, hexaToHsla, hslaToRgba, rgbaToHexa as rgbaToHexa, rgbaToHsla } from "../helpers/color";
|
import { ColorHsla, hexaToHsla, hslaToRgba, rgbaToHexa as rgbaToHexa, rgbaToHsla } from "../helpers/color";
|
||||||
|
import attachGrabListeners from "../helpers/dom/attachGrabListeners";
|
||||||
import { clamp } from "../helpers/number";
|
import { clamp } from "../helpers/number";
|
||||||
import InputField, { InputState } from "./inputField";
|
import InputField, { InputState } from "./inputField";
|
||||||
|
|
||||||
type EventPosition = {x: number, y: number, isTouch?: boolean};
|
|
||||||
export type ColorPickerColor = {
|
export type ColorPickerColor = {
|
||||||
hsl: string;
|
hsl: string;
|
||||||
rgb: string;
|
rgb: string;
|
||||||
@ -133,56 +133,6 @@ export default class ColorPicker {
|
|||||||
this.attachHueListeners();
|
this.attachHueListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachGrabListeners(element: SVGSVGElement, onStart: (position: EventPosition) => void, onMove: (position: EventPosition) => void, onEnd: (position: EventPosition) => void) {
|
|
||||||
// * Mouse
|
|
||||||
const onMouseMove = (event: MouseEvent) => {
|
|
||||||
onMove({x: event.pageX, y: event.pageY});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseDown = (event: MouseEvent) => {
|
|
||||||
if(event.button !== 0) {
|
|
||||||
element.addEventListener('mousedown', onMouseDown, {once: true});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onGrabStart();
|
|
||||||
onStart({x: event.pageX, y: event.pageY});
|
|
||||||
onMouseMove(event);
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', onMouseMove);
|
|
||||||
document.addEventListener('mouseup', () => {
|
|
||||||
document.removeEventListener('mousemove', onMouseMove);
|
|
||||||
element.addEventListener('mousedown', onMouseDown, {once: true});
|
|
||||||
this.onGrabEnd();
|
|
||||||
onEnd && onEnd({x: event.pageX, y: event.pageY});
|
|
||||||
}, {once: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
element.addEventListener('mousedown', onMouseDown, {once: true});
|
|
||||||
|
|
||||||
// * Touch
|
|
||||||
const onTouchMove = (event: TouchEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
onMove({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTouchStart = (event: TouchEvent) => {
|
|
||||||
this.onGrabStart();
|
|
||||||
onStart({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true});
|
|
||||||
onTouchMove(event);
|
|
||||||
|
|
||||||
document.addEventListener('touchmove', onTouchMove, {passive: false});
|
|
||||||
document.addEventListener('touchend', (event) => {
|
|
||||||
document.removeEventListener('touchmove', onTouchMove);
|
|
||||||
element.addEventListener('touchstart', onTouchStart, {passive: true, once: true});
|
|
||||||
this.onGrabEnd();
|
|
||||||
onEnd && onEnd({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true});
|
|
||||||
}, {passive: true, once: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
element.addEventListener('touchstart', onTouchStart, {passive: true, once: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
private onGrabStart = () => {
|
private onGrabStart = () => {
|
||||||
document.documentElement.style.cursor = this.elements.boxDragger.style.cursor = 'grabbing';
|
document.documentElement.style.cursor = this.elements.boxDragger.style.cursor = 'grabbing';
|
||||||
};
|
};
|
||||||
@ -192,21 +142,27 @@ export default class ColorPicker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private attachBoxListeners() {
|
private attachBoxListeners() {
|
||||||
this.attachGrabListeners(this.elements.box, () => {
|
attachGrabListeners(this.elements.box as any, () => {
|
||||||
|
this.onGrabStart();
|
||||||
this.boxRect = this.elements.box.getBoundingClientRect();
|
this.boxRect = this.elements.box.getBoundingClientRect();
|
||||||
//this.boxDraggerRect = this.elements.boxDragger.getBoundingClientRect();
|
//this.boxDraggerRect = this.elements.boxDragger.getBoundingClientRect();
|
||||||
}, (pos) => {
|
}, (pos) => {
|
||||||
this.saturationHandler(pos.x, pos.y);
|
this.saturationHandler(pos.x, pos.y);
|
||||||
}, null);
|
}, () => {
|
||||||
|
this.onGrabEnd();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachHueListeners() {
|
private attachHueListeners() {
|
||||||
this.attachGrabListeners(this.elements.hue, () => {
|
attachGrabListeners(this.elements.hue as any, () => {
|
||||||
|
this.onGrabStart();
|
||||||
this.hueRect = this.elements.hue.getBoundingClientRect();
|
this.hueRect = this.elements.hue.getBoundingClientRect();
|
||||||
//this.hueDraggerRect = this.elements.hueDragger.getBoundingClientRect();
|
//this.hueDraggerRect = this.elements.hueDragger.getBoundingClientRect();
|
||||||
}, (pos) => {
|
}, (pos) => {
|
||||||
this.hueHandler(pos.x);
|
this.hueHandler(pos.x);
|
||||||
}, null);
|
}, () => {
|
||||||
|
this.onGrabEnd();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setColor(color: ColorHsla | string, updateHexInput = true, updateRgbInput = true) {
|
public setColor(color: ColorHsla | string, updateHexInput = true, updateRgbInput = true) {
|
||||||
|
@ -4,10 +4,8 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isTouchSupported } from "../helpers/touchSupport";
|
|
||||||
import { clamp } from "../helpers/number";
|
import { clamp } from "../helpers/number";
|
||||||
|
import attachGrabListeners, { GrabEvent } from "../helpers/dom/attachGrabListeners";
|
||||||
type SUPEREVENT = MouseEvent | TouchEvent;
|
|
||||||
|
|
||||||
export default class RangeSelector {
|
export default class RangeSelector {
|
||||||
public container: HTMLDivElement;
|
public container: HTMLDivElement;
|
||||||
@ -15,12 +13,14 @@ export default class RangeSelector {
|
|||||||
protected seek: HTMLInputElement;
|
protected seek: HTMLInputElement;
|
||||||
|
|
||||||
public mousedown = false;
|
public mousedown = false;
|
||||||
|
protected rect: DOMRect;
|
||||||
|
protected _removeListeners: () => void;
|
||||||
|
|
||||||
private events: Partial<{
|
private events: Partial<{
|
||||||
//onMouseMove: ProgressLine['onMouseMove'],
|
//onMouseMove: ProgressLine['onMouseMove'],
|
||||||
onMouseDown: RangeSelector['onMouseDown'],
|
onMouseDown: RangeSelector['onMouseDown'],
|
||||||
onMouseUp: RangeSelector['onMouseUp'],
|
onMouseUp: RangeSelector['onMouseUp'],
|
||||||
onScrub: (scrubTime: number) => void
|
onScrub: (value: number) => void
|
||||||
}> = {};
|
}> = {};
|
||||||
|
|
||||||
protected decimals: number;
|
protected decimals: number;
|
||||||
@ -41,10 +41,6 @@ export default class RangeSelector {
|
|||||||
seek.max = '' + this.max;
|
seek.max = '' + this.max;
|
||||||
seek.value = '' + value;
|
seek.value = '' + value;
|
||||||
|
|
||||||
/* this.seek.addEventListener('change', (e) => {
|
|
||||||
console.log('seek change', e);
|
|
||||||
}); */
|
|
||||||
|
|
||||||
if(value) {
|
if(value) {
|
||||||
this.setProgress(value);
|
this.setProgress(value);
|
||||||
}
|
}
|
||||||
@ -62,33 +58,33 @@ export default class RangeSelector {
|
|||||||
this.events = events;
|
this.events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove = (e: SUPEREVENT) => {
|
protected onMouseMove = (event: GrabEvent) => {
|
||||||
this.mousedown && this.scrub(e);
|
this.scrub(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMouseDown = (e: SUPEREVENT) => {
|
protected onMouseDown = (event: GrabEvent) => {
|
||||||
this.scrub(e);
|
this.rect = this.container.getBoundingClientRect();
|
||||||
this.mousedown = true;
|
this.mousedown = true;
|
||||||
this.events?.onMouseDown && this.events.onMouseDown(e);
|
this.scrub(event);
|
||||||
|
this.events?.onMouseDown && this.events.onMouseDown(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMouseUp = (e: SUPEREVENT) => {
|
protected onMouseUp = (event: GrabEvent) => {
|
||||||
this.mousedown = false;
|
this.mousedown = false;
|
||||||
this.events?.onMouseUp && this.events.onMouseUp(e);
|
this.events?.onMouseUp && this.events.onMouseUp(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
public setListeners() {
|
public setListeners() {
|
||||||
this.container.addEventListener('mousemove', this.onMouseMove);
|
this.seek.addEventListener('input', this.onInput);
|
||||||
this.container.addEventListener('mousedown', this.onMouseDown);
|
this._removeListeners = attachGrabListeners(this.container, this.onMouseDown, this.onMouseMove, this.onMouseUp);
|
||||||
this.container.addEventListener('mouseup', this.onMouseUp);
|
|
||||||
|
|
||||||
if(isTouchSupported) {
|
|
||||||
this.container.addEventListener('touchmove', this.onMouseMove, {passive: true});
|
|
||||||
this.container.addEventListener('touchstart', this.onMouseDown, {passive: true});
|
|
||||||
this.container.addEventListener('touchend', this.onMouseUp, {passive: true});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onInput = () => {
|
||||||
|
const value = +this.seek.value;
|
||||||
|
this.setFilled(value);
|
||||||
|
this.events?.onScrub && this.events.onScrub(value);
|
||||||
|
};
|
||||||
|
|
||||||
public setProgress(value: number) {
|
public setProgress(value: number) {
|
||||||
this.setFilled(value);
|
this.setFilled(value);
|
||||||
this.seek.value = '' + value;
|
this.seek.value = '' + value;
|
||||||
@ -97,50 +93,40 @@ export default class RangeSelector {
|
|||||||
public setFilled(value: number) {
|
public setFilled(value: number) {
|
||||||
let percents = (value - this.min) / (this.max - this.min);
|
let percents = (value - this.min) / (this.max - this.min);
|
||||||
percents = clamp(percents, 0, 1);
|
percents = clamp(percents, 0, 1);
|
||||||
//console.log('setFilled', percents, value);
|
|
||||||
this.filled.style.width = (percents * 100) + '%';
|
this.filled.style.width = (percents * 100) + '%';
|
||||||
//this.filled.style.transform = 'scaleX(' + scaleX + ')';
|
//this.filled.style.transform = 'scaleX(' + scaleX + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected scrub(e: SUPEREVENT) {
|
protected scrub(event: GrabEvent) {
|
||||||
let offsetX: number;
|
const offsetX = clamp(event.x - this.rect.left, 0, this.rect.width);
|
||||||
const rect = (e.target as HTMLElement).getBoundingClientRect();
|
|
||||||
if(e instanceof MouseEvent) {
|
|
||||||
offsetX = e.pageX - Math.round(rect.left);
|
|
||||||
} else { // touch
|
|
||||||
offsetX = e.targetTouches[0].pageX - Math.round(rect.left);
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = this.min + (offsetX / Math.round(rect.width) * (this.max - this.min));
|
let value = this.min + (offsetX / this.rect.width * (this.max - this.min));
|
||||||
|
|
||||||
if((value - this.min) < ((this.max - this.min) / 2)) {
|
if((value - this.min) < ((this.max - this.min) / 2)) {
|
||||||
value -= this.step / 10;
|
value -= this.step / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log('scrub value:', value, this.decimals, offsetX, rect.width, e);
|
|
||||||
value = +value.toFixed(this.decimals);
|
value = +value.toFixed(this.decimals);
|
||||||
//const dotIndex = ('' + value).indexOf('.');
|
|
||||||
//value = +('' + value).slice(0, this.decimals ? dotIndex + this.decimals : dotIndex);
|
|
||||||
|
|
||||||
value = clamp(value, this.min, this.max);
|
value = clamp(value, this.min, this.max);
|
||||||
|
|
||||||
this.setFilled(value);
|
//this.seek.value = '' + value;
|
||||||
|
//this.onInput();
|
||||||
|
|
||||||
|
this.setProgress(value);
|
||||||
this.events?.onScrub && this.events.onScrub(value);
|
this.events?.onScrub && this.events.onScrub(value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeListeners() {
|
public removeListeners() {
|
||||||
this.container.removeEventListener('mousemove', this.onMouseMove);
|
if(this._removeListeners) {
|
||||||
this.container.removeEventListener('mousedown', this.onMouseDown);
|
this._removeListeners();
|
||||||
this.container.removeEventListener('mouseup', this.onMouseUp);
|
this._removeListeners = null;
|
||||||
|
|
||||||
if(isTouchSupported) {
|
|
||||||
this.container.removeEventListener('touchmove', this.onMouseMove);
|
|
||||||
this.container.removeEventListener('touchstart', this.onMouseDown);
|
|
||||||
this.container.removeEventListener('touchend', this.onMouseUp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.seek.removeEventListener('input', this.onInput);
|
||||||
|
|
||||||
this.events = {};
|
this.events = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
src/helpers/dom/attachGrabListeners.ts
Normal file
61
src/helpers/dom/attachGrabListeners.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
export type GrabEvent = {x: number, y: number, isTouch?: boolean};
|
||||||
|
|
||||||
|
export default function attachGrabListeners(element: HTMLElement, onStart: (position: GrabEvent) => void, onMove: (position: GrabEvent) => void, onEnd: (position: GrabEvent) => void) {
|
||||||
|
// * Mouse
|
||||||
|
const onMouseMove = (event: MouseEvent) => {
|
||||||
|
onMove({x: event.pageX, y: event.pageY});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = (event: MouseEvent) => {
|
||||||
|
document.removeEventListener('mousemove', onMouseMove);
|
||||||
|
element.addEventListener('mousedown', onMouseDown, {once: true});
|
||||||
|
onEnd && onEnd({x: event.pageX, y: event.pageY});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseDown = (event: MouseEvent) => {
|
||||||
|
if(event.button !== 0) {
|
||||||
|
element.addEventListener('mousedown', onMouseDown, {once: true});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart({x: event.pageX, y: event.pageY});
|
||||||
|
onMouseMove(event);
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMouseMove);
|
||||||
|
document.addEventListener('mouseup', onMouseUp, {once: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
element.addEventListener('mousedown', onMouseDown, {once: true});
|
||||||
|
|
||||||
|
// * Touch
|
||||||
|
const onTouchMove = (event: TouchEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
onMove({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTouchEnd = (event: TouchEvent) => {
|
||||||
|
document.removeEventListener('touchmove', onTouchMove);
|
||||||
|
element.addEventListener('touchstart', onTouchStart, {passive: true, once: true});
|
||||||
|
onEnd && onEnd({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTouchStart = (event: TouchEvent) => {
|
||||||
|
onStart({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true});
|
||||||
|
onTouchMove(event);
|
||||||
|
|
||||||
|
document.addEventListener('touchmove', onTouchMove, {passive: false});
|
||||||
|
document.addEventListener('touchend', onTouchEnd, {passive: true, once: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
element.addEventListener('touchstart', onTouchStart, {passive: true, once: true});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
element.removeEventListener('mousedown', onMouseDown);
|
||||||
|
document.removeEventListener('mousemove', onMouseMove);
|
||||||
|
document.removeEventListener('mouseup', onMouseUp);
|
||||||
|
|
||||||
|
element.removeEventListener('touchstart', onTouchStart);
|
||||||
|
document.removeEventListener('touchmove', onTouchMove);
|
||||||
|
document.removeEventListener('touchend', onTouchEnd);
|
||||||
|
};
|
||||||
|
}
|
@ -11,8 +11,6 @@ import { isTouchSupported } from "../helpers/touchSupport";
|
|||||||
import RangeSelector from "../components/rangeSelector";
|
import RangeSelector from "../components/rangeSelector";
|
||||||
import { onVideoLoad } from "../helpers/files";
|
import { onVideoLoad } from "../helpers/files";
|
||||||
|
|
||||||
type SUPEREVENT = MouseEvent | TouchEvent;
|
|
||||||
|
|
||||||
export class MediaProgressLine extends RangeSelector {
|
export class MediaProgressLine extends RangeSelector {
|
||||||
private filledLoad: HTMLDivElement;
|
private filledLoad: HTMLDivElement;
|
||||||
|
|
||||||
@ -36,7 +34,7 @@ export class MediaProgressLine extends RangeSelector {
|
|||||||
this.setSeekMax();
|
this.setSeekMax();
|
||||||
this.setListeners();
|
this.setListeners();
|
||||||
this.setHandlers({
|
this.setHandlers({
|
||||||
onMouseDown: (e: SUPEREVENT) => {
|
onMouseDown: () => {
|
||||||
//super.onMouseDown(e);
|
//super.onMouseDown(e);
|
||||||
|
|
||||||
//Таймер для того, чтобы стопать видео, если зажал мышку и не отпустил клик
|
//Таймер для того, чтобы стопать видео, если зажал мышку и не отпустил клик
|
||||||
@ -50,7 +48,7 @@ export class MediaProgressLine extends RangeSelector {
|
|||||||
}, 150);
|
}, 150);
|
||||||
},
|
},
|
||||||
|
|
||||||
onMouseUp: (e: SUPEREVENT) => {
|
onMouseUp: () => {
|
||||||
//super.onMouseUp(e);
|
//super.onMouseUp(e);
|
||||||
|
|
||||||
if(this.stopAndScrubTimeout) {
|
if(this.stopAndScrubTimeout) {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
.ckin {
|
.ckin {
|
||||||
&__player {
|
&__player {
|
||||||
letter-spacing: 0.02em;
|
letter-spacing: 0.02em;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
&.ckin__fullscreen {
|
&.ckin__fullscreen {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user