Doodle3D-Core/src/reducer/d2/tools/shapes/circleReducer.js

76 lines
2.3 KiB
JavaScript

import update from 'react-addons-update';
import { Matrix, Vector } from '@doodle3d/cal';
import * as actions from '../../../../actions/index.js';
import { addObjectActive2D, addObject, setActive2D } from '../../../objectReducers.js';
import createDebug from 'debug';
const debug = createDebug('d3d:reducer:circle');
const DEFAULT_RADIUS = 25;
const DEFAULT_SEGMENT = Math.PI * 0.5; // for segmented circle
const MAX_SEGMENT = Math.PI * 2;
export default function circleReducer(state, action, segmented = false) {
if (action.log !== false) debug(action.type);
const { position, screenMatrixZoom } = action;
let scenePosition;
if (position !== undefined && screenMatrixZoom !== undefined) {
scenePosition = position.applyMatrix(screenMatrixZoom.inverseMatrix());
}
const activeShape = state.d2.activeShape;
switch (action.type) {
case actions.D2_DRAG_START: {
return addObjectActive2D(state, {
type: (segmented ? 'CIRCLE_SEGMENT' : 'CIRCLE'),
transform: new Matrix({ x: scenePosition.x, y: scenePosition.y })
});
}
case actions.D2_DRAG: {
if (activeShape) {
const beginPos = new Vector().copy(state.objectsById[activeShape].transform);
const delta = scenePosition.subtract(beginPos);
let segment;
if (segmented) {
segment = (delta.angle() + Math.PI * 2.5) % MAX_SEGMENT;
} else {
segment = MAX_SEGMENT;
}
const radius = delta.length();
state = updateCircle(state, activeShape, radius, segment);
}
return state;
}
case actions.D2_DRAG_END: {
if (activeShape) {
state = setActive2D(state, null);
}
return state;
}
case actions.D2_TAP: {
const segment = segmented ? DEFAULT_SEGMENT : MAX_SEGMENT;
return addObject(state, {
type: (segmented ? 'CIRCLE_SEGMENT' : 'CIRCLE'),
transform: new Matrix({ x: scenePosition.x, y: scenePosition.y }),
circle: {
radius: DEFAULT_RADIUS,
segment
}
});
}
default:
return state;
}
}
function updateCircle(state, id, radius, segment) {
return update(state, {
objectsById: {
[id]: {
circle: {
radius: { $set: radius },
segment: { $set: segment }
}
}
}
});
}