UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

142 lines (126 loc) 5.67 kB
import {AnimationCurve} from "../AnimationCurve.js"; import {DraggableAspect} from "../../../ui/DraggableAspect.js"; import {position_canvas_to_curve} from "../draw/position_canvas_to_curve.js"; import Vector2 from "../../../../core/geom/Vector2.js"; import {updateKeyframePosition} from "./updateKeyframePosition.js"; import {number_pretty_print} from "../../../../core/primitives/numbers/number_pretty_print.js"; import {applyActionMove} from "../actionProcessorOperations/applyActionChange.js"; /** * * @param {element} markerElement * @param {CanvasView} graph * @param {AABB2} frame * @param {Vector2} margin * @param {AABB2} validEditableBounds * @param {AnimationCurve} curve * @param {function} fnUpdateGraph * @param {Keyframe} keyframe * @param {List} selectedKeyframes * @param {ObservedValue} activeKeyframe * @param {LabelView} keyCoordinateDisplay * @param {function} fnUpdateMarkerPosition * @param {Signal} frameUpdated * @param {Signal} keyframeChange * @param {EmptyView} vContainer * @param {ActionProcessor} actionProcessor * @param {keyframesContext} actionProcessorCTX * @returns {DraggableAspect} */ export function createKeyframeDraggableAspect({ markerElement, graph, frame, margin, validEditableBounds, curve, fnUpdateGraph, keyframe, selectedKeyframes, activeKeyframe, keyCoordinateDisplay, fnUpdateMarkerPosition, frameUpdated, keyframeChange, vContainer, actionProcessor, actionProcessorCTX }) { const curveSet = { curveStartIndices: new AnimationCurve(), curveStartValues: new AnimationCurve(), curveEndIndices: new AnimationCurve(), curveEndValue: new AnimationCurve(), } return new DraggableAspect({ el: markerElement, drag(position) { const moveKeyframeToCoord = position_canvas_to_curve( graph.size, frame, margin, position.x, position.y ); if (isMovingOutOfBounds(moveKeyframeToCoord, keyframe, validEditableBounds, selectedKeyframes)) { const deltaPosition = new Vector2( moveKeyframeToCoord.x - keyframe.time, moveKeyframeToCoord.y - keyframe.value ) selectedKeyframes.forEach((selKf) => { if (activeKeyframe.get() !== selKf) { updateKeyframePosition(selKf, deltaPosition, curve); } }); updateKeyframePosition(keyframe, deltaPosition, curve); } keyCoordinateDisplay.updateText(`${number_pretty_print(moveKeyframeToCoord.x)}, ${number_pretty_print(moveKeyframeToCoord.y)}`); keyCoordinateDisplay.position.set( position.x, position.y - 24 ); fnUpdateMarkerPosition(); frameUpdated.send0(); fnUpdateGraph(); keyframeChange.send0(); }, dragStart() { activeKeyframe.set(keyframe); curveSet.curveStartIndices.clear() curveSet.curveStartIndices.addMany(curve.keys) curveSet.curveStartValues.copy(curve); //deep copy vContainer.addChild(keyCoordinateDisplay); }, dragEnd() { curveSet.curveEndIndices.clear() curveSet.curveEndIndices.addMany(curve.keys) curveSet.curveEndValue.copy(curve); //deep copy vContainer.removeChild(keyCoordinateDisplay); //Reset back before action processor for (let i = 0; i < curve.length; i++) { curve.keys[i] = curveSet.curveStartIndices.keys[i]; curve.keys[i].copy(curveSet.curveStartValues.keys[i]); } applyActionMove('move keyframe(s)', curveSet, actionProcessor, actionProcessorCTX); } }); } /** * Check if new keyframe position is in the valid bounds * @param {Vector2} newCoord * @param {Keyframe} keyframe * @param {AABB2} validBounds * @param {List} selectedKeyframes * @returns {boolean} */ function isMovingOutOfBounds(newCoord, keyframe, validBounds, selectedKeyframes) { const transitionVector = newCoord.clone()._sub(keyframe.time, keyframe.value); const isSelectionOutOfBound = (kf) => { const adjustedCord = transitionVector.clone()._add(kf.time, kf.value); return (!validBounds.containsPoint(adjustedCord.x, adjustedCord.y)) }; if (!validBounds.containsPoint(newCoord.x, newCoord.y) || selectedKeyframes.some(isSelectionOutOfBound)) { return false; } //all checks passed return true; }