浏览代码

added keyframeTimeChanged event. Allow to prevent drag events.

Ievgen Naida 5 年之前
父节点
当前提交
91c76c0882

+ 4 - 2
README.md

@@ -96,11 +96,13 @@ Read only and defined by the interfaces:
 | dragStarted               | emitted on drag started. args type: TimelineDragEvent        |
 | drag                      | emitted when dragging. args type: TimelineDragEvent   	|
 | dragFinished              | emitted when drag finished. args type: TimelineDragEvent     	|
+| KeyframeChanged              | emitted when drag finished. args type: TimelineKeyframeChangedEvent   |
 
+Each event can be prevented by calling args.preventDefault()
 
-Type strict event subscription: 
+Example of the type strict event subscription: 
 ```JavaScript
-this.timeline.onDragStarted((args) => {
+this.timeline.onDragStarted((args:TimelineDragEvent) => {
     if (args) {
     }
 });

+ 3 - 7
index.html

@@ -375,13 +375,9 @@
     });
     timeline.onDrag(function (obj) {
       logDraggingMessage(obj, 'drag');
-      // obj.preventDefault();
-      //  return;
-      if (obj.row && obj.type == 'keyframe' && obj.val <= 3000) {
-        e.preventDefault();
-      } else {
-
-      }
+    });
+    timeline.onKeyframeChanged(function (obj) {
+      console.log('keyframe: ' + obj.val);
     });
     timeline.onDragFinished(function (obj) {
       logDraggingMessage(obj, 'dragfinished');

+ 4 - 1
lib/animation-timeline.d.ts

@@ -17,16 +17,19 @@ export { TimelineCutBoundsRectResults } from './utils/timelineCutBoundsRectResul
 export { TimelineSelectionResults } from './utils/timelineSelectionResults';
 export { TimelineValues } from './utils/timelineValues';
 export { TimelineMouseData } from './utils/timelineMouseData';
+export { TimelineElementDragState } from './utils/timelineDraggableData';
+export { TimelineDraggableData } from './utils/timelineDraggableData';
 export { TimelineModelCalcResults } from './utils/timelineModelCalcResults';
 export { TimelineCalculatedRow } from './utils/timelineModelCalcResults';
 export { TimelineCalculatedGroup } from './utils/timelineModelCalcResults';
 export { TimelineCalculated } from './utils/timelineModelCalcResults';
 export { TimelineCalculatedKeyframe } from './utils/timelineModelCalcResults';
+export { TimelineKeyframeChangedEvent } from './utils/events/timelineKeyframeChangedEvent';
+export { TimelineTimeChangedEvent } from './utils/events/timelineTimeChangedEvent';
 export { TimelineSelectedEvent } from './utils/events/timelineSelectedEvent';
 export { TimelineScrollEvent } from './utils/events/timelineScrollEvent';
 export { TimelineClickEvent } from './utils/events/timelineClickEvent';
 export { TimelineDragEvent } from './utils/events/timelineDragEvent';
-export { TimelineTimeChangedEvent } from './utils/events/timelineTimeChangedEvent';
 export { TimelineEvents } from './enums/timelineEvents';
 export { TimelineKeyframeShape } from './enums/timelineKeyframeShape';
 export { TimelineInteractionMode } from './enums/timelineInteractionMode';

+ 255 - 54
lib/animation-timeline.js

@@ -91,7 +91,7 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/
 /******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __webpack_require__(__webpack_require__.s = 17);
+/******/ 	return __webpack_require__(__webpack_require__.s = 18);
 /******/ })
 /************************************************************************/
 /******/ ([
@@ -198,6 +198,12 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ }),
 /* 17 */
+/***/ (function(module, exports) {
+
+
+
+/***/ }),
+/* 18 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -224,16 +230,19 @@ __webpack_require__.d(__webpack_exports__, "TimelineCutBoundsRectResults", funct
 __webpack_require__.d(__webpack_exports__, "TimelineSelectionResults", function() { return /* reexport */ timelineSelectionResults["TimelineSelectionResults"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineValues", function() { return /* reexport */ timelineValues["TimelineValues"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineMouseData", function() { return /* reexport */ timelineMouseData["TimelineMouseData"]; });
+__webpack_require__.d(__webpack_exports__, "TimelineElementDragState", function() { return /* reexport */ timelineDraggableData["TimelineElementDragState"]; });
+__webpack_require__.d(__webpack_exports__, "TimelineDraggableData", function() { return /* reexport */ timelineDraggableData["TimelineDraggableData"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineModelCalcResults", function() { return /* reexport */ timelineModelCalcResults["TimelineModelCalcResults"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineCalculatedRow", function() { return /* reexport */ timelineModelCalcResults["TimelineCalculatedRow"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineCalculatedGroup", function() { return /* reexport */ timelineModelCalcResults["TimelineCalculatedGroup"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineCalculated", function() { return /* reexport */ timelineModelCalcResults["TimelineCalculated"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineCalculatedKeyframe", function() { return /* reexport */ timelineModelCalcResults["TimelineCalculatedKeyframe"]; });
+__webpack_require__.d(__webpack_exports__, "TimelineKeyframeChangedEvent", function() { return /* reexport */ TimelineKeyframeChangedEvent; });
+__webpack_require__.d(__webpack_exports__, "TimelineTimeChangedEvent", function() { return /* reexport */ timelineTimeChangedEvent_TimelineTimeChangedEvent; });
 __webpack_require__.d(__webpack_exports__, "TimelineSelectedEvent", function() { return /* reexport */ TimelineSelectedEvent; });
 __webpack_require__.d(__webpack_exports__, "TimelineScrollEvent", function() { return /* reexport */ timelineScrollEvent["TimelineScrollEvent"]; });
 __webpack_require__.d(__webpack_exports__, "TimelineClickEvent", function() { return /* reexport */ TimelineClickEvent; });
 __webpack_require__.d(__webpack_exports__, "TimelineDragEvent", function() { return /* reexport */ TimelineDragEvent; });
-__webpack_require__.d(__webpack_exports__, "TimelineTimeChangedEvent", function() { return /* reexport */ timelineTimeChangedEvent_TimelineTimeChangedEvent; });
 __webpack_require__.d(__webpack_exports__, "TimelineEvents", function() { return /* reexport */ TimelineEvents; });
 __webpack_require__.d(__webpack_exports__, "TimelineKeyframeShape", function() { return /* reexport */ TimelineKeyframeShape; });
 __webpack_require__.d(__webpack_exports__, "TimelineInteractionMode", function() { return /* reexport */ TimelineInteractionMode; });
@@ -824,7 +833,7 @@ var TimelineEvents;
 (function (TimelineEvents) {
   TimelineEvents["Selected"] = "selected";
   TimelineEvents["TimeChanged"] = "timechanged";
-  TimelineEvents["KeyframeTimeChanged"] = "keyframeTimeChanged";
+  TimelineEvents["KeyframeChanged"] = "keyframeChanged";
   TimelineEvents["DragStarted"] = "dragStarted";
   TimelineEvents["Drag"] = "drag";
   TimelineEvents["DragFinished"] = "dragFinished";
@@ -1005,20 +1014,46 @@ function timelineDragEvent_isNativeReflectConstruct() { if (typeof Reflect === "
 
 function timelineDragEvent_getPrototypeOf(o) { timelineDragEvent_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return timelineDragEvent_getPrototypeOf(o); }
 
+function timelineDragEvent_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
 
-var TimelineDragEvent = /*#__PURE__*/function (_TimelineClickEvent) {
-  timelineDragEvent_inherits(TimelineDragEvent, _TimelineClickEvent);
+var TimelineDragEvent = /*#__PURE__*/function (_TimelineBaseEvent) {
+  timelineDragEvent_inherits(TimelineDragEvent, _TimelineBaseEvent);
 
   var _super = timelineDragEvent_createSuper(TimelineDragEvent);
 
   function TimelineDragEvent() {
+    var _this;
+
     timelineDragEvent_classCallCheck(this, TimelineDragEvent);
 
-    return _super.apply(this, arguments);
+    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
+
+    _this = _super.call.apply(_super, [this].concat(args));
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "args", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "pos", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "elements", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "target", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "val", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "prevVal", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "snapVal", void 0);
+
+    timelineDragEvent_defineProperty(timelineDragEvent_assertThisInitialized(_this), "originalVal", void 0);
+
+    return _this;
   }
 
   return TimelineDragEvent;
-}(TimelineClickEvent);
+}(TimelineBaseEvent);
 // CONCATENATED MODULE: ./src/settings/defaults.ts
 
 
@@ -1271,6 +1306,57 @@ var TimelineSelectionMode;
   TimelineSelectionMode["Append"] = "append";
   TimelineSelectionMode["Revert"] = "revert";
 })(TimelineSelectionMode || (TimelineSelectionMode = {}));
+// CONCATENATED MODULE: ./src/utils/events/timelineKeyframeChangedEvent.ts
+function timelineKeyframeChangedEvent_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { timelineKeyframeChangedEvent_typeof = function _typeof(obj) { return typeof obj; }; } else { timelineKeyframeChangedEvent_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return timelineKeyframeChangedEvent_typeof(obj); }
+
+function timelineKeyframeChangedEvent_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function timelineKeyframeChangedEvent_inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) timelineKeyframeChangedEvent_setPrototypeOf(subClass, superClass); }
+
+function timelineKeyframeChangedEvent_setPrototypeOf(o, p) { timelineKeyframeChangedEvent_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return timelineKeyframeChangedEvent_setPrototypeOf(o, p); }
+
+function timelineKeyframeChangedEvent_createSuper(Derived) { var hasNativeReflectConstruct = timelineKeyframeChangedEvent_isNativeReflectConstruct(); return function () { var Super = timelineKeyframeChangedEvent_getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = timelineKeyframeChangedEvent_getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return timelineKeyframeChangedEvent_possibleConstructorReturn(this, result); }; }
+
+function timelineKeyframeChangedEvent_possibleConstructorReturn(self, call) { if (call && (timelineKeyframeChangedEvent_typeof(call) === "object" || typeof call === "function")) { return call; } return timelineKeyframeChangedEvent_assertThisInitialized(self); }
+
+function timelineKeyframeChangedEvent_assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function timelineKeyframeChangedEvent_isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
+
+function timelineKeyframeChangedEvent_getPrototypeOf(o) { timelineKeyframeChangedEvent_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return timelineKeyframeChangedEvent_getPrototypeOf(o); }
+
+function timelineKeyframeChangedEvent_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+
+var TimelineKeyframeChangedEvent = /*#__PURE__*/function (_TimelineBaseEvent) {
+  timelineKeyframeChangedEvent_inherits(TimelineKeyframeChangedEvent, _TimelineBaseEvent);
+
+  var _super = timelineKeyframeChangedEvent_createSuper(TimelineKeyframeChangedEvent);
+
+  function TimelineKeyframeChangedEvent() {
+    var _this;
+
+    timelineKeyframeChangedEvent_classCallCheck(this, TimelineKeyframeChangedEvent);
+
+    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
+
+    _this = _super.call.apply(_super, [this].concat(args));
+
+    timelineKeyframeChangedEvent_defineProperty(timelineKeyframeChangedEvent_assertThisInitialized(_this), "val", void 0);
+
+    timelineKeyframeChangedEvent_defineProperty(timelineKeyframeChangedEvent_assertThisInitialized(_this), "prevVal", void 0);
+
+    timelineKeyframeChangedEvent_defineProperty(timelineKeyframeChangedEvent_assertThisInitialized(_this), "target", void 0);
+
+    timelineKeyframeChangedEvent_defineProperty(timelineKeyframeChangedEvent_assertThisInitialized(_this), "source", void 0);
+
+    return _this;
+  }
+
+  return TimelineKeyframeChangedEvent;
+}(TimelineBaseEvent);
 // CONCATENATED MODULE: ./src/timeline.ts
 function timeline_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { timeline_typeof = function _typeof(obj) { return typeof obj; }; } else { timeline_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return timeline_typeof(obj); }
 
@@ -1317,6 +1403,7 @@ function timeline_defineProperty(obj, key, value) { if (key in obj) { Object.def
 
 
 
+
 var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
   timeline_inherits(Timeline, _TimelineEventsEmitte);
 
@@ -1552,7 +1639,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       if (target && _this._interactionMode !== TimelineInteractionMode.Zoom) {
         _this._drag = {
           changed: false,
-          target: target,
+          target: _this._setElementDragState(target, target.val),
           val: target.val,
           type: target.type,
           elements: []
@@ -1567,12 +1654,17 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
           } // Allow to drag all selected keyframes on a screen
 
 
-          _this._drag.elements = _this.getSelectedElements();
+          _this._drag.elements = _this.getSelectedElements().map(function (element) {
+            return _this._setElementDragState(element, element.val);
+          });
         } else if (target.type === TimelineElementType.Group) {
           var keyframes = _this._drag.target.keyframes;
-          _this._drag.elements = keyframes && Array.isArray(keyframes) ? keyframes.map(function (keyframe) {
-            return _this._convertToElement(_this._drag.target.row, keyframe);
-          }) : [];
+
+          if (keyframes && Array.isArray(keyframes)) {
+            _this._drag.elements = keyframes.map(function (keyframe) {
+              return _this._setElementDragState(_this._convertToElement(_this._drag.target.row, keyframe), keyframe.val);
+            });
+          }
         } else {
           _this._drag.elements = [_this._drag.target];
         }
@@ -1616,13 +1708,20 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
             } else if ((_this._drag.type == TimelineElementType.Keyframe || _this._drag.type == TimelineElementType.Group) && _this._drag.elements) {
               var offset = Math.floor(convertedVal - _this._drag.val);
 
-              var movedOffset = _this._moveElements(offset, _this._drag.elements);
+              var movedOffset = _this._moveElements(offset, _this._drag.elements, TimelineEventSource.User);
 
               if (movedOffset !== 0) {
                 if (!_this._drag.changed) {
+                  _this._drag.prevVal = _this._drag.val;
+
                   var _eventArgs = _this._emitDragStartedEvent();
 
                   if (_eventArgs.isPrevented()) {
+                    // Cleanup drag here, so drag finished will be ignored.
+                    _this._drag = null;
+
+                    _this._cleanUpSelection();
+
                     return;
                   }
                 }
@@ -2048,6 +2147,23 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
      * @param args
      */
 
+  }, {
+    key: "_setElementDragState",
+    value: function _setElementDragState(element, val) {
+      var state = element;
+      state.prevVal = state.val;
+
+      if (state.startedVal === undefined || state.startedVal === null) {
+        state.startedVal = val;
+      }
+
+      if (state.prevVal === undefined || state.prevVal === null) {
+        state.prevVal = val;
+      }
+
+      state.val = val;
+      return state;
+    }
   }, {
     key: "isLeftButtonClicked",
     value: function isLeftButtonClicked(args) {
@@ -2066,6 +2182,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
     value: function _moveElements(offset, elements) {
       var _this2 = this;
 
+      var source = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : TimelineEventSource.Programmatically;
+
       if (!elements) {
         return;
       }
@@ -2103,12 +2221,12 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
         if (Math.abs(offset) > 0) {
           // don't allow to move less than zero.
           elements.forEach(function (element) {
-            var toSet = element.keyframe.val + offset;
-            isChanged = _this2._setKeyframePos(element.keyframe, toSet) || isChanged;
+            var prevVal = element.keyframe.val;
+            var toSet = prevVal + offset;
 
-            if (isChanged) {
-              element.val = element.keyframe.val;
-            }
+            var newValue = _this2._setKeyframePos(element, toSet, source);
+
+            isChanged = newValue !== prevVal;
           });
         }
 
@@ -2217,19 +2335,36 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
      * Set keyframe value.
      * @param keyframe
      * @param value
+     * @return set value.
      */
 
   }, {
     key: "_setKeyframePos",
-    value: function _setKeyframePos(keyframe, value) {
+    value: function _setKeyframePos(element, value) {
+      var source = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : TimelineEventSource.Programmatically;
+
+      if (!element || !element.keyframe) {
+        return value;
+      }
+
       value = Math.floor(value);
 
-      if (keyframe && keyframe.val != value) {
-        keyframe.val = value;
-        return true;
+      if (element.keyframe && element.keyframe.val != value) {
+        element.prevVal = element.val;
+        element.val = value;
+        element.keyframe.val = value;
+
+        var event = this._emitKeyframeChanged(element, source);
+
+        if (event.isPrevented()) {
+          element.val = event.prevVal;
+          element.keyframe.val = event.prevVal;
+        }
+
+        return value;
       }
 
-      return false;
+      return value;
     }
     /**
      * @param cursor to set.
@@ -4061,6 +4196,15 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
     value: function onDoubleClick(callback) {
       this.on(TimelineEvents.DoubleClick, callback);
     }
+    /**
+     * Subscribe on keyframe changed event.
+     */
+
+  }, {
+    key: "onKeyframeChanged",
+    value: function onKeyframeChanged(callback) {
+      this.on(TimelineEvents.KeyframeChanged, callback);
+    }
     /**
      * Subscribe on drag finished event.
      */
@@ -4099,12 +4243,29 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
 
       return scrollEvent;
     }
+  }, {
+    key: "_emitKeyframeChanged",
+    value: function _emitKeyframeChanged(element) {
+      var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : TimelineEventSource.Programmatically;
+      var args = new TimelineKeyframeChangedEvent();
+      args.val = element.val;
+      args.prevVal = element.prevVal;
+      args.target = element;
+      args.source = source;
+      this.emit(TimelineEvents.KeyframeChanged, args);
+      return args;
+    }
   }, {
     key: "_emitDragStartedEvent",
     value: function _emitDragStartedEvent() {
       var args = this._getDragEventArgs();
 
       this.emit(TimelineEvents.DragStarted, args);
+
+      if (args.isPrevented()) {
+        this._preventDrag(args, this._drag, true);
+      }
+
       return args;
     }
   }, {
@@ -4114,20 +4275,50 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
         var args = this._getDragEventArgs();
 
         this.emit(TimelineEvents.DragFinished, args);
+
+        if (args.isPrevented()) {
+          this._preventDrag(args, this._drag, true);
+        }
+
         return args;
       }
+
+      return null;
+    }
+  }, {
+    key: "_preventDrag",
+    value: function _preventDrag(dragArgs, data) {
+      var _this11 = this;
+
+      var toStart = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+      if (dragArgs.elements) {
+        dragArgs.elements.forEach(function (element) {
+          var toSet = toStart ? element.startedVal : element.prevVal;
+
+          _this11._setKeyframePos(element, toSet);
+        });
+      }
+
+      data.val = data.prevVal;
+      dragArgs.val = dragArgs.prevVal;
     }
   }, {
     key: "_emitDragEvent",
     value: function _emitDragEvent() {
-      if (this._drag) {
-        var args = this._getDragEventArgs();
+      if (!this._drag) {
+        return null;
+      }
 
-        this.emit(TimelineEvents.Drag, args);
-        return args;
+      var args = this._getDragEventArgs();
+
+      this.emit(TimelineEvents.Drag, args);
+
+      if (args.isPrevented()) {
+        this._preventDrag(args, this._drag, false);
       }
 
-      return null;
+      return args;
     }
   }, {
     key: "_emitKeyframesSelected",
@@ -4143,13 +4334,16 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
     value: function _getDragEventArgs() {
       var draggableArguments = new TimelineDragEvent();
 
-      if (this._drag) {
-        draggableArguments.val = this._currentPos.val;
-        draggableArguments.pos = this._currentPos;
-        draggableArguments.elements = this._drag.elements;
-        draggableArguments.target = this._drag.target;
+      if (!this._drag) {
+        return draggableArguments;
       }
 
+      draggableArguments.val = this._currentPos.val;
+      draggableArguments.originalVal = this._currentPos.originalVal;
+      draggableArguments.snapVal = this._currentPos.snapVal;
+      draggableArguments.pos = this._currentPos;
+      draggableArguments.elements = this._drag.elements;
+      draggableArguments.target = this._drag.target;
       return draggableArguments;
     }
   }]);
@@ -4157,55 +4351,58 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
   return Timeline;
 }(TimelineEventsEmitter);
 // EXTERNAL MODULE: ./src/timelineModel.ts
-var timelineModel = __webpack_require__(1);
+var timelineModel = __webpack_require__(2);
 
 // EXTERNAL MODULE: ./src/timelineRow.ts
-var timelineRow = __webpack_require__(2);
+var timelineRow = __webpack_require__(3);
 
 // EXTERNAL MODULE: ./src/timelineKeyframe.ts
-var timelineKeyframe = __webpack_require__(3);
+var timelineKeyframe = __webpack_require__(4);
 
 // EXTERNAL MODULE: ./src/settings/timelineConsts.ts
-var timelineConsts = __webpack_require__(4);
+var timelineConsts = __webpack_require__(5);
 
 // EXTERNAL MODULE: ./src/timelineRanged.ts
-var timelineRanged = __webpack_require__(5);
+var timelineRanged = __webpack_require__(6);
 
 // EXTERNAL MODULE: ./src/settings/timelineOptions.ts
-var timelineOptions = __webpack_require__(6);
+var timelineOptions = __webpack_require__(7);
 
 // EXTERNAL MODULE: ./src/settings/styles/timelineKeyframeStyle.ts
-var timelineKeyframeStyle = __webpack_require__(7);
+var timelineKeyframeStyle = __webpack_require__(8);
 
 // EXTERNAL MODULE: ./src/settings/styles/timelineRowStyle.ts
-var timelineRowStyle = __webpack_require__(8);
+var timelineRowStyle = __webpack_require__(9);
 
 // EXTERNAL MODULE: ./src/settings/styles/timelineStyle.ts
-var styles_timelineStyle = __webpack_require__(9);
+var styles_timelineStyle = __webpack_require__(10);
 
 // EXTERNAL MODULE: ./src/utils/timelineElement.ts
-var timelineElement = __webpack_require__(10);
+var timelineElement = __webpack_require__(11);
 
 // EXTERNAL MODULE: ./src/utils/selectable.ts
-var selectable = __webpack_require__(11);
+var selectable = __webpack_require__(12);
 
 // EXTERNAL MODULE: ./src/utils/timelineCutBoundsRectResults.ts
-var timelineCutBoundsRectResults = __webpack_require__(12);
+var timelineCutBoundsRectResults = __webpack_require__(13);
 
 // EXTERNAL MODULE: ./src/utils/timelineSelectionResults.ts
-var timelineSelectionResults = __webpack_require__(13);
+var timelineSelectionResults = __webpack_require__(14);
 
 // EXTERNAL MODULE: ./src/utils/timelineValues.ts
-var timelineValues = __webpack_require__(14);
+var timelineValues = __webpack_require__(15);
 
 // EXTERNAL MODULE: ./src/utils/timelineMouseData.ts
-var timelineMouseData = __webpack_require__(15);
+var timelineMouseData = __webpack_require__(16);
+
+// EXTERNAL MODULE: ./src/utils/timelineDraggableData.ts
+var timelineDraggableData = __webpack_require__(1);
 
 // EXTERNAL MODULE: ./src/utils/timelineModelCalcResults.ts
 var timelineModelCalcResults = __webpack_require__(0);
 
 // EXTERNAL MODULE: ./src/utils/events/timelineScrollEvent.ts
-var timelineScrollEvent = __webpack_require__(16);
+var timelineScrollEvent = __webpack_require__(17);
 
 // CONCATENATED MODULE: ./src/animation-timeline.ts
 // bundle entry point
@@ -4215,11 +4412,15 @@ var timelineScrollEvent = __webpack_require__(16);
 
 
 
- // styles
+ // @public styles
+
+
+
 
 
 
 
+ // @private helper containers.
 
 
 
@@ -4227,21 +4428,21 @@ var timelineScrollEvent = __webpack_require__(16);
 
 
 
+ // @private virtual model
 
- // virtual model
 
 
 
 
+ // @public events
 
- // events
 
 
 
 
 
 
- // enums
+ // @public enums
 
 
 
@@ -4249,7 +4450,7 @@ var timelineScrollEvent = __webpack_require__(16);
 
 
 
- // private defaults are exposed:
+ // @private defaults are exposed:
 
 
 

+ 1 - 1
lib/animation-timeline.js.map

@@ -1 +1 @@
-{"version":3,"file":"animation-timeline.js","sourceRoot":"","sources":["../src/animation-timeline.ts"],"names":[],"mappings":";AAAA,qBAAqB;;AAErB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AAIjB,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA;AAS9B,iEAAgE;AAAvD,wHAAA,kBAAkB,OAAA;AAC3B,uDAAsD;AAA7C,8GAAA,aAAa,OAAA;AAetB,SAAS;AACT,8EAA6E;AAApE,8HAAA,qBAAqB,OAAA;AAE9B,wEAAuE;AAA9D,wHAAA,kBAAkB,OAAA;AAC3B,sEAAqE;AAA5D,sHAAA,iBAAiB,OAAA;AAC1B,oFAAmF;AAA1E,oIAAA,wBAAwB,OAAA;AACjC,yDAAwD;AAA/C,gHAAA,cAAc,OAAA;AAEvB,QAAQ;AACR,uEAAsE;AAA7D,8HAAA,qBAAqB,OAAA;AAC9B,2EAA0E;AAAjE,kIAAA,uBAAuB,OAAA;AAChC,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAC5B,iEAAgE;AAAvD,wHAAA,kBAAkB,OAAA;AAC3B,6DAA4D;AAAnD,oHAAA,gBAAgB,OAAA;AACzB,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAC5B,uEAAsE;AAA7D,8HAAA,qBAAqB,OAAA;AAE9B,gCAAgC;AAChC,gDAA6D;AAApD,kHAAA,sBAAsB,OAAA;AAC/B,gDAAmE;AAA1D,wHAAA,4BAA4B,OAAA;AACrC,gDAA8D;AAArD,mHAAA,uBAAuB,OAAA;AAChC,gDAA2D;AAAlD,gHAAA,oBAAoB,OAAA;AAC7B,gDAA4D;AAAnD,iHAAA,qBAAqB,OAAA"}
+{"version":3,"file":"animation-timeline.js","sourceRoot":"","sources":["../src/animation-timeline.ts"],"names":[],"mappings":";AAAA,qBAAqB;;AAErB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AAIjB,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA;AAU9B,iEAAgE;AAAvD,wHAAA,kBAAkB,OAAA;AAC3B,uDAAsD;AAA7C,8GAAA,aAAa,OAAA;AAmBtB,iBAAiB;AACjB,4FAA2F;AAAlF,4IAAA,4BAA4B,OAAA;AACrC,oFAAmF;AAA1E,oIAAA,wBAAwB,OAAA;AACjC,8EAA6E;AAApE,8HAAA,qBAAqB,OAAA;AAE9B,wEAAuE;AAA9D,wHAAA,kBAAkB,OAAA;AAC3B,sEAAqE;AAA5D,sHAAA,iBAAiB,OAAA;AAC1B,yDAAwD;AAA/C,gHAAA,cAAc,OAAA;AAEvB,gBAAgB;AAChB,uEAAsE;AAA7D,8HAAA,qBAAqB,OAAA;AAC9B,2EAA0E;AAAjE,kIAAA,uBAAuB,OAAA;AAChC,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAC5B,iEAAgE;AAAvD,wHAAA,kBAAkB,OAAA;AAC3B,6DAA4D;AAAnD,oHAAA,gBAAgB,OAAA;AACzB,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAC5B,uEAAsE;AAA7D,8HAAA,qBAAqB,OAAA;AAE9B,iCAAiC;AACjC,gDAA6D;AAApD,kHAAA,sBAAsB,OAAA;AAC/B,gDAAmE;AAA1D,wHAAA,4BAA4B,OAAA;AACrC,gDAA8D;AAArD,mHAAA,uBAAuB,OAAA;AAChC,gDAA2D;AAAlD,gHAAA,oBAAoB,OAAA;AAC7B,gDAA4D;AAAnD,iHAAA,qBAAqB,OAAA"}

文件差异内容过多而无法显示
+ 0 - 0
lib/animation-timeline.min.js


+ 1 - 1
lib/enums/timelineEvents.d.ts

@@ -1,7 +1,7 @@
 export declare enum TimelineEvents {
     Selected = "selected",
     TimeChanged = "timechanged",
-    KeyframeTimeChanged = "keyframeTimeChanged",
+    KeyframeChanged = "keyframeChanged",
     DragStarted = "dragStarted",
     Drag = "drag",
     DragFinished = "dragFinished",

+ 1 - 1
lib/enums/timelineEvents.js.map

@@ -1 +1 @@
-{"version":3,"file":"timelineEvents.js","sourceRoot":"","sources":["../../src/enums/timelineEvents.ts"],"names":[],"mappings":";;;AAAA,IAAY,cAUX;AAVD,WAAY,cAAc;IACxB,uCAAqB,CAAA;IACrB,6CAA2B,CAAA;IAC3B,6DAA2C,CAAA;IAC3C,6CAA2B,CAAA;IAC3B,+BAAa,CAAA;IACb,+CAA6B,CAAA;IAC7B,mCAAiB,CAAA;IACjB,6CAA2B,CAAA;IAC3B,yCAAuB,CAAA;AACzB,CAAC,EAVW,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAUzB"}
+{"version":3,"file":"timelineEvents.js","sourceRoot":"","sources":["../../src/enums/timelineEvents.ts"],"names":[],"mappings":";;;AAAA,IAAY,cAUX;AAVD,WAAY,cAAc;IACxB,uCAAqB,CAAA;IACrB,6CAA2B,CAAA;IAC3B,qDAAmC,CAAA;IACnC,6CAA2B,CAAA;IAC3B,+BAAa,CAAA;IACb,+CAA6B,CAAA;IAC7B,mCAAiB,CAAA;IACjB,6CAA2B,CAAA;IAC3B,yCAAuB,CAAA;AACzB,CAAC,EAVW,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAUzB"}

+ 12 - 3
lib/timeline.d.ts

@@ -10,7 +10,7 @@ import { TimelineCalculatedRow, TimelineModelCalcResults, TimelineCalculatedKeyf
 import { TimelineInteractionMode } from './enums/timelineInteractionMode';
 import { TimelineScrollEvent } from './utils/events/timelineScrollEvent';
 import { TimelineSelectedEvent } from './utils/events/timelineSelectedEvent';
-import { TimelineDraggableData } from './utils/timelineDraggableData';
+import { TimelineDraggableData, TimelineElementDragState } from './utils/timelineDraggableData';
 import { TimelineClickEvent } from './utils/events/timelineClickEvent';
 import { TimelineDragEvent } from './utils/events/timelineDragEvent';
 import { TimelineEventSource } from './enums/timelineEventSource';
@@ -18,6 +18,7 @@ import { TimelineTimeChangedEvent } from './utils/events/timelineTimeChangedEven
 import { TimelineSelectionMode } from './enums/timelineSelectionMode';
 import { TimelineSelectionResults } from './utils/timelineSelectionResults';
 import { TimelineMouseData } from './utils/timelineMouseData';
+import { TimelineKeyframeChangedEvent } from './utils/events/timelineKeyframeChangedEvent';
 export declare class Timeline extends TimelineEventsEmitter {
     /**
      * component container.
@@ -140,6 +141,7 @@ export declare class Timeline extends TimelineEventsEmitter {
      * @param args
      */
     _handleMouseDownEvent: (args: MouseEvent) => void;
+    _setElementDragState(element: TimelineElement | TimelineElementDragState, val: number): TimelineElementDragState;
     isLeftButtonClicked(args: MouseEvent | TouchEvent | any): boolean;
     _handleMouseMoveEvent: (args: MouseEvent | TouchEvent | any) => void;
     /**
@@ -148,7 +150,7 @@ export declare class Timeline extends TimelineEventsEmitter {
      * @param elements Element to move.
      * @returns real moved value.
      */
-    _moveElements(offset: number, elements: Array<TimelineElement>): number;
+    _moveElements(offset: number, elements: Array<TimelineElementDragState>, source?: TimelineEventSource): number;
     _handleMouseUpEvent: (args: MouseEvent) => void;
     /**
      * client height.
@@ -172,8 +174,9 @@ export declare class Timeline extends TimelineEventsEmitter {
      * Set keyframe value.
      * @param keyframe
      * @param value
+     * @return set value.
      */
-    _setKeyframePos(keyframe: TimelineKeyframe, value: number): boolean;
+    _setKeyframePos(element: TimelineElementDragState, value: number, source?: TimelineEventSource): number;
     /**
      * @param cursor to set.
      */
@@ -371,6 +374,10 @@ export declare class Timeline extends TimelineEventsEmitter {
      * Subscribe on double click.
      */
     onDoubleClick(callback: (eventArgs: TimelineClickEvent) => void): void;
+    /**
+     * Subscribe on keyframe changed event.
+     */
+    onKeyframeChanged(callback: (eventArgs: TimelineKeyframeChangedEvent) => void): void;
     /**
      * Subscribe on drag finished event.
      */
@@ -381,8 +388,10 @@ export declare class Timeline extends TimelineEventsEmitter {
      */
     onScroll(callback: (eventArgs: TimelineScrollEvent) => void): void;
     _emitScrollEvent(args: MouseEvent | null): TimelineScrollEvent;
+    _emitKeyframeChanged(element: TimelineElementDragState, source?: TimelineEventSource): TimelineKeyframeChangedEvent;
     _emitDragStartedEvent(): TimelineDragEvent;
     _emitDragFinishedEvent(): TimelineDragEvent;
+    _preventDrag(dragArgs: TimelineDragEvent, data: TimelineDraggableData, toStart?: boolean): void;
     _emitDragEvent(): TimelineDragEvent;
     _emitKeyframesSelected(state: TimelineSelectionResults): TimelineSelectedEvent;
     _getDragEventArgs(): TimelineDragEvent;

文件差异内容过多而无法显示
+ 0 - 0
lib/timeline.js.map


+ 8 - 0
lib/timelineRanged.d.ts

@@ -7,4 +7,12 @@ export interface TimelineRanged {
      * max.
      */
     max?: number | null;
+    /**
+     * Allow to calculate min.
+     */
+    getMin?: () => number;
+    /**
+     * Allow to calculate max.
+     */
+    getMax?: () => number;
 }

+ 33 - 2
lib/utils/events/timelineDragEvent.d.ts

@@ -1,3 +1,34 @@
-import { TimelineClickEvent } from './timelineClickEvent';
-export declare class TimelineDragEvent extends TimelineClickEvent {
+import { TimelineValues } from '../timelineValues';
+import { TimelineBaseEvent } from './timelineBaseEvent';
+import { TimelineElementDragState } from '../timelineDraggableData';
+export declare class TimelineDragEvent extends TimelineBaseEvent implements TimelineValues {
+    args: MouseEvent;
+    /**
+     * Clicked screen position.
+     */
+    pos: DOMPoint;
+    /**
+     * Elements to be dragged as a group.
+     */
+    elements: Array<TimelineElementDragState>;
+    /**
+     * Target element
+     */
+    target: TimelineElementDragState;
+    /**
+     * Value to be used.
+     */
+    val: number;
+    /**
+     * prev value.
+     */
+    prevVal: number;
+    /**
+     * Snapped value.
+     */
+    snapVal: number;
+    /**
+     * Unsnapped original value.
+     */
+    originalVal: number;
 }

+ 1 - 1
lib/utils/events/timelineDragEvent.js.map

@@ -1 +1 @@
-{"version":3,"file":"timelineDragEvent.js","sourceRoot":"","sources":["../../../src/utils/events/timelineDragEvent.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2DAA0D;AAE1D;IAAuC,qCAAkB;IAAzD;;IAEA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAFD,CAAuC,uCAAkB,GAExD;AAFY,8CAAiB"}
+{"version":3,"file":"timelineDragEvent.js","sourceRoot":"","sources":["../../../src/utils/events/timelineDragEvent.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,yDAAwD;AAGxD;IAAuC,qCAAiB;IAAxD;;IAiCA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAjCD,CAAuC,qCAAiB,GAiCvD;AAjCY,8CAAiB"}

+ 21 - 0
lib/utils/events/timelineKeyframeChangedEvent.d.ts

@@ -0,0 +1,21 @@
+import { TimelineBaseEvent } from './timelineBaseEvent';
+import { TimelineElement } from '../timelineElement';
+import { TimelineEventSource } from '../../animation-timeline';
+export declare class TimelineKeyframeChangedEvent extends TimelineBaseEvent {
+    /**
+     * Value to be used.
+     */
+    val: number;
+    /**
+     * Previous value.
+     */
+    prevVal: number;
+    /**
+     * Target element
+     */
+    target: TimelineElement;
+    /**
+     * Event source.
+     */
+    source: TimelineEventSource;
+}

+ 26 - 0
lib/utils/events/timelineKeyframeChangedEvent.js

@@ -0,0 +1,26 @@
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.TimelineKeyframeChangedEvent = void 0;
+var timelineBaseEvent_1 = require("./timelineBaseEvent");
+var TimelineKeyframeChangedEvent = /** @class */ (function (_super) {
+    __extends(TimelineKeyframeChangedEvent, _super);
+    function TimelineKeyframeChangedEvent() {
+        return _super !== null && _super.apply(this, arguments) || this;
+    }
+    return TimelineKeyframeChangedEvent;
+}(timelineBaseEvent_1.TimelineBaseEvent));
+exports.TimelineKeyframeChangedEvent = TimelineKeyframeChangedEvent;
+//# sourceMappingURL=timelineKeyframeChangedEvent.js.map

+ 1 - 0
lib/utils/events/timelineKeyframeChangedEvent.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"timelineKeyframeChangedEvent.js","sourceRoot":"","sources":["../../../src/utils/events/timelineKeyframeChangedEvent.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAwD;AAIxD;IAAkD,gDAAiB;IAAnE;;IAiBA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAjBD,CAAkD,qCAAiB,GAiBlE;AAjBY,oEAA4B"}

+ 17 - 0
lib/utils/events/timelineKeyframeTimeChangedEvent.d.ts

@@ -0,0 +1,17 @@
+import { TimelineBaseEvent } from './timelineBaseEvent';
+import { TimelineElement } from '../timelineElement';
+import { TimelineEventSource } from '../../animation-timeline';
+export declare class TimelineKeyframeChangedEvent extends TimelineBaseEvent {
+    /**
+     * Value to be used.
+     */
+    val: number;
+    /**
+     * Target element
+     */
+    target: TimelineElement;
+    /**
+     * Event source.
+     */
+    source: TimelineEventSource;
+}

+ 26 - 0
lib/utils/events/timelineKeyframeTimeChangedEvent.js

@@ -0,0 +1,26 @@
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.TimelineKeyframeChangedEvent = void 0;
+var timelineBaseEvent_1 = require("./timelineBaseEvent");
+var TimelineKeyframeChangedEvent = /** @class */ (function (_super) {
+    __extends(TimelineKeyframeChangedEvent, _super);
+    function TimelineKeyframeChangedEvent() {
+        return _super !== null && _super.apply(this, arguments) || this;
+    }
+    return TimelineKeyframeChangedEvent;
+}(timelineBaseEvent_1.TimelineBaseEvent));
+exports.TimelineKeyframeChangedEvent = TimelineKeyframeChangedEvent;
+//# sourceMappingURL=timelineKeyframeChangedEvent.js.map

+ 1 - 0
lib/utils/events/timelineKeyframeTimeChangedEvent.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"timelineKeyframeChangedEvent.js","sourceRoot":"","sources":["../../../src/utils/events/timelineKeyframeChangedEvent.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAwD;AAIxD;IAAsD,oDAAiB;IAAvE;;IAaA,CAAC;IAAD,uCAAC;AAAD,CAAC,AAbD,CAAsD,qCAAiB,GAatE;AAbY,4EAAgC"}

+ 16 - 2
lib/utils/timelineDraggableData.d.ts

@@ -6,13 +6,27 @@ export interface TimelineDraggableData extends TimelineValues {
     /**
      * Drag initial click target.
      */
-    target: TimelineElement;
+    target: TimelineElementDragState;
     /**
      * Elements to be dragged.
      */
-    elements: Array<TimelineElement>;
+    elements: Array<TimelineElementDragState>;
     /**
      * Dragging type.
      */
     type: TimelineElementType;
+    /**
+     * Prev value.
+     */
+    prevVal: number;
+}
+export interface TimelineElementDragState extends TimelineElement {
+    /**
+     * Drag started value.
+     */
+    startedVal: number;
+    /**
+     * Value before change.
+     */
+    prevVal: number;
 }

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "animation-timeline-js",
-  "version": "2.1.2",
+  "version": "2.1.3",
   "description": "animation timeline control based on the canvas.",
   "main": "lib/animation-timeline.min.js",
   "types": "lib/animation-timeline.d.ts",

+ 12 - 6
src/animation-timeline.ts

@@ -7,7 +7,8 @@ export { TimelineKeyframe } from './timelineKeyframe';
 export { TimelineEventsEmitter } from './timelineEventsEmitter';
 export { TimelineConsts } from './settings/timelineConsts';
 export { TimelineRanged } from './timelineRanged';
-// styles
+
+// @public styles
 export { TimelineOptions } from './settings/timelineOptions';
 export { TimelineKeyframeStyle } from './settings/styles/timelineKeyframeStyle';
 export { TimelineRowStyle } from './settings/styles/timelineRowStyle';
@@ -16,28 +17,33 @@ export { TimelineStyle } from './settings/styles/timelineStyle';
 export { TimelineStyleUtils } from './utils/timelineStyleUtils';
 export { TimelineUtils } from './utils/timelineUtils';
 export { TimelineElement } from './utils/timelineElement';
+
+// @private helper containers.
 export { Selectable } from './utils/selectable';
 export { TimelineCutBoundsRectResults } from './utils/timelineCutBoundsRectResults';
 export { TimelineSelectionResults } from './utils/timelineSelectionResults';
 export { TimelineValues } from './utils/timelineValues';
 export { TimelineMouseData } from './utils/timelineMouseData';
+export { TimelineElementDragState } from './utils/timelineDraggableData';
+export { TimelineDraggableData } from './utils/timelineDraggableData';
 
-// virtual model
+// @private virtual model
 export { TimelineModelCalcResults } from './utils/timelineModelCalcResults';
 export { TimelineCalculatedRow } from './utils/timelineModelCalcResults';
 export { TimelineCalculatedGroup } from './utils/timelineModelCalcResults';
 export { TimelineCalculated } from './utils/timelineModelCalcResults';
 export { TimelineCalculatedKeyframe } from './utils/timelineModelCalcResults';
 
-// events
+// @public events
+export { TimelineKeyframeChangedEvent } from './utils/events/timelineKeyframeChangedEvent';
+export { TimelineTimeChangedEvent } from './utils/events/timelineTimeChangedEvent';
 export { TimelineSelectedEvent } from './utils/events/timelineSelectedEvent';
 export { TimelineScrollEvent } from './utils/events/timelineScrollEvent';
 export { TimelineClickEvent } from './utils/events/timelineClickEvent';
 export { TimelineDragEvent } from './utils/events/timelineDragEvent';
-export { TimelineTimeChangedEvent } from './utils/events/timelineTimeChangedEvent';
 export { TimelineEvents } from './enums/timelineEvents';
 
-// enums
+// @public enums
 export { TimelineKeyframeShape } from './enums/timelineKeyframeShape';
 export { TimelineInteractionMode } from './enums/timelineInteractionMode';
 export { TimelineElementType } from './enums/timelineElementType';
@@ -46,7 +52,7 @@ export { TimelineCapShape } from './enums/timelineCapShape';
 export { TimelineEventSource } from './enums/timelineEventSource';
 export { TimelineSelectionMode } from './enums/timelineSelectionMode';
 
-// private defaults are exposed:
+// @private defaults are exposed:
 export { defaultTimelineOptions } from './settings/defaults';
 export { defaultTimelineKeyframeStyle } from './settings/defaults';
 export { defaultTimelineRowStyle } from './settings/defaults';

+ 1 - 1
src/enums/timelineEvents.ts

@@ -1,7 +1,7 @@
 export enum TimelineEvents {
   Selected = 'selected',
   TimeChanged = 'timechanged',
-  KeyframeTimeChanged = 'keyframeTimeChanged',
+  KeyframeChanged = 'keyframeChanged',
   DragStarted = 'dragStarted',
   Drag = 'drag',
   DragFinished = 'dragFinished',

+ 100 - 38
src/timeline.ts

@@ -18,7 +18,7 @@ import { TimelineCalculatedRow, TimelineModelCalcResults, TimelineCalculatedGrou
 import { TimelineInteractionMode } from './enums/timelineInteractionMode';
 import { TimelineScrollEvent } from './utils/events/timelineScrollEvent';
 import { TimelineSelectedEvent } from './utils/events/timelineSelectedEvent';
-import { TimelineDraggableData } from './utils/timelineDraggableData';
+import { TimelineDraggableData, TimelineElementDragState } from './utils/timelineDraggableData';
 import { TimelineClickEvent } from './utils/events/timelineClickEvent';
 import { TimelineDragEvent } from './utils/events/timelineDragEvent';
 import { defaultTimelineConsts, defaultTimelineOptions } from './settings/defaults';
@@ -28,6 +28,7 @@ import { TimelineSelectionMode } from './enums/timelineSelectionMode';
 import { TimelineSelectionResults } from './utils/timelineSelectionResults';
 import { TimelineRanged } from './timelineRanged';
 import { TimelineMouseData } from './utils/timelineMouseData';
+import { TimelineKeyframeChangedEvent } from './utils/events/timelineKeyframeChangedEvent';
 
 export class Timeline extends TimelineEventsEmitter {
   /**
@@ -442,7 +443,7 @@ export class Timeline extends TimelineEventsEmitter {
     if (target && this._interactionMode !== TimelineInteractionMode.Zoom) {
       this._drag = {
         changed: false,
-        target: target,
+        target: this._setElementDragState(target, target.val),
         val: target.val,
         type: target.type,
         elements: [],
@@ -456,15 +457,17 @@ export class Timeline extends TimelineEventsEmitter {
           this._selectInternal(target.keyframe);
         }
         // Allow to drag all selected keyframes on a screen
-        this._drag.elements = this.getSelectedElements();
+        this._drag.elements = this.getSelectedElements().map((element) => {
+          return this._setElementDragState(element, element.val);
+        });
       } else if (target.type === TimelineElementType.Group) {
         const keyframes = this._drag.target.keyframes;
-        this._drag.elements =
-          keyframes && Array.isArray(keyframes)
-            ? keyframes.map((keyframe) => {
-                return this._convertToElement(this._drag.target.row, keyframe) as TimelineElement;
-              })
-            : [];
+
+        if (keyframes && Array.isArray(keyframes)) {
+          this._drag.elements = keyframes.map((keyframe) => {
+            return this._setElementDragState(this._convertToElement(this._drag.target.row, keyframe), keyframe.val);
+          });
+        }
       } else {
         this._drag.elements = [this._drag.target];
       }
@@ -472,7 +475,18 @@ export class Timeline extends TimelineEventsEmitter {
 
     this.redraw();
   };
-
+  _setElementDragState(element: TimelineElement | TimelineElementDragState, val: number): TimelineElementDragState {
+    const state = element as TimelineElementDragState;
+    state.prevVal = state.val;
+    if (state.startedVal === undefined || state.startedVal === null) {
+      state.startedVal = val;
+    }
+    if (state.prevVal === undefined || state.prevVal === null) {
+      state.prevVal = val;
+    }
+    state.val = val;
+    return state;
+  }
   isLeftButtonClicked(args: MouseEvent | TouchEvent | any): boolean {
     return !!args && args.buttons == 1;
   }
@@ -505,17 +519,20 @@ export class Timeline extends TimelineEventsEmitter {
             this._setTimeInternal(convertedVal, TimelineEventSource.User);
           } else if ((this._drag.type == TimelineElementType.Keyframe || this._drag.type == TimelineElementType.Group) && this._drag.elements) {
             const offset = Math.floor(convertedVal - this._drag.val);
-            const movedOffset = this._moveElements(offset, this._drag.elements);
+            const movedOffset = this._moveElements(offset, this._drag.elements, TimelineEventSource.User);
             if (movedOffset !== 0) {
               if (!this._drag.changed) {
+                this._drag.prevVal = this._drag.val;
                 const eventArgs = this._emitDragStartedEvent();
                 if (eventArgs.isPrevented()) {
+                  // Cleanup drag here, so drag finished will be ignored.
+                  this._drag = null;
+                  this._cleanUpSelection();
                   return;
                 }
               }
 
               this._drag.changed = true;
-
               this._drag.val += offset;
               this._emitDragEvent();
             }
@@ -583,7 +600,7 @@ export class Timeline extends TimelineEventsEmitter {
    * @param elements Element to move.
    * @returns real moved value.
    */
-  _moveElements(offset: number, elements: Array<TimelineElement>): number {
+  _moveElements(offset: number, elements: Array<TimelineElementDragState>, source: TimelineEventSource = TimelineEventSource.Programmatically): number {
     if (!elements) {
       return;
     }
@@ -611,11 +628,10 @@ export class Timeline extends TimelineEventsEmitter {
       if (Math.abs(offset) > 0) {
         // don't allow to move less than zero.
         elements.forEach((element) => {
-          const toSet = element.keyframe.val + offset;
-          isChanged = this._setKeyframePos(element.keyframe, toSet) || isChanged;
-          if (isChanged) {
-            element.val = element.keyframe.val;
-          }
+          const prevVal = element.keyframe.val;
+          const toSet = prevVal + offset;
+          const newValue = this._setKeyframePos(element, toSet, source);
+          isChanged = newValue !== prevVal;
         });
       }
 
@@ -735,16 +751,27 @@ export class Timeline extends TimelineEventsEmitter {
    * Set keyframe value.
    * @param keyframe
    * @param value
+   * @return set value.
    */
-  _setKeyframePos(keyframe: TimelineKeyframe, value: number): boolean {
+  _setKeyframePos(element: TimelineElementDragState, value: number, source: TimelineEventSource = TimelineEventSource.Programmatically): number {
+    if (!element || !element.keyframe) {
+      return value;
+    }
     value = Math.floor(value);
-    if (keyframe && keyframe.val != value) {
-      keyframe.val = value;
+    if (element.keyframe && element.keyframe.val != value) {
+      element.prevVal = element.val;
+      element.val = value;
+      element.keyframe.val = value;
+      const event = this._emitKeyframeChanged(element, source);
+      if (event.isPrevented()) {
+        element.val = event.prevVal;
+        element.keyframe.val = event.prevVal;
+      }
 
-      return true;
+      return value;
     }
 
-    return false;
+    return value;
   }
 
   /**
@@ -2271,7 +2298,12 @@ export class Timeline extends TimelineEventsEmitter {
   public onDoubleClick(callback: (eventArgs: TimelineClickEvent) => void): void {
     this.on(TimelineEvents.DoubleClick, callback);
   }
-
+  /**
+   * Subscribe on keyframe changed event.
+   */
+  public onKeyframeChanged(callback: (eventArgs: TimelineKeyframeChangedEvent) => void): void {
+    this.on(TimelineEvents.KeyframeChanged, callback);
+  }
   /**
    * Subscribe on drag finished event.
    */
@@ -2299,27 +2331,55 @@ export class Timeline extends TimelineEventsEmitter {
     super.emit(TimelineEvents.Scroll, scrollEvent);
     return scrollEvent;
   }
+  _emitKeyframeChanged(element: TimelineElementDragState, source: TimelineEventSource = TimelineEventSource.Programmatically): TimelineKeyframeChangedEvent {
+    const args = new TimelineKeyframeChangedEvent();
+    args.val = element.val;
+    args.prevVal = element.prevVal;
+    args.target = element;
+    args.source = source;
+    this.emit(TimelineEvents.KeyframeChanged, args);
+    return args;
+  }
   _emitDragStartedEvent(): TimelineDragEvent {
     const args = this._getDragEventArgs();
     this.emit(TimelineEvents.DragStarted, args);
+    if (args.isPrevented()) {
+      this._preventDrag(args, this._drag, true);
+    }
     return args;
   }
   _emitDragFinishedEvent(): TimelineDragEvent {
     if (this._drag && this._drag.changed) {
       const args = this._getDragEventArgs();
       this.emit(TimelineEvents.DragFinished, args);
+      if (args.isPrevented()) {
+        this._preventDrag(args, this._drag, true);
+      }
       return args;
     }
+
+    return null;
+  }
+  _preventDrag(dragArgs: TimelineDragEvent, data: TimelineDraggableData, toStart = false): void {
+    if (dragArgs.elements) {
+      dragArgs.elements.forEach((element) => {
+        const toSet = toStart ? element.startedVal : element.prevVal;
+        this._setKeyframePos(element, toSet);
+      });
+    }
+    data.val = data.prevVal;
+    dragArgs.val = dragArgs.prevVal;
   }
   _emitDragEvent(): TimelineDragEvent {
-    if (this._drag) {
-      const args = this._getDragEventArgs();
-      this.emit(TimelineEvents.Drag, args);
-
-      return args;
+    if (!this._drag) {
+      return null;
     }
-
-    return null;
+    const args = this._getDragEventArgs();
+    this.emit(TimelineEvents.Drag, args);
+    if (args.isPrevented()) {
+      this._preventDrag(args, this._drag, false);
+    }
+    return args;
   }
   _emitKeyframesSelected(state: TimelineSelectionResults): TimelineSelectedEvent {
     const args = new TimelineSelectedEvent();
@@ -2330,13 +2390,15 @@ export class Timeline extends TimelineEventsEmitter {
   }
   _getDragEventArgs(): TimelineDragEvent {
     const draggableArguments = new TimelineDragEvent();
-    if (this._drag) {
-      draggableArguments.val = this._currentPos.val;
-      draggableArguments.pos = this._currentPos;
-      draggableArguments.elements = this._drag.elements;
-      draggableArguments.target = this._drag.target;
-    }
-
+    if (!this._drag) {
+      return draggableArguments;
+    }
+    draggableArguments.val = this._currentPos.val;
+    draggableArguments.originalVal = this._currentPos.originalVal;
+    draggableArguments.snapVal = this._currentPos.snapVal;
+    draggableArguments.pos = this._currentPos;
+    draggableArguments.elements = this._drag.elements;
+    draggableArguments.target = this._drag.target;
     return draggableArguments;
   }
 }

+ 9 - 0
src/timelineRanged.ts

@@ -7,4 +7,13 @@ export interface TimelineRanged {
    * max.
    */
   max?: number | null;
+
+  /**
+   * Allow to calculate min.
+   */
+  getMin?: () => number;
+  /**
+   * Allow to calculate max.
+   */
+  getMax?: () => number;
 }

+ 36 - 2
src/utils/events/timelineDragEvent.ts

@@ -1,4 +1,38 @@
-import { TimelineClickEvent } from './timelineClickEvent';
+import { TimelineValues } from '../timelineValues';
+import { TimelineBaseEvent } from './timelineBaseEvent';
+import { TimelineElementDragState } from '../timelineDraggableData';
 
-export class TimelineDragEvent extends TimelineClickEvent {
+export class TimelineDragEvent extends TimelineBaseEvent implements TimelineValues {
+  args: MouseEvent;
+  /**
+   * Clicked screen position.
+   */
+  pos: DOMPoint;
+
+  /**
+   * Elements to be dragged as a group.
+   */
+  elements: Array<TimelineElementDragState>;
+  /**
+   * Target element
+   */
+  target: TimelineElementDragState;
+  /**
+   * Value to be used.
+   */
+  val: number;
+
+  /**
+   * prev value.
+   */
+  prevVal: number;
+
+  /**
+   * Snapped value.
+   */
+  snapVal: number;
+  /**
+   * Unsnapped original value.
+   */
+  originalVal: number;
 }

+ 22 - 0
src/utils/events/timelineKeyframeChangedEvent.ts

@@ -0,0 +1,22 @@
+import { TimelineBaseEvent } from './timelineBaseEvent';
+import { TimelineElement } from '../timelineElement';
+import { TimelineEventSource } from '../../animation-timeline';
+
+export class TimelineKeyframeChangedEvent extends TimelineBaseEvent {
+  /**
+   * Value to be used.
+   */
+  val: number;
+  /**
+   * Previous value.
+   */
+  prevVal: number;
+  /**
+   * Target element
+   */
+  target: TimelineElement;
+  /**
+   * Event source.
+   */
+  source: TimelineEventSource;
+}

+ 17 - 2
src/utils/timelineDraggableData.ts

@@ -7,13 +7,28 @@ export interface TimelineDraggableData extends TimelineValues {
   /**
    * Drag initial click target.
    */
-  target: TimelineElement;
+  target: TimelineElementDragState;
   /**
    * Elements to be dragged.
    */
-  elements: Array<TimelineElement>;
+  elements: Array<TimelineElementDragState>;
   /**
    * Dragging type.
    */
   type: TimelineElementType;
+  /**
+   * Prev value.
+   */
+  prevVal: number;
+}
+
+export interface TimelineElementDragState extends TimelineElement {
+  /**
+   * Drag started value.
+   */
+  startedVal: number;
+  /**
+   * Value before change.
+   */
+  prevVal: number;
 }

+ 13 - 8
src/utils/timelineUtils.ts

@@ -87,20 +87,25 @@ export class TimelineUtils {
     if (!from || !to) {
       return to;
     }
-    const isFromMinNumber = TimelineUtils.isNumber(from.min);
-    const isToMinNumber = TimelineUtils.isNumber(to.min);
+    const fromMin = Math.min(from.getMin ? from.getMin() : from.min, from.min);
+    const toMin = Math.min(to.getMin ? to.getMin() : to.min, to.min);
+    const isFromMinNumber = TimelineUtils.isNumber(fromMin);
+    const isToMinNumber = TimelineUtils.isNumber(toMin);
     // get absolute min and max bounds:
     if (isFromMinNumber && isToMinNumber) {
-      to.min = shrink ? Math.min(from.min, to.min) : Math.max(from.min, to.min);
+      to.min = shrink ? Math.min(fromMin, toMin) : Math.max(fromMin, toMin);
     } else if (isFromMinNumber) {
-      to.min = from.min;
+      to.min = fromMin;
     }
-    const isFromMaxNumber = TimelineUtils.isNumber(from.max);
-    const isToMaxNumber = TimelineUtils.isNumber(to.max);
+
+    const fromMax = Math.min(from.getMax && from.getMax ? from.getMax() : from.max, from.max);
+    const toMax = Math.min(to.getMax ? to.getMax() : to.max, to.max);
+    const isFromMaxNumber = TimelineUtils.isNumber(fromMax);
+    const isToMaxNumber = TimelineUtils.isNumber(toMax);
     if (isFromMaxNumber && isToMaxNumber) {
-      to.max = shrink ? Math.max(from.max, to.max) : Math.min(from.max, to.max);
+      to.max = shrink ? Math.max(fromMax, toMax) : Math.min(fromMax, toMax);
     } else if (isFromMaxNumber) {
-      to.max = from.max;
+      to.max = fromMax;
     }
 
     return to;

文件差异内容过多而无法显示
+ 0 - 0
tests/js/timelineTests.js


+ 19 - 18
tests/timelineTests.ts

@@ -9,6 +9,7 @@ import {
   TimelineElement,
   TimelineOptions,
   TimelineRowStyle,
+  TimelineElementDragState,
   TimelineKeyframeStyle,
 } from './../lib/animation-timeline';
 
@@ -562,11 +563,11 @@ describe('Timeline', function () {
         {
           keyframe: model.rows[0].keyframes[1],
           row: model.rows[0],
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: model.rows[0].keyframes[0],
           row: model.rows[0],
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ]);
 
       chai.expect(movedOffset).equal(move);
@@ -586,11 +587,11 @@ describe('Timeline', function () {
         {
           keyframe: model.rows[0].keyframes[1],
           row: model.rows[0],
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: model.rows[0].keyframes[0],
           row: model.rows[0],
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ]);
 
       chai.expect(movedOffset).equal(move);
@@ -606,10 +607,10 @@ describe('Timeline', function () {
       const elementsToMove = [
         {
           keyframe: { val: item1 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: item2 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
@@ -627,10 +628,10 @@ describe('Timeline', function () {
       const elementsToMove = [
         {
           keyframe: { val: item1 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: item2 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
@@ -647,10 +648,10 @@ describe('Timeline', function () {
       const elementsToMove = [
         {
           keyframe: { val: item1 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: item2 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
@@ -668,19 +669,19 @@ describe('Timeline', function () {
         {
           keyframe: { val: 100 },
           row: row,
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: 400 },
           row: row,
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: 200 },
           row: row2,
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: 300 },
           row: row2,
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
       const moved = move / 2;
@@ -699,10 +700,10 @@ describe('Timeline', function () {
       const elementsToMove = [
         {
           keyframe: { val: item1 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: item2 },
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
@@ -718,11 +719,11 @@ describe('Timeline', function () {
         {
           keyframe: { val: 25 },
           row: row,
-        } as TimelineElement,
+        } as TimelineElementDragState,
         {
           keyframe: { val: 50 },
           row: row,
-        } as TimelineElement,
+        } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 

部分文件因为文件数量过多而无法显示