import * as React from "react"; import {Icon, IconName, MaybeElement} from "@blueprintjs/core"; import {PointerLockManager} from "../utils/pointerLock"; // todo: bounds and stepsize // todo use the old version in safari etc that change the page height on pointer lock export class DraggableIcon extends React.Component<{ icon: IconName | MaybeElement, size?: number, value: number, stepSize?: number, small?: boolean, disabled?: boolean, onChange: (v: number, last?: boolean) => void }> { private cursor = 'auto' private dragStartValue = -Infinity private lastValue = -Infinity private pointerLockManager: PointerLockManager | null = null private divRef = React.createRef() private removeEvents = () => { if (isFinite(this.lastValue) && !this.props.disabled) this.props.onChange(this.lastValue) this.lastValue = -Infinity this.dragStartValue = -Infinity if (this.pointerLockManager) { this.pointerLockManager.releaseLock() this.pointerLockManager = null } document.documentElement.style.cursor = this.cursor // setDragging(false) }; private handlePointerMove = (movementX: number, _movementY: number, _cursorX: number, _cursorY: number) => { if (isFinite(this.dragStartValue)) { let stepSize = (this.props.stepSize ?? 1) / 10 // Use movementX for horizontal dragging let off = movementX; // Scale the movement off *= stepSize; // Apply modifiers - these need to be checked differently in pointer lock // We'll accumulate the offset instead if (!this.accumulatedOffset) this.accumulatedOffset = 0; this.accumulatedOffset += off; let val = this.dragStartValue + this.accumulatedOffset; // val = Math.min(props.max, Math.max(props.min, val)); // todo val = Number(val.toFixed(Math.max(1, -Math.log10(stepSize / 10)))); // clip decimal places depending on step size if(!this.props.disabled) this.props.onChange(val, false) this.lastValue = val; } }; private accumulatedOffset = 0; render() { // const [dragging, setDragging] = React.useState(false) return (
{ // if(dragging) return if(this.props.disabled) return if (!this.divRef.current) return; this.dragStartValue = this.props.value this.accumulatedOffset = 0 this.cursor = document.documentElement.style.cursor document.documentElement.style.cursor = "none" // Create pointer lock manager this.pointerLockManager = new PointerLockManager(this.divRef.current, { onMove: this.handlePointerMove, onLockChange: (locked) => { if (!locked) { this.removeEvents(); } } }); this.pointerLockManager.requestLock(ev.clientX, ev.clientY); ev.stopPropagation() ev.preventDefault() // Add mouseup listener to release lock const handleMouseUp = () => { this.removeEvents(); document.removeEventListener('mouseup', handleMouseUp); }; document.addEventListener('mouseup', handleMouseUp); // setDragging(true) }} >
) } }