@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
142 lines (126 loc) • 5.67 kB
JavaScript
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;
}