2017-10-11 11:32:51 -04:00
|
|
|
import {clearSelection, getSelectedLeafItems} from '../selection';
|
2017-09-21 10:36:26 -04:00
|
|
|
|
2017-09-22 14:14:48 -04:00
|
|
|
/** Sub tool of the Reshape tool for moving handles, which adjust bezier curves. */
|
2017-09-21 10:36:26 -04:00
|
|
|
class HandleTool {
|
2017-09-21 18:20:44 -04:00
|
|
|
/**
|
2017-10-02 15:25:04 -04:00
|
|
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
|
|
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
2017-09-21 18:20:44 -04:00
|
|
|
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
|
|
|
*/
|
2017-10-02 15:25:04 -04:00
|
|
|
constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
2017-09-21 10:36:26 -04:00
|
|
|
this.hitType = null;
|
2017-10-02 15:25:04 -04:00
|
|
|
this.setSelectedItems = setSelectedItems;
|
|
|
|
this.clearSelectedItems = clearSelectedItems;
|
2017-09-21 18:20:44 -04:00
|
|
|
this.onUpdateSvg = onUpdateSvg;
|
2017-09-21 10:36:26 -04:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @param {!object} hitProperties Describes the mouse event
|
|
|
|
* @param {?boolean} hitProperties.multiselect Whether to multiselect on mouse down (e.g. shift key held)
|
|
|
|
* select the whole group.
|
|
|
|
*/
|
|
|
|
onMouseDown (hitProperties) {
|
|
|
|
if (!hitProperties.multiselect) {
|
2017-10-02 15:25:04 -04:00
|
|
|
clearSelection(this.clearSelectedItems);
|
2017-09-21 10:36:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
hitProperties.hitResult.segment.handleIn.selected = true;
|
|
|
|
hitProperties.hitResult.segment.handleOut.selected = true;
|
|
|
|
this.hitType = hitProperties.hitResult.type;
|
|
|
|
}
|
|
|
|
onMouseDrag (event) {
|
2017-10-11 11:32:51 -04:00
|
|
|
const selectedItems = getSelectedLeafItems();
|
2017-09-21 10:36:26 -04:00
|
|
|
|
|
|
|
for (const item of selectedItems) {
|
|
|
|
for (const seg of item.segments) {
|
|
|
|
// add the point of the segment before the drag started
|
|
|
|
// for later use in the snap calculation
|
|
|
|
if (!seg.origPoint) {
|
|
|
|
seg.origPoint = seg.point.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg.handleOut.selected && this.hitType === 'handle-out'){
|
|
|
|
// if option is pressed or handles have been split,
|
|
|
|
// they're no longer parallel and move independently
|
|
|
|
if (event.modifiers.option ||
|
|
|
|
!seg.handleOut.isColinear(seg.handleIn)) {
|
|
|
|
seg.handleOut = seg.handleOut.add(event.delta);
|
|
|
|
} else {
|
|
|
|
const oldLength = seg.handleOut.length;
|
|
|
|
seg.handleOut = seg.handleOut.add(event.delta);
|
|
|
|
seg.handleIn = seg.handleOut.multiply(-seg.handleIn.length / oldLength);
|
|
|
|
}
|
|
|
|
} else if (seg.handleIn.selected && this.hitType === 'handle-in') {
|
|
|
|
// if option is pressed or handles have been split,
|
|
|
|
// they're no longer parallel and move independently
|
|
|
|
if (event.modifiers.option ||
|
|
|
|
!seg.handleOut.isColinear(seg.handleIn)) {
|
|
|
|
seg.handleIn = seg.handleIn.add(event.delta);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
const oldLength = seg.handleIn.length;
|
|
|
|
seg.handleIn = seg.handleIn.add(event.delta);
|
|
|
|
seg.handleOut = seg.handleIn.multiply(-seg.handleOut.length / oldLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onMouseUp () {
|
|
|
|
// @todo add back undo
|
2017-09-21 18:20:44 -04:00
|
|
|
this.onUpdateSvg();
|
2017-09-21 10:36:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default HandleTool;
|