|
@@ -317,10 +317,14 @@ var TimelineUtils = /*#__PURE__*/function () {
|
|
|
ctx.moveTo(x1, y1);
|
|
|
ctx.lineTo(x2, y2);
|
|
|
}
|
|
|
+ /**
|
|
|
+ * Check is valid number.
|
|
|
+ */
|
|
|
+
|
|
|
}, {
|
|
|
key: "isNumber",
|
|
|
value: function isNumber(val) {
|
|
|
- if (typeof val === 'number' && !isNaN(val)) {
|
|
|
+ if (typeof val === 'number' && !isNaN(val) && Number.isFinite(val)) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -362,6 +366,11 @@ var TimelineUtils = /*#__PURE__*/function () {
|
|
|
key: "findGoodStep",
|
|
|
value: function findGoodStep(originalStep) {
|
|
|
var divisionCheck = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
|
+
|
|
|
+ if (originalStep <= 0 || isNaN(originalStep) || !Number.isFinite(originalStep)) {
|
|
|
+ return originalStep;
|
|
|
+ }
|
|
|
+
|
|
|
var step = originalStep;
|
|
|
var lastDistance = null;
|
|
|
var pow = TimelineUtils.getPowArgument(originalStep);
|
|
@@ -388,6 +397,57 @@ var TimelineUtils = /*#__PURE__*/function () {
|
|
|
|
|
|
return step;
|
|
|
}
|
|
|
+ /**
|
|
|
+ * Keep value in min, max bounds.
|
|
|
+ */
|
|
|
+
|
|
|
+ }, {
|
|
|
+ key: "keepInBounds",
|
|
|
+ value: function keepInBounds(value) {
|
|
|
+ var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
|
+ var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
|
+
|
|
|
+ if (TimelineUtils.isNumber(value)) {
|
|
|
+ if (TimelineUtils.isNumber(min)) {
|
|
|
+ value = Math.max(value, min);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (TimelineUtils.isNumber(max)) {
|
|
|
+ value = Math.min(value, max);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ key: "setMinMax",
|
|
|
+ value: function setMinMax(to, from) {
|
|
|
+ var shrink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
|
+
|
|
|
+ if (!from || !to) {
|
|
|
+ return to;
|
|
|
+ }
|
|
|
+
|
|
|
+ var isFromMinNumber = TimelineUtils.isNumber(from.min);
|
|
|
+ var isToMinNumber = TimelineUtils.isNumber(to.min); // get absolute min and max bounds:
|
|
|
+
|
|
|
+ if (isFromMinNumber && isToMinNumber) {
|
|
|
+ to.min = shrink ? Math.min(from.min, to.min) : Math.max(from.min, to.min);
|
|
|
+ } else if (isFromMinNumber) {
|
|
|
+ to.min = from.min;
|
|
|
+ }
|
|
|
+
|
|
|
+ var isFromMaxNumber = TimelineUtils.isNumber(from.max);
|
|
|
+ var isToMaxNumber = TimelineUtils.isNumber(to.max);
|
|
|
+
|
|
|
+ if (isFromMaxNumber && isToMaxNumber) {
|
|
|
+ to.max = shrink ? Math.max(from.max, to.max) : Math.min(from.max, to.max);
|
|
|
+ } else if (isFromMaxNumber) {
|
|
|
+ to.max = from.max;
|
|
|
+ }
|
|
|
+
|
|
|
+ return to;
|
|
|
+ }
|
|
|
}, {
|
|
|
key: "isRectOverlap",
|
|
|
value: function isRectOverlap(rect, rect2) {
|
|
@@ -989,12 +1049,6 @@ var defaultTimelineRowStyle = {
|
|
|
keyframesStyle: defaultTimelineKeyframeStyle
|
|
|
};
|
|
|
var defaultTimelineOptions = {
|
|
|
- /**
|
|
|
- * Snap the mouse to the values on a timeline.
|
|
|
- * Value can be from 1 to 60
|
|
|
- */
|
|
|
- snapsPerSeconds: 5,
|
|
|
-
|
|
|
/**
|
|
|
* Snap all selected keyframes as a bundle during the drag.
|
|
|
*/
|
|
@@ -1010,8 +1064,17 @@ var defaultTimelineOptions = {
|
|
|
* approximate step for the timeline in pixels for 1 second
|
|
|
*/
|
|
|
stepPx: 120,
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Number of units that should fit into one stepPx. (1 second by a default)
|
|
|
+ */
|
|
|
+ stepVal: 1000,
|
|
|
stepSmallPx: 30,
|
|
|
- smallSteps: 50,
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Snap step in units. from 0 to stepVal
|
|
|
+ */
|
|
|
+ snapStep: 200,
|
|
|
|
|
|
/**
|
|
|
* additional left margin in pixels to start the line gauge from.
|
|
@@ -1042,13 +1105,26 @@ var defaultTimelineOptions = {
|
|
|
*/
|
|
|
headerHeight: 30,
|
|
|
font: '11px sans-serif',
|
|
|
- zoom: 1000,
|
|
|
- // Zoom speed. Use percent of the screen to set zoom speed.
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Default zoom level = 1. where screen pixels are equals to the corresponding stepVal stepPx.
|
|
|
+ */
|
|
|
+ zoom: 1,
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Default zoom speed.
|
|
|
+ */
|
|
|
zoomSpeed: 0.1,
|
|
|
- // Max zoom
|
|
|
- zoomMin: 80,
|
|
|
- // Min zoom
|
|
|
- zoomMax: 8000,
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Max zoom value.
|
|
|
+ */
|
|
|
+ zoomMin: 0.1,
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Min zoom value.
|
|
|
+ */
|
|
|
+ zoomMax: 8,
|
|
|
|
|
|
/**
|
|
|
* Set this to true in a MAC OS environment: The Meta key will be used instead of the Ctrl key.
|
|
@@ -1513,7 +1589,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
if (_this._startPos) {
|
|
|
if (isLeftClicked || isTouch) {
|
|
|
if (_this._drag && !_this._startedDragWithCtrl) {
|
|
|
- var convertedVal = _this._mousePosToVal(_this._currentPos.x, true);
|
|
|
+ var convertedVal = _this._currentPos.val;
|
|
|
|
|
|
if (_this._drag.type === TimelineElementType.Timeline) {
|
|
|
_this._setTimeInternal(convertedVal, TimelineEventSource.User);
|
|
@@ -1614,7 +1690,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
_this._zoom(direction, _this._options.zoomSpeed, mousePos);
|
|
|
} else {
|
|
|
- _this._performClick(pos, args, _this._drag);
|
|
|
+ _this._performClick(pos, _this._drag);
|
|
|
}
|
|
|
} else if (!_this._drag && _this._selectionRect && _this._selectionRectEnabled) {
|
|
|
if (_this._interactionMode === TimelineInteractionMode.Zoom) {
|
|
@@ -1641,7 +1717,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
} // Rescale when animation is played out of the bounds.
|
|
|
|
|
|
|
|
|
- if (_this.valToPx(_this._val, true) > _this._scrollContainer.scrollWidth) {
|
|
|
+ if (_this.valToPx(_this._val) > _this._scrollContainer.scrollWidth) {
|
|
|
_this.rescale();
|
|
|
|
|
|
if (!_this._isPanStarted && _this._drag && _this._drag.type !== TimelineElementType.Timeline) {
|
|
@@ -1687,10 +1763,23 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
throw new Error("Element cannot be empty. Should be string or DOM element.");
|
|
|
}
|
|
|
|
|
|
- var id = options.id;
|
|
|
- this._options = this._mergeOptions(options);
|
|
|
- this._currentZoom = this._options.zoom;
|
|
|
+ this._generateContainers(options.id);
|
|
|
+
|
|
|
+ this._options = this._setOptions(options);
|
|
|
|
|
|
+ this._subscribeOnEvents();
|
|
|
+
|
|
|
+ this.rescale();
|
|
|
+ this.redraw();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Generate component html.
|
|
|
+ * @param id container.
|
|
|
+ */
|
|
|
+
|
|
|
+ }, {
|
|
|
+ key: "_generateContainers",
|
|
|
+ value: function _generateContainers(id) {
|
|
|
if (id instanceof HTMLElement) {
|
|
|
this._container = id;
|
|
|
} else {
|
|
@@ -1713,9 +1802,6 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
this._container.style.position = 'relative'; // Generate size container:
|
|
|
|
|
|
this._canvas.style.cssText = 'image-rendering: -moz-crisp-edges;' + 'image-rendering: -webkit-crisp-edges;' + 'image-rendering: pixelated;' + 'image-rendering: crisp-edges;' + 'user-select: none;' + '-webkit-user-select: none;' + '-khtml-user-select: none;' + '-moz-user-select: none;' + '-o-user-select: none;' + 'user-select: none;' + 'touch-action: none;' + 'position: relative;' + '-webkit-user-drag: none;' + '-khtml-user-drag: none;' + '-moz-user-drag: none;' + '-o-user-drag: none;' + 'user-drag: none;' + 'padding: inherit';
|
|
|
-
|
|
|
- this._scrollContainer.classList.add(this._options.scrollContainerClass);
|
|
|
-
|
|
|
this._scrollContainer.style.cssText = 'overflow: scroll;' + 'position: absolute;' + 'width: 100%;' + 'height: 100%;';
|
|
|
this._scrollContent.style.width = this._scrollContent.style.height = '100%'; // add the text node to the created div
|
|
|
|
|
@@ -1723,24 +1809,13 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
this._container.appendChild(this._scrollContainer);
|
|
|
|
|
|
- var scrollBarWidth = this._scrollContainer.offsetWidth - this._scrollContent.clientWidth; // Calculate current browser scroll bar size and add offset for the canvas
|
|
|
+ var scrollBarWidth = this._scrollContainer.offsetWidth - this._scrollContent.clientWidth; // Calculate current browser scrollbar size and add offset for the canvas
|
|
|
|
|
|
this._canvas.style.width = this._canvas.style.height = 'calc(100% -' + (scrollBarWidth || 17) + 'px)';
|
|
|
|
|
|
this._container.appendChild(this._canvas);
|
|
|
|
|
|
- if (this._options.fillColor) {
|
|
|
- this._scrollContainer.style.background = this._options.fillColor;
|
|
|
- } // Normalize and validate span per seconds
|
|
|
-
|
|
|
-
|
|
|
- this._options.snapsPerSeconds = Math.max(0, Math.min(60, this._options.snapsPerSeconds || 0));
|
|
|
this._ctx = this._canvas.getContext('2d');
|
|
|
-
|
|
|
- this._subscribeOnEvents();
|
|
|
-
|
|
|
- this.rescale();
|
|
|
- this.redraw();
|
|
|
}
|
|
|
/**
|
|
|
* Subscribe current component on the related events.
|
|
@@ -1839,21 +1914,14 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
var deltaSpeed = TimelineUtils.getDistance(this._width() / 2, x) * 0.2;
|
|
|
x = x + deltaSpeed;
|
|
|
var diff = this._width() / x;
|
|
|
- var val = this.pxToVal(this._scrollContainer.scrollLeft + x, false);
|
|
|
- var zoom = direction * this._currentZoom * speed; //this._options.zoom
|
|
|
-
|
|
|
- this._currentZoom += zoom;
|
|
|
|
|
|
- if (TimelineUtils.isNumber(this._options.zoomMax) && this._currentZoom > this._options.zoomMax) {
|
|
|
- this._currentZoom = this._options.zoomMax;
|
|
|
- }
|
|
|
+ var val = this._fromScreen(x - this._leftMargin());
|
|
|
|
|
|
- if (TimelineUtils.isNumber(this._options.zoomMin) && this._currentZoom < this._options.zoomMin) {
|
|
|
- this._currentZoom = this._options.zoomMin;
|
|
|
- } // Get only after zoom is set
|
|
|
+ var zoom = direction * this._currentZoom * speed; //this._options.zoom
|
|
|
|
|
|
+ this._currentZoom = this._setZoom(this._currentZoom + zoom); // Get only after zoom is set
|
|
|
|
|
|
- var zoomCenter = this.valToPx(val, true);
|
|
|
+ var zoomCenter = this.valToPx(val);
|
|
|
var newScrollLeft = Math.round(zoomCenter - this._width() / diff);
|
|
|
|
|
|
if (newScrollLeft <= 0) {
|
|
@@ -1894,6 +1962,31 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
this._zoom(-1, speed, this._scrollContainer.clientWidth / 2);
|
|
|
}
|
|
|
+ /**
|
|
|
+ * Set direct zoom value.
|
|
|
+ * @param zoom zoom value to set.
|
|
|
+ * @param min min zoom.
|
|
|
+ * @param max max zoom.
|
|
|
+ * @return normalized value.
|
|
|
+ */
|
|
|
+
|
|
|
+ }, {
|
|
|
+ key: "_setZoom",
|
|
|
+ value: function _setZoom(zoom) {
|
|
|
+ var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
|
+ var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
|
+ min = TimelineUtils.isNumber(min) ? min : this._options.zoomMin;
|
|
|
+ max = TimelineUtils.isNumber(max) ? max : this._options.zoomMax;
|
|
|
+
|
|
|
+ if (TimelineUtils.isNumber(zoom)) {
|
|
|
+ zoom = TimelineUtils.keepInBounds(zoom, min, max);
|
|
|
+ zoom = zoom || 1;
|
|
|
+ this._currentZoom = zoom;
|
|
|
+ return zoom;
|
|
|
+ }
|
|
|
+
|
|
|
+ return zoom;
|
|
|
+ }
|
|
|
/**
|
|
|
* @param args
|
|
|
*/
|
|
@@ -1928,15 +2021,14 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
min: Number.MIN_SAFE_INTEGER,
|
|
|
max: Number.MAX_SAFE_INTEGER
|
|
|
};
|
|
|
- bounds = this._setMinMax(bounds, this._options);
|
|
|
+ bounds = TimelineUtils.setMinMax(bounds, this._options);
|
|
|
elements.forEach(function (p) {
|
|
|
// find allowed bounds for the draggable items.
|
|
|
// find for each row and keyframe separately.
|
|
|
- var currentBounds = _this2._setMinMax(_this2._setMinMax({
|
|
|
+ var currentBounds = TimelineUtils.setMinMax(TimelineUtils.setMinMax({
|
|
|
min: bounds.min,
|
|
|
max: bounds.max
|
|
|
}, p.keyframe), p.row);
|
|
|
-
|
|
|
var expectedKeyframeValue = _this2._options && _this2._options.snapAllKeyframesOnMove ? _this2.snapVal(p.keyframe.val) : p.keyframe.val;
|
|
|
var newPosition = expectedKeyframeValue + offset;
|
|
|
|
|
@@ -2035,14 +2127,14 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
}
|
|
|
}, {
|
|
|
key: "_performClick",
|
|
|
- value: function _performClick(pos, args, drag) {
|
|
|
+ value: function _performClick(pos, drag) {
|
|
|
var isChanged = false;
|
|
|
|
|
|
if (drag && drag.type === TimelineElementType.Keyframe) {
|
|
|
var mode = TimelineSelectionMode.Normal;
|
|
|
|
|
|
- if (this._startedDragWithCtrl && this._controlKeyPressed(args) || this._startedDragWithShiftKey && args.shiftKey) {
|
|
|
- if (this._controlKeyPressed(args)) {
|
|
|
+ if (this._startedDragWithCtrl && this._controlKeyPressed(pos.args) || this._startedDragWithShiftKey && pos.args.shiftKey) {
|
|
|
+ if (this._controlKeyPressed(pos.args)) {
|
|
|
mode = TimelineSelectionMode.Revert;
|
|
|
}
|
|
|
} // Reverse selected keyframe selection by a click:
|
|
@@ -2050,19 +2142,16 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
isChanged = this._selectInternal(this._drag.target.keyframe, mode).selectionChanged || isChanged;
|
|
|
|
|
|
- if (args.shiftKey) {
|
|
|
- // change timeline pos:
|
|
|
- var convertedVal = this._mousePosToVal(pos.x, true); // Set current timeline position if it's not a drag or selection rect small or fast click.
|
|
|
-
|
|
|
-
|
|
|
- isChanged = this._setTimeInternal(convertedVal, TimelineEventSource.User) || isChanged;
|
|
|
+ if (pos.args.shiftKey) {
|
|
|
+ // Set current timeline position if it's not a drag or selection rect small or fast click.
|
|
|
+ isChanged = this._setTimeInternal(pos.val, TimelineEventSource.User) || isChanged;
|
|
|
}
|
|
|
} else {
|
|
|
// deselect keyframes if any:
|
|
|
isChanged = this._selectInternal(null).selectionChanged || isChanged; // change timeline pos:
|
|
|
// Set current timeline position if it's not a drag or selection rect small or fast click.
|
|
|
|
|
|
- isChanged = this._setTimeInternal(this._mousePosToVal(pos.x, true), TimelineEventSource.User) || isChanged;
|
|
|
+ isChanged = this._setTimeInternal(pos.val, TimelineEventSource.User) || isChanged;
|
|
|
}
|
|
|
|
|
|
return isChanged;
|
|
@@ -2332,8 +2421,13 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
value: function _trackMousePos(canvas, mouseArgs) {
|
|
|
var pos = this._getMousePos(canvas, mouseArgs);
|
|
|
|
|
|
- pos.val = this.pxToVal(pos.x + this._scrollContainer.scrollLeft);
|
|
|
- pos.snapVal = this.snapVal(pos.val);
|
|
|
+ pos.originalVal = this._mousePosToVal(pos.x, false);
|
|
|
+ pos.snapVal = this._mousePosToVal(pos.x, true);
|
|
|
+ pos.val = pos.originalVal;
|
|
|
+
|
|
|
+ if (this._options && this._options.snapEnabled) {
|
|
|
+ pos.val = pos.snapVal;
|
|
|
+ }
|
|
|
|
|
|
if (this._startPos) {
|
|
|
if (!this._selectionRect) {
|
|
@@ -2341,8 +2435,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
} // get the pos with the virtualization:
|
|
|
|
|
|
|
|
|
- var x = Math.floor(this._startPos.x + (this._scrollStartPos.x - this._scrollContainer.scrollLeft));
|
|
|
- var y = Math.floor(this._startPos.y + (this._scrollStartPos.y - this._scrollContainer.scrollTop));
|
|
|
+ var x = Math.floor(this._startPos.x + (this._scrollStartPos.x - this.getScrollLeft()));
|
|
|
+ var y = Math.floor(this._startPos.y + (this._scrollStartPos.y - this.getScrollTop()));
|
|
|
this._selectionRect.x = Math.min(x, pos.x);
|
|
|
this._selectionRect.y = Math.min(y, pos.y);
|
|
|
this._selectionRect.width = Math.max(x, pos.x) - this._selectionRect.x;
|
|
@@ -2488,7 +2582,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
} else if (isRight) {
|
|
|
// Get normalized speed:
|
|
|
speedX = TimelineUtils.getDistance(x, this._width() - bounds) * scrollSpeedMultiplier;
|
|
|
- newWidth = this._scrollContainer.scrollLeft + this._width() + speedX;
|
|
|
+ newWidth = this.getScrollLeft() + this._width() + speedX;
|
|
|
}
|
|
|
|
|
|
if (isTop) {
|
|
@@ -2525,63 +2619,75 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
}, {
|
|
|
key: "pxToVal",
|
|
|
- value: function pxToVal(coords) {
|
|
|
- var absolute = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
+ value: function pxToVal(px) {
|
|
|
+ var steps = this._options.stepVal * this._currentZoom || 1;
|
|
|
+ var val = px / this._options.stepPx * steps;
|
|
|
+ return val;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Convert value to local screen component coordinates.
|
|
|
+ */
|
|
|
|
|
|
- if (!absolute) {
|
|
|
- coords -= this._options.leftMargin;
|
|
|
- }
|
|
|
+ }, {
|
|
|
+ key: "_toScreenPx",
|
|
|
+ value: function _toScreenPx(val) {
|
|
|
+ return this.valToPx(val) - this.getScrollLeft() + this._leftMargin();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Convert screen local coordinates to a global value info.
|
|
|
+ */
|
|
|
|
|
|
- var ms = coords / this._options.stepPx * this._currentZoom;
|
|
|
- return ms;
|
|
|
+ }, {
|
|
|
+ key: "_fromScreen",
|
|
|
+ value: function _fromScreen(px) {
|
|
|
+ return this.pxToVal(this.getScrollLeft() + px);
|
|
|
}
|
|
|
/**
|
|
|
- * Convert area value to screen pixel coordinates.
|
|
|
+ * Convert area value to global screen pixel coordinates.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "valToPx",
|
|
|
- value: function valToPx(ms) {
|
|
|
- var absolute = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
-
|
|
|
- // Respect current scroll container offset. (virtualization)
|
|
|
- if (!absolute && this._scrollContainer) {
|
|
|
- var x = this._scrollContainer.scrollLeft;
|
|
|
- ms -= this.pxToVal(x);
|
|
|
- }
|
|
|
-
|
|
|
+ value: function valToPx(val) {
|
|
|
if (!this._options) {
|
|
|
- return ms;
|
|
|
+ return val;
|
|
|
}
|
|
|
|
|
|
- return ms * this._options.stepPx / this._currentZoom;
|
|
|
+ var steps = this._options.stepVal * this._currentZoom || 1;
|
|
|
+ return val * this._options.stepPx / steps;
|
|
|
}
|
|
|
/**
|
|
|
- * Snap a value to a nearest beautiful point.
|
|
|
+ * Snap a value to a nearest grid point.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "snapVal",
|
|
|
- value: function snapVal(ms) {
|
|
|
- // Apply snap to steps if enabled.
|
|
|
- if (this._options && this._options.snapsPerSeconds && this._options.snapEnabled) {
|
|
|
- var stopsPerPixel = 1000 / this._options.snapsPerSeconds;
|
|
|
- var step = ms / stopsPerPixel;
|
|
|
+ value: function snapVal(val) {
|
|
|
+ // Snap a value if configured.
|
|
|
+ if (this._options && this._options.snapEnabled && this._options.snapStep) {
|
|
|
+ var stops = this._options.snapStep;
|
|
|
+ var step = val / stops;
|
|
|
var stepsFit = Math.round(step);
|
|
|
- ms = Math.round(stepsFit * stopsPerPixel);
|
|
|
- }
|
|
|
|
|
|
- if (this._options && TimelineUtils.isNumber(this._options.min) && ms < this._options.min) {
|
|
|
- ms = 0;
|
|
|
+ var minSteps = Math.abs(this._options.min) / this._options.snapStep;
|
|
|
+
|
|
|
+ var minOffset = TimelineUtils.sign(this._options.min) * (minSteps - Math.floor(minSteps)) * this._options.snapStep;
|
|
|
+
|
|
|
+ val = Math.round(minOffset) + Math.round(stepsFit * stops);
|
|
|
}
|
|
|
|
|
|
- return ms;
|
|
|
+ val = TimelineUtils.keepInBounds(val, this._options.min, this._options.max);
|
|
|
+ return val;
|
|
|
}
|
|
|
}, {
|
|
|
key: "_mousePosToVal",
|
|
|
value: function _mousePosToVal(x) {
|
|
|
var snapEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
- var convertedVal = this.pxToVal(this._scrollContainer.scrollLeft + Math.min(x, this._width()));
|
|
|
+
|
|
|
+ var mousePos = Math.min(x, this._width()) - this._leftMargin();
|
|
|
+
|
|
|
+ var convertedVal = this._fromScreen(mousePos);
|
|
|
+
|
|
|
convertedVal = Math.round(convertedVal);
|
|
|
|
|
|
if (snapEnabled) {
|
|
@@ -2598,8 +2704,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
- key: "_formatLineGaugeText",
|
|
|
- value: function _formatLineGaugeText(ms) {
|
|
|
+ key: "_formatUnitsText",
|
|
|
+ value: function _formatUnitsText(ms) {
|
|
|
var isSeconds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
// 1- Convert to seconds:
|
|
|
var seconds = ms / 1000;
|
|
@@ -2646,57 +2752,73 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
return str;
|
|
|
}
|
|
|
+ /**
|
|
|
+ * Left padding of the timeline.
|
|
|
+ */
|
|
|
+
|
|
|
+ }, {
|
|
|
+ key: "_leftMargin",
|
|
|
+ value: function _leftMargin() {
|
|
|
+ if (!this._options) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return this._options.leftMargin || 0;
|
|
|
+ }
|
|
|
}, {
|
|
|
key: "_renderTicks",
|
|
|
value: function _renderTicks() {
|
|
|
- if (!this._ctx || !this._options) {
|
|
|
+ var rulerActive = !!this._ctx && !!this._options && !!this._ctx.canvas && this._ctx.canvas.clientWidth > 0 && this._ctx.canvas.clientHeight > 0 && this._options.stepPx;
|
|
|
+
|
|
|
+ if (!rulerActive) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- this._ctx.save();
|
|
|
+ var screenWidth = this._width() - this._leftMargin();
|
|
|
|
|
|
- var areaWidth = this._scrollContainer.scrollWidth - (this._options.leftMargin || 0);
|
|
|
- var from = this.pxToVal(this._options.min);
|
|
|
- var to = this.pxToVal(areaWidth);
|
|
|
- var dist = TimelineUtils.getDistance(from, to);
|
|
|
+ var from = this.pxToVal(this.getScrollLeft());
|
|
|
+ var to = this.pxToVal(this.getScrollLeft() + screenWidth);
|
|
|
|
|
|
- if (dist === 0) {
|
|
|
+ if (isNaN(from) || isNaN(to) || from === to) {
|
|
|
return;
|
|
|
- } // normalize step.
|
|
|
-
|
|
|
+ }
|
|
|
|
|
|
- var stepsCanFit = areaWidth / this._options.stepPx;
|
|
|
- var realStep = dist / stepsCanFit; // Find the nearest 'beautiful' step for a line gauge. This step should be divided by 1/2/5!
|
|
|
- //let step = realStep;
|
|
|
+ if (to < from) {
|
|
|
+ var wasToVal = to;
|
|
|
+ to = from;
|
|
|
+ from = wasToVal;
|
|
|
+ }
|
|
|
|
|
|
- var step = TimelineUtils.findGoodStep(realStep);
|
|
|
+ var valDistance = TimelineUtils.getDistance(from, to);
|
|
|
|
|
|
- if (step == 0 || isNaN(step) || !isFinite(step)) {
|
|
|
+ if (valDistance <= 0) {
|
|
|
return;
|
|
|
- }
|
|
|
+ } // Find the nearest 'beautiful' step for a gauge.
|
|
|
+ // 'beautiful' step should be dividable by 1/2/5/10!
|
|
|
|
|
|
- var goodStepDistancePx = areaWidth / (dist / step);
|
|
|
- var smallStepsCanFit = goodStepDistancePx / this._options.stepSmallPx;
|
|
|
- var realSmallStep = step / smallStepsCanFit;
|
|
|
- var smallStep = TimelineUtils.findGoodStep(realSmallStep, step);
|
|
|
|
|
|
- if (step % smallStep != 0) {
|
|
|
- smallStep = realSmallStep;
|
|
|
- } // filter to draw only visible
|
|
|
+ var step = TimelineUtils.findGoodStep(valDistance / (screenWidth / this._options.stepPx));
|
|
|
+ var smallStep = TimelineUtils.findGoodStep(valDistance / (screenWidth / this._options.stepSmallPx)); // Find beautiful start point:
|
|
|
|
|
|
+ var fromVal = Math.floor(from / step) * step; // Find a beautiful end point:
|
|
|
|
|
|
- var visibleFrom = this.pxToVal(this._scrollContainer.scrollLeft + this._options.leftMargin || 0);
|
|
|
- var visibleTo = this.pxToVal(this._scrollContainer.scrollLeft + this._scrollContainer.clientWidth); // Find beautiful start point:
|
|
|
+ var toVal = Math.ceil(to / step) * step + step;
|
|
|
|
|
|
- from = Math.floor(visibleFrom / step) * step; // Find a beautiful end point:
|
|
|
+ if (!TimelineUtils.isNumber(step) || step <= 0 || Math.abs(toVal - fromVal) === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- to = Math.ceil(visibleTo / step) * step + step;
|
|
|
- var lastTextX = null;
|
|
|
+ var lastTextStart = 0;
|
|
|
|
|
|
- for (var i = from; i <= to; i += step) {
|
|
|
- var pos = this.valToPx(i);
|
|
|
+ this._ctx.save();
|
|
|
+
|
|
|
+ var headerHeight = timelineStyleUtils_TimelineStyleUtils.headerHeight(this._options);
|
|
|
+ var tickHeight = headerHeight / 2;
|
|
|
+ var smallTickHeight = headerHeight / 1.3;
|
|
|
|
|
|
- var sharpPos = this._getSharp(Math.round(pos));
|
|
|
+ for (var i = fromVal; i <= toVal; i += step) {
|
|
|
+ // local
|
|
|
+ var sharpPos = this._getSharp(this._toScreenPx(i));
|
|
|
|
|
|
this._ctx.save();
|
|
|
|
|
@@ -2706,7 +2828,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
this._ctx.lineWidth = 1;
|
|
|
this._ctx.strokeStyle = this._options.tickColor;
|
|
|
- TimelineUtils.drawLine(this._ctx, sharpPos, timelineStyleUtils_TimelineStyleUtils.headerHeight(this._options) / 2, sharpPos, this._height());
|
|
|
+ TimelineUtils.drawLine(this._ctx, sharpPos, tickHeight, sharpPos, headerHeight);
|
|
|
|
|
|
this._ctx.stroke();
|
|
|
|
|
@@ -2716,31 +2838,34 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
this._ctx.font = this._options.font;
|
|
|
}
|
|
|
|
|
|
- var text = this._formatLineGaugeText(i);
|
|
|
+ var text = this._formatUnitsText(i);
|
|
|
|
|
|
var textSize = this._ctx.measureText(text);
|
|
|
|
|
|
var textX = sharpPos - textSize.width / 2; // skip text render if there is no space for it.
|
|
|
|
|
|
- if (isNaN(lastTextX) || lastTextX <= textX) {
|
|
|
- lastTextX = textX + textSize.width;
|
|
|
+ if (isNaN(lastTextStart) || lastTextStart <= textX) {
|
|
|
+ lastTextStart = textX + textSize.width;
|
|
|
|
|
|
this._ctx.fillText(text, textX, 10);
|
|
|
}
|
|
|
|
|
|
- this._ctx.restore(); // Draw small steps
|
|
|
+ this._ctx.restore();
|
|
|
|
|
|
+ if (!TimelineUtils.isNumber(smallStep) || smallStep <= 0) {
|
|
|
+ continue;
|
|
|
+ } // Draw small steps
|
|
|
|
|
|
- for (var x = i + smallStep; x < i + step; x += smallStep) {
|
|
|
- var nextPos = this.valToPx(x);
|
|
|
|
|
|
- var nextSharpPos = this._getSharp(Math.floor(nextPos));
|
|
|
+ for (var x = i + smallStep; x < i + step; x += smallStep) {
|
|
|
+ // local
|
|
|
+ var nextSharpPos = this._getSharp(this._toScreenPx(x));
|
|
|
|
|
|
this._ctx.beginPath();
|
|
|
|
|
|
this._ctx.lineWidth = this._pixelRatio;
|
|
|
this._ctx.strokeStyle = this._options.tickColor;
|
|
|
- TimelineUtils.drawLine(this._ctx, nextSharpPos, timelineStyleUtils_TimelineStyleUtils.headerHeight(this._options) / 1.3, nextSharpPos, timelineStyleUtils_TimelineStyleUtils.headerHeight(this._options));
|
|
|
+ TimelineUtils.drawLine(this._ctx, nextSharpPos, smallTickHeight, nextSharpPos, headerHeight);
|
|
|
|
|
|
this._ctx.stroke();
|
|
|
}
|
|
@@ -2748,35 +2873,6 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
this._ctx.restore();
|
|
|
}
|
|
|
- }, {
|
|
|
- key: "_setMinMax",
|
|
|
- value: function _setMinMax(to, from) {
|
|
|
- var shrink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
|
-
|
|
|
- if (!from || !to) {
|
|
|
- return to;
|
|
|
- }
|
|
|
-
|
|
|
- var isFromMinNumber = TimelineUtils.isNumber(from.min);
|
|
|
- var isToMinNumber = TimelineUtils.isNumber(to.min); // get absolute min and max bounds:
|
|
|
-
|
|
|
- if (isFromMinNumber && isToMinNumber) {
|
|
|
- to.min = shrink ? Math.min(from.min, to.min) : Math.max(from.min, to.min);
|
|
|
- } else if (isFromMinNumber) {
|
|
|
- to.min = from.min;
|
|
|
- }
|
|
|
-
|
|
|
- var isFromMaxNumber = TimelineUtils.isNumber(from.max);
|
|
|
- var isToMaxNumber = TimelineUtils.isNumber(to.max);
|
|
|
-
|
|
|
- if (isFromMaxNumber && isToMaxNumber) {
|
|
|
- to.max = shrink ? Math.max(from.max, to.max) : Math.min(from.max, to.max);
|
|
|
- } else if (isFromMaxNumber) {
|
|
|
- to.max = from.max;
|
|
|
- }
|
|
|
-
|
|
|
- return to;
|
|
|
- }
|
|
|
/**
|
|
|
* calculate virtual mode. Determine screen positions for the elements.
|
|
|
*/
|
|
@@ -2899,19 +2995,18 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
calcRow.groups.forEach(function (group) {
|
|
|
// Extend row min max bounds by a group bounds:
|
|
|
- _this6._setMinMax(calcRow, group, true); // get group screen coords
|
|
|
-
|
|
|
+ TimelineUtils.setMinMax(calcRow, group, true); // get group screen coords
|
|
|
|
|
|
var groupRect = _this6._getKeyframesGroupSize(row, calcRow.size.y, group.min, group.max);
|
|
|
|
|
|
group.size = groupRect;
|
|
|
}); // Extend screen bounds by a current calculation:
|
|
|
|
|
|
- _this6._setMinMax(toReturn, calcRow, true);
|
|
|
+ TimelineUtils.setMinMax(toReturn, calcRow, true);
|
|
|
});
|
|
|
|
|
|
if (TimelineUtils.isNumber(toReturn.max)) {
|
|
|
- toReturn.size.width = this.valToPx(toReturn.max, true);
|
|
|
+ toReturn.size.width = this.valToPx(toReturn.max);
|
|
|
}
|
|
|
|
|
|
return toReturn;
|
|
@@ -3023,8 +3118,12 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
var margin = height - groupHeight; // draw keyframes rows.
|
|
|
|
|
|
- var xMin = this.valToPx(minValue);
|
|
|
- var xMax = this.valToPx(maxValue);
|
|
|
+ var xMin = this._toScreenPx(minValue); // local
|
|
|
+
|
|
|
+
|
|
|
+ var xMax = this._toScreenPx(maxValue); // local
|
|
|
+
|
|
|
+
|
|
|
return {
|
|
|
x: xMin,
|
|
|
y: rowY + Math.floor(margin / 2),
|
|
@@ -3063,7 +3162,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
if (height > 0) {
|
|
|
if (!isNaN(val)) {
|
|
|
var toReturn = {
|
|
|
- x: Math.floor(this.valToPx(val)),
|
|
|
+ x: Math.floor(this._toScreenPx(val)),
|
|
|
+ // local
|
|
|
y: Math.floor(y),
|
|
|
height: height,
|
|
|
width: width
|
|
@@ -3230,7 +3330,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
}, {
|
|
|
key: "_renderTimeline",
|
|
|
value: function _renderTimeline() {
|
|
|
- if (!this._options || !this._options.timelineStyle) {
|
|
|
+ if (!this._ctx || !this._options || !this._options.timelineStyle) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -3241,7 +3341,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
var thickness = style.width || 1;
|
|
|
this._ctx.lineWidth = thickness * this._pixelRatio;
|
|
|
|
|
|
- var timeLinePos = this._getSharp(Math.round(this.valToPx(this._val)), thickness);
|
|
|
+ var timeLinePos = this._getSharp(this._toScreenPx(this._val), thickness);
|
|
|
|
|
|
this._ctx.strokeStyle = style.strokeColor;
|
|
|
this._ctx.fillStyle = style.fillColor;
|
|
@@ -3359,6 +3459,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
key: "_getSharp",
|
|
|
value: function _getSharp(pos) {
|
|
|
var thickness = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
|
+ pos = Math.round(pos);
|
|
|
|
|
|
if (thickness % 2 == 0) {
|
|
|
return pos;
|
|
@@ -3450,20 +3551,44 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
return this._scrollContainer ? this._scrollContainer.scrollTop : 0;
|
|
|
}
|
|
|
/**
|
|
|
- * Set this._options.
|
|
|
+ * Set options and render the component.
|
|
|
* Options will be merged with the defaults and control invalidated
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "setOptions",
|
|
|
value: function setOptions(toSet) {
|
|
|
- this._options = this._mergeOptions(toSet);
|
|
|
+ this._options = this._setOptions(toSet);
|
|
|
this.rescale();
|
|
|
this.redraw(); // Merged options:
|
|
|
|
|
|
return this._options;
|
|
|
}
|
|
|
}, {
|
|
|
+ key: "_setOptions",
|
|
|
+ value: function _setOptions(toSet) {
|
|
|
+ this._options = this._mergeOptions(toSet); // Normalize and validate spans per value.
|
|
|
+
|
|
|
+ this._options.snapStep = TimelineUtils.keepInBounds(this._options.snapStep, 0, this._options.stepVal);
|
|
|
+ this._currentZoom = this._setZoom(this._options.zoom, this._options.zoomMin, this._options.zoomMax);
|
|
|
+ this._options.min = TimelineUtils.isNumber(this._options.min) ? this._options.min : 0;
|
|
|
+ this._options.max = TimelineUtils.isNumber(this._options.max) ? this._options.max : Number.MAX_VALUE;
|
|
|
+
|
|
|
+ if (this._scrollContainer) {
|
|
|
+ var classList = this._scrollContainer.classList;
|
|
|
+
|
|
|
+ if (this._options.scrollContainerClass && classList.contains(this._options.scrollContainerClass)) {
|
|
|
+ classList.add(this._options.scrollContainerClass);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this._options.fillColor) {
|
|
|
+ this._scrollContainer.style.background = this._options.fillColor;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return this._options;
|
|
|
+ }
|
|
|
+ }, {
|
|
|
key: "getModel",
|
|
|
value: function getModel() {
|
|
|
return this._model;
|
|
@@ -3511,7 +3636,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
return {
|
|
|
x: x,
|
|
|
y: y,
|
|
|
- radius: radius
|
|
|
+ radius: radius,
|
|
|
+ args: e
|
|
|
};
|
|
|
}
|
|
|
/**
|
|
@@ -3570,7 +3696,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
var additionalOffset = this._options.stepPx;
|
|
|
newWidth = newWidth || 0; // not less than current timeline position
|
|
|
|
|
|
- var timelineGlobalPos = this.valToPx(this._val, true);
|
|
|
+ var timelineGlobalPos = this.valToPx(this._val);
|
|
|
var timelinePos = 0;
|
|
|
|
|
|
if (timelineGlobalPos > this._width()) {
|
|
@@ -3581,10 +3707,10 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var keyframeW = data.size.width + this._options.leftMargin + additionalOffset;
|
|
|
+ var keyframeW = data.size.width + this._leftMargin() + additionalOffset;
|
|
|
newWidth = Math.max(newWidth, // keyframes size
|
|
|
keyframeW, // not less than current scroll position
|
|
|
- this._scrollContainer.scrollLeft + this._width(), timelinePos);
|
|
|
+ this.getScrollLeft() + this._width(), timelinePos);
|
|
|
var minWidthPx = Math.floor(newWidth) + 'px';
|
|
|
|
|
|
if (minWidthPx != this._scrollContent.style.minWidth) {
|
|
@@ -3693,7 +3819,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
var headerHeight = timelineStyleUtils_TimelineStyleUtils.headerHeight(this._options); // Check whether we can drag timeline.
|
|
|
|
|
|
- var timeLinePos = this.valToPx(this._val);
|
|
|
+ var timeLinePos = this._toScreenPx(this._val);
|
|
|
+
|
|
|
var width = 0;
|
|
|
|
|
|
if (this._options && this._options.timelineStyle) {
|
|
@@ -3709,6 +3836,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ var snap = this._options.snapEnabled;
|
|
|
+
|
|
|
if (pos.y >= headerHeight && this._options.keyframesDraggable) {
|
|
|
this._forEachKeyframe(function (calcKeyframe, index, isNextRow) {
|
|
|
// Check keyframes group overlap
|
|
@@ -3717,7 +3846,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
|
|
|
if (rowOverlapped) {
|
|
|
var row = {
|
|
|
- val: _this10._mousePosToVal(pos.x, true),
|
|
|
+ val: _this10._mousePosToVal(pos.x, snap),
|
|
|
keyframes: calcKeyframe.parentRow.model.keyframes,
|
|
|
type: TimelineElementType.Row,
|
|
|
row: calcKeyframe.parentRow.model
|
|
@@ -3733,7 +3862,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
var keyframesModels = _this10._mapKeyframes(group.keyframes);
|
|
|
|
|
|
var groupElement = {
|
|
|
- val: _this10._mousePosToVal(pos.x, true),
|
|
|
+ val: _this10._mousePosToVal(pos.x, snap),
|
|
|
type: TimelineElementType.Group,
|
|
|
group: group,
|
|
|
row: calcKeyframe.parentRow.model,
|
|
@@ -3884,8 +4013,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
|
|
|
value: function _emitScrollEvent(args) {
|
|
|
var scrollEvent = {
|
|
|
args: args,
|
|
|
- scrollLeft: this._scrollContainer.scrollLeft,
|
|
|
- scrollTop: this._scrollContainer.scrollTop,
|
|
|
+ scrollLeft: this.getScrollLeft(),
|
|
|
+ scrollTop: this.getScrollTop(),
|
|
|
scrollHeight: this._scrollContainer.scrollHeight,
|
|
|
scrollWidth: this._scrollContainer.scrollWidth
|
|
|
};
|