diff --git a/src/components/forms/slider.jsx b/src/components/forms/slider.jsx index f9e455e5..04fdbd87 100644 --- a/src/components/forms/slider.jsx +++ b/src/components/forms/slider.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import bindAll from 'lodash.bindall'; +import {getEventXY} from '../../lib/touch-utils'; import styles from './slider.css'; @@ -14,25 +15,39 @@ class SliderComponent extends React.Component { 'handleMouseDown', 'handleMouseUp', 'handleMouseMove', + 'handleClickBackground', 'setBackground' ]); } handleMouseDown () { - document.addEventListener('mouseup', this.handleMouseUp); document.addEventListener('mousemove', this.handleMouseMove); + document.addEventListener('mouseup', this.handleMouseUp); + document.addEventListener('touchmove', this.handleMouseMove); + document.addEventListener('touchend', this.handleMouseUp); } handleMouseUp () { - document.removeEventListener('mouseup', this.handleMouseUp); document.removeEventListener('mousemove', this.handleMouseMove); + document.removeEventListener('mouseup', this.handleMouseUp); + document.removeEventListener('touchmove', this.handleMouseMove); + document.removeEventListener('touchend', this.handleMouseUp); } handleMouseMove (event) { 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 x = event.clientX - backgroundBBox.left; - this.props.onChange(Math.max(0, Math.min(100, 100 * x / backgroundBBox.width))); + const scaledX = x - backgroundBBox.left; + return Math.max(0, Math.min(100, 100 * scaledX / backgroundBBox.width)); } setBackground (ref) { @@ -53,6 +68,7 @@ class SliderComponent extends React.Component { style={{ backgroundImage: this.props.background }} + onClick={this.handleClickBackground} >
); diff --git a/src/containers/color-picker.jsx b/src/containers/color-picker.jsx index 624e468c..b36f38f6 100644 --- a/src/containers/color-picker.jsx +++ b/src/containers/color-picker.jsx @@ -28,9 +28,9 @@ const hsvToHex = (h, s, v) => parseColor(`hsv(${3.6 * h}, ${s}, ${v})`).hex ; -// Important! This component ignores new color props and cannot be updated -// This is to make the HSV <=> RGB conversion stable. Because of this, the -// component MUST be unmounted in order to change the props externally. +// Important! This component ignores new color props except when isEyeDropping +// This is to make the HSV <=> RGB conversion stable. The sliders manage their +// own changes until unmounted or color changes with props.isEyeDropping = true. class ColorPicker extends React.Component { constructor (props) { super(props); @@ -51,7 +51,7 @@ class ColorPicker extends React.Component { }; } 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 const hsv = this.getHsv(newProps.color); this.setState({ @@ -68,16 +68,19 @@ class ColorPicker extends React.Component { [50, 100, 100] : colorStringToHsv(color); } handleHueChange (hue) { - this.setState({hue: hue}); - this.handleColorChange(); + this.setState({hue: hue}, () => { + this.handleColorChange(); + }); } handleSaturationChange (saturation) { - this.setState({saturation: saturation}); - this.handleColorChange(); + this.setState({saturation: saturation}, () => { + this.handleColorChange(); + }); } handleBrightnessChange (brightness) { - this.setState({brightness: brightness}); - this.handleColorChange(); + this.setState({brightness: brightness}, () => { + this.handleColorChange(); + }); } handleColorChange () { this.props.onChangeColor(hsvToHex( diff --git a/src/containers/paint-editor.jsx b/src/containers/paint-editor.jsx index 637e6a3d..ea2d5fe2 100644 --- a/src/containers/paint-editor.jsx +++ b/src/containers/paint-editor.jsx @@ -140,14 +140,14 @@ class PaintEditor extends React.Component { const callback = this.props.changeColorToEyeDropper; this.eyeDropper.remove(); - this.props.previousTool.activate(); - this.props.onDeactivateEyeDropper(); - this.stopEyeDroppingLoop(); if (!this.eyeDropper.hideLoupe) { // If not hide loupe, that means the click is inside the canvas, // so apply the new color callback(colorString); } + this.props.previousTool.activate(); + this.props.onDeactivateEyeDropper(); + this.stopEyeDroppingLoop(); this.setState({colorInfo: null}); } } diff --git a/src/lib/touch-utils.js b/src/lib/touch-utils.js new file mode 100644 index 00000000..df1897b3 --- /dev/null +++ b/src/lib/touch-utils.js @@ -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 +};