mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 21:42:30 -05:00
Merge pull request #261 from paulkaplan/touch-sliders
Make color pick touch accessible and jump on click
This commit is contained in:
commit
efe30ec50d
4 changed files with 53 additions and 17 deletions
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import bindAll from 'lodash.bindall';
|
import bindAll from 'lodash.bindall';
|
||||||
|
import {getEventXY} from '../../lib/touch-utils';
|
||||||
|
|
||||||
import styles from './slider.css';
|
import styles from './slider.css';
|
||||||
|
|
||||||
|
@ -14,25 +15,39 @@ class SliderComponent extends React.Component {
|
||||||
'handleMouseDown',
|
'handleMouseDown',
|
||||||
'handleMouseUp',
|
'handleMouseUp',
|
||||||
'handleMouseMove',
|
'handleMouseMove',
|
||||||
|
'handleClickBackground',
|
||||||
'setBackground'
|
'setBackground'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseDown () {
|
handleMouseDown () {
|
||||||
document.addEventListener('mouseup', this.handleMouseUp);
|
|
||||||
document.addEventListener('mousemove', this.handleMouseMove);
|
document.addEventListener('mousemove', this.handleMouseMove);
|
||||||
|
document.addEventListener('mouseup', this.handleMouseUp);
|
||||||
|
document.addEventListener('touchmove', this.handleMouseMove);
|
||||||
|
document.addEventListener('touchend', this.handleMouseUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseUp () {
|
handleMouseUp () {
|
||||||
document.removeEventListener('mouseup', this.handleMouseUp);
|
|
||||||
document.removeEventListener('mousemove', this.handleMouseMove);
|
document.removeEventListener('mousemove', this.handleMouseMove);
|
||||||
|
document.removeEventListener('mouseup', this.handleMouseUp);
|
||||||
|
document.removeEventListener('touchmove', this.handleMouseMove);
|
||||||
|
document.removeEventListener('touchend', this.handleMouseUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseMove (event) {
|
handleMouseMove (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
this.props.onChange(this.scaleMouseToSliderPosition(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickBackground (event) {
|
||||||
|
this.props.onChange(this.scaleMouseToSliderPosition(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleMouseToSliderPosition (event){
|
||||||
|
const {x} = getEventXY(event);
|
||||||
const backgroundBBox = this.background.getBoundingClientRect();
|
const backgroundBBox = this.background.getBoundingClientRect();
|
||||||
const x = event.clientX - backgroundBBox.left;
|
const scaledX = x - backgroundBBox.left;
|
||||||
this.props.onChange(Math.max(0, Math.min(100, 100 * x / backgroundBBox.width)));
|
return Math.max(0, Math.min(100, 100 * scaledX / backgroundBBox.width));
|
||||||
}
|
}
|
||||||
|
|
||||||
setBackground (ref) {
|
setBackground (ref) {
|
||||||
|
@ -53,6 +68,7 @@ class SliderComponent extends React.Component {
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: this.props.background
|
backgroundImage: this.props.background
|
||||||
}}
|
}}
|
||||||
|
onClick={this.handleClickBackground}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={styles.handle}
|
className={styles.handle}
|
||||||
|
@ -60,6 +76,7 @@ class SliderComponent extends React.Component {
|
||||||
left: `${handleOffset}px`
|
left: `${handleOffset}px`
|
||||||
}}
|
}}
|
||||||
onMouseDown={this.handleMouseDown}
|
onMouseDown={this.handleMouseDown}
|
||||||
|
onTouchStart={this.handleMouseDown}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,9 +28,9 @@ const hsvToHex = (h, s, v) =>
|
||||||
parseColor(`hsv(${3.6 * h}, ${s}, ${v})`).hex
|
parseColor(`hsv(${3.6 * h}, ${s}, ${v})`).hex
|
||||||
;
|
;
|
||||||
|
|
||||||
// Important! This component ignores new color props and cannot be updated
|
// Important! This component ignores new color props except when isEyeDropping
|
||||||
// This is to make the HSV <=> RGB conversion stable. Because of this, the
|
// This is to make the HSV <=> RGB conversion stable. The sliders manage their
|
||||||
// component MUST be unmounted in order to change the props externally.
|
// own changes until unmounted or color changes with props.isEyeDropping = true.
|
||||||
class ColorPicker extends React.Component {
|
class ColorPicker extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -51,7 +51,7 @@ class ColorPicker extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentWillReceiveProps (newProps) {
|
componentWillReceiveProps (newProps) {
|
||||||
if (this.props.color !== newProps.color) {
|
if (this.props.isEyeDropping && this.props.color !== newProps.color) {
|
||||||
// color set by eye dropper, so update slider states
|
// color set by eye dropper, so update slider states
|
||||||
const hsv = this.getHsv(newProps.color);
|
const hsv = this.getHsv(newProps.color);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -68,16 +68,19 @@ class ColorPicker extends React.Component {
|
||||||
[50, 100, 100] : colorStringToHsv(color);
|
[50, 100, 100] : colorStringToHsv(color);
|
||||||
}
|
}
|
||||||
handleHueChange (hue) {
|
handleHueChange (hue) {
|
||||||
this.setState({hue: hue});
|
this.setState({hue: hue}, () => {
|
||||||
this.handleColorChange();
|
this.handleColorChange();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
handleSaturationChange (saturation) {
|
handleSaturationChange (saturation) {
|
||||||
this.setState({saturation: saturation});
|
this.setState({saturation: saturation}, () => {
|
||||||
this.handleColorChange();
|
this.handleColorChange();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
handleBrightnessChange (brightness) {
|
handleBrightnessChange (brightness) {
|
||||||
this.setState({brightness: brightness});
|
this.setState({brightness: brightness}, () => {
|
||||||
this.handleColorChange();
|
this.handleColorChange();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
handleColorChange () {
|
handleColorChange () {
|
||||||
this.props.onChangeColor(hsvToHex(
|
this.props.onChangeColor(hsvToHex(
|
||||||
|
|
|
@ -140,14 +140,14 @@ class PaintEditor extends React.Component {
|
||||||
const callback = this.props.changeColorToEyeDropper;
|
const callback = this.props.changeColorToEyeDropper;
|
||||||
|
|
||||||
this.eyeDropper.remove();
|
this.eyeDropper.remove();
|
||||||
this.props.previousTool.activate();
|
|
||||||
this.props.onDeactivateEyeDropper();
|
|
||||||
this.stopEyeDroppingLoop();
|
|
||||||
if (!this.eyeDropper.hideLoupe) {
|
if (!this.eyeDropper.hideLoupe) {
|
||||||
// If not hide loupe, that means the click is inside the canvas,
|
// If not hide loupe, that means the click is inside the canvas,
|
||||||
// so apply the new color
|
// so apply the new color
|
||||||
callback(colorString);
|
callback(colorString);
|
||||||
}
|
}
|
||||||
|
this.props.previousTool.activate();
|
||||||
|
this.props.onDeactivateEyeDropper();
|
||||||
|
this.stopEyeDroppingLoop();
|
||||||
this.setState({colorInfo: null});
|
this.setState({colorInfo: null});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/lib/touch-utils.js
Normal file
16
src/lib/touch-utils.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/* DO NOT EDIT
|
||||||
|
@todo This file is copied from GUI and should be pulled out into a shared library.
|
||||||
|
See https://github.com/LLK/scratch-paint/issues/13 */
|
||||||
|
|
||||||
|
const getEventXY = e => {
|
||||||
|
if (e.touches && e.touches[0]) {
|
||||||
|
return {x: e.touches[0].clientX, y: e.touches[0].clientY};
|
||||||
|
} else if (e.changedTouches && e.changedTouches[0]) {
|
||||||
|
return {x: e.changedTouches[0].clientX, y: e.changedTouches[0].clientY};
|
||||||
|
}
|
||||||
|
return {x: e.clientX, y: e.clientY};
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
getEventXY
|
||||||
|
};
|
Loading…
Reference in a new issue