From 07b30aa55bd9343d428939a3c74b987197ad9bea Mon Sep 17 00:00:00 2001 From: DD Date: Thu, 21 Dec 2017 14:49:05 -0500 Subject: [PATCH] Handle pointed and curved --- src/components/mode-tools/mode-tools.jsx | 13 ++- src/containers/mode-tools.jsx | 109 ++++++++++++++++++++-- src/helper/selection-tools/handle-tool.js | 1 + src/reducers/selected-items.js | 2 +- 4 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/components/mode-tools/mode-tools.jsx b/src/components/mode-tools/mode-tools.jsx index d46cf71f..70a47d8f 100644 --- a/src/components/mode-tools/mode-tools.jsx +++ b/src/components/mode-tools/mode-tools.jsx @@ -95,18 +95,18 @@ const ModeToolsComponent = props => { return (
); @@ -154,13 +154,16 @@ ModeToolsComponent.propTypes = { className: PropTypes.string, clipboardItems: PropTypes.arrayOf(PropTypes.array), eraserValue: PropTypes.number, - hasSelectedPoints: PropTypes.bool, + hasSelectedUncurvedPoints: PropTypes.bool, + hasSelectedUnpointedPoints: PropTypes.bool, intl: intlShape.isRequired, mode: PropTypes.string.isRequired, onBrushSliderChange: PropTypes.func, onCopyToClipboard: PropTypes.func.isRequired, + onCurvePoints: PropTypes.func.isRequired, onEraserSliderChange: PropTypes.func, onPasteFromClipboard: PropTypes.func.isRequired, + onPointPoints: PropTypes.func.isRequired, selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)) }; diff --git a/src/containers/mode-tools.jsx b/src/containers/mode-tools.jsx index 58ac3e87..2c5660f8 100644 --- a/src/containers/mode-tools.jsx +++ b/src/containers/mode-tools.jsx @@ -13,21 +13,115 @@ class ModeTools extends React.Component { constructor (props) { super(props); bindAll(this, [ - 'hasSelectedPoints', + '_getSelectedUncurvedPoints', + '_getSelectedUnpointedPoints', + 'hasSelectedUncurvedPoints', + 'hasSelectedUnpointedPoints', 'handleCopyToClipboard', - 'handlePasteFromClipboard' + 'handleCurvePoints', + 'handlePasteFromClipboard', + 'handlePointPoints' ]); } - hasSelectedPoints () { + _getSelectedUncurvedPoints () { + const items = []; const selectedItems = getSelectedLeafItems(); for (const item of selectedItems) { + if (!item.segments) continue; for (const seg of item.segments) { if (seg.selected) { - return true; + const prev = seg.getPrevious(); + const next = seg.getNext(); + const isCurved = + (!prev || seg.handleIn.length > 0) && + (!next || seg.handleOut.length > 0) && + (prev && next ? seg.handleOut.isColinear(seg.handleIn) : true); + if (!isCurved) items.push(seg); } } } - return false; + return items; + } + _getSelectedUnpointedPoints () { + const points = []; + const selectedItems = getSelectedLeafItems(); + for (const item of selectedItems) { + if (!item.segments) continue; + for (const seg of item.segments) { + if (seg.selected) { + if (seg.handleIn.length > 0 || seg.handleOut.length > 0) { + points.push(seg); + } + } + } + } + return points; + } + hasSelectedUncurvedPoints () { + const points = this._getSelectedUncurvedPoints(); + return points.length > 0; + } + hasSelectedUnpointedPoints () { + const points = this._getSelectedUnpointedPoints(); + return points.length > 0; + } + handleCurvePoints () { + let changed; + const points = this._getSelectedUncurvedPoints(); + for (const point of points) { + const prev = point.getPrevious(); + const next = point.getNext(); + const noHandles = point.handleIn.length === 0 && point.handleOut.length === 0; + if (!prev && !next) { + continue; + } else if (prev && (!next || noHandles)) { + // Point is end point or has no handles + // Direction is average of normal at the point and direction to prev point + // Lenth is curve length / 2 + point.handleIn = (prev.getCurve().getNormalAtTime(1) + .add(prev.point.subtract(point.point).normalize())) + .normalize() + .multiply(prev.getCurve().length / 2); + } else if (next && !prev) { + // Point is start point + // Direction is average of normal at the point and direction to next point + // Lenth is curve length / 2 + point.handleOut = (point.getCurve().getNormalAtTime(0) + .add(next.point.subtract(point.point).normalize())) + .normalize() + .multiply(point.getCurve().length / 2); + } + + // Point guaranteed to have a handle now. Make the second handle match the length and direction of first. + // This defines a curved point. + if (point.handleIn.length > 0 && next) { + point.handleOut = point.handleIn.multiply(-1); + } else if (point.handleOut.length > 0 && prev) { + point.handleIn = point.handleOut.multiply(-1); + } + changed = true; + } + if (changed) { + this.props.setSelectedItems(); + this.props.onUpdateSvg(); + } + } + handlePointPoints () { + let changed; + const points = this._getSelectedUnpointedPoints(); + for (const point of points) { + const noHandles = point.handleIn.length === 0 && point.handleOut.length === 0; + if (!noHandles) { + point.handleIn = null; + point.handleOut = null; + changed = true; + } + } + if (changed) { + debugger; + this.props.setSelectedItems(); + this.props.onUpdateSvg(); + } } handleCopyToClipboard () { const selectedItems = getSelectedRootItems(); @@ -62,9 +156,12 @@ class ModeTools extends React.Component { render () { return ( ); } diff --git a/src/helper/selection-tools/handle-tool.js b/src/helper/selection-tools/handle-tool.js index cbf78770..305681fd 100644 --- a/src/helper/selection-tools/handle-tool.js +++ b/src/helper/selection-tools/handle-tool.js @@ -79,6 +79,7 @@ class HandleTool { } } if (moved) { + this.setSelectedItems(); this.onUpdateSvg(); } this.selectedItems = []; diff --git a/src/reducers/selected-items.js b/src/reducers/selected-items.js index 67a2d147..b3397aec 100644 --- a/src/reducers/selected-items.js +++ b/src/reducers/selected-items.js @@ -14,7 +14,7 @@ const reducer = function (state, action) { if (action.selectedItems.length !== state.length) { return action.selectedItems; } - // Shallow equality check (we may need to update this later for more granularity) + // Shallow equality check for (let i = 0; i < action.selectedItems.length; i++) { if (action.selectedItems[i] !== state[i]) { return action.selectedItems;