@checksub_team/peaks_timeline 2.3.0-alpha.3 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/peaks.js +178 -65
- package/src/components/sources-layer.js +310 -99
package/package.json
CHANGED
package/peaks.js
CHANGED
|
@@ -19663,6 +19663,7 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19663
19663
|
this._rescaleVersion = 0;
|
|
19664
19664
|
this._throttledBatchDraw = this._invoker.throttleTrailing(this._layer.batchDraw.bind(this._layer));
|
|
19665
19665
|
this._drawPending = false;
|
|
19666
|
+
this._suppressDragLifecycleForSourceId = null;
|
|
19666
19667
|
this._peaks.on('handler.sources.add', this._onSourcesAdd.bind(this));
|
|
19667
19668
|
this._peaks.on('handler.sources.destroy', this._onSourcesDestroy.bind(this));
|
|
19668
19669
|
this._peaks.on('handler.sources.show', this._onSourcesShow.bind(this));
|
|
@@ -19727,9 +19728,22 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19727
19728
|
var redraw = false;
|
|
19728
19729
|
var isSourceGroupHovered = false;
|
|
19729
19730
|
var isSourceGroupDragged = false;
|
|
19731
|
+
var isActiveDraggedSource = false;
|
|
19732
|
+
var draggedAbsPos = null;
|
|
19733
|
+
var pointerPos = null;
|
|
19730
19734
|
if (sourceGroup) {
|
|
19731
19735
|
isSourceGroupHovered = sourceGroup.isHovered();
|
|
19732
19736
|
isSourceGroupDragged = sourceGroup.isDragged();
|
|
19737
|
+
isActiveDraggedSource = Boolean(isSourceGroupDragged && this.isDragInProgress() && this._draggedElementId && this._draggedElementId === source.id);
|
|
19738
|
+
if (isSourceGroupDragged) {
|
|
19739
|
+
draggedAbsPos = sourceGroup.absolutePosition();
|
|
19740
|
+
}
|
|
19741
|
+
if (isActiveDraggedSource) {
|
|
19742
|
+
pointerPos = this._view.getPointerPosition();
|
|
19743
|
+
this._suppressDragLifecycleForSourceId = source.id;
|
|
19744
|
+
sourceGroup.stopDrag();
|
|
19745
|
+
sourceGroup.setDragging(false);
|
|
19746
|
+
}
|
|
19733
19747
|
this._destroySourceGroup(source);
|
|
19734
19748
|
redraw = true;
|
|
19735
19749
|
}
|
|
@@ -19739,10 +19753,27 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19739
19753
|
newSourceGroup.startHover();
|
|
19740
19754
|
}
|
|
19741
19755
|
if (isSourceGroupDragged) {
|
|
19742
|
-
newSourceGroup.
|
|
19756
|
+
newSourceGroup.setDragging(true);
|
|
19757
|
+
if (draggedAbsPos) {
|
|
19758
|
+
newSourceGroup.moveTo(this._dragGroup);
|
|
19759
|
+
newSourceGroup.absolutePosition(draggedAbsPos);
|
|
19760
|
+
}
|
|
19761
|
+
if (isActiveDraggedSource) {
|
|
19762
|
+
if (pointerPos && draggedAbsPos) {
|
|
19763
|
+
this._dragOffsetX = draggedAbsPos.x - pointerPos.x;
|
|
19764
|
+
this._dragOffsetY = draggedAbsPos.y - pointerPos.y;
|
|
19765
|
+
} else {
|
|
19766
|
+
this._dragOffsetX = undefined;
|
|
19767
|
+
this._dragOffsetY = undefined;
|
|
19768
|
+
}
|
|
19769
|
+
newSourceGroup.startDrag();
|
|
19770
|
+
}
|
|
19743
19771
|
}
|
|
19744
19772
|
redraw = true;
|
|
19745
19773
|
}
|
|
19774
|
+
if (this._suppressDragLifecycleForSourceId === source.id) {
|
|
19775
|
+
this._suppressDragLifecycleForSourceId = null;
|
|
19776
|
+
}
|
|
19746
19777
|
if (redraw) {
|
|
19747
19778
|
this.updateSources(frameStartTime, frameEndTime);
|
|
19748
19779
|
}
|
|
@@ -19850,9 +19881,25 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19850
19881
|
this.batchDraw();
|
|
19851
19882
|
}
|
|
19852
19883
|
};
|
|
19884
|
+
SourcesLayer.prototype.isDragInProgress = function () {
|
|
19885
|
+
return this._draggedElements && this._draggedElements.length > 0;
|
|
19886
|
+
};
|
|
19887
|
+
SourcesLayer.prototype.cleanupAfterDrag = function () {
|
|
19888
|
+
this._initialSourcePositions = null;
|
|
19889
|
+
this._dragOffsetX = undefined;
|
|
19890
|
+
this._dragOffsetY = undefined;
|
|
19891
|
+
this._draggedElements = null;
|
|
19892
|
+
this._draggedElementId = null;
|
|
19893
|
+
this._draggedElementsData = null;
|
|
19894
|
+
};
|
|
19853
19895
|
SourcesLayer.prototype.onSourcesGroupDragStart = function (element) {
|
|
19854
|
-
this.
|
|
19896
|
+
if (this._suppressDragLifecycleForSourceId && element && element.currentTarget && element.currentTarget.attrs && element.currentTarget.attrs.sourceId === this._suppressDragLifecycleForSourceId) {
|
|
19897
|
+
return;
|
|
19898
|
+
}
|
|
19855
19899
|
this._mouseDownX = this._view.getPointerPosition().x;
|
|
19900
|
+
this._initialTimeOffset = this._view.getTimeOffset();
|
|
19901
|
+
this._dragOffsetX = undefined;
|
|
19902
|
+
this._dragOffsetY = undefined;
|
|
19856
19903
|
this._draggedElementId = element.currentTarget.attrs.sourceId;
|
|
19857
19904
|
var selectedElements = this._view.getSelectedElements();
|
|
19858
19905
|
const shouldDragSelectedElements = Object.keys(selectedElements).includes(this._draggedElementId);
|
|
@@ -19891,11 +19938,11 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19891
19938
|
}
|
|
19892
19939
|
});
|
|
19893
19940
|
};
|
|
19894
|
-
SourcesLayer.prototype.onSourcesGroupDragEnd = function () {
|
|
19941
|
+
SourcesLayer.prototype.onSourcesGroupDragEnd = function (element) {
|
|
19942
|
+
if (this._suppressDragLifecycleForSourceId && element && element.currentTarget && element.currentTarget.attrs && element.currentTarget.attrs.sourceId === this._suppressDragLifecycleForSourceId) {
|
|
19943
|
+
return;
|
|
19944
|
+
}
|
|
19895
19945
|
var self = this;
|
|
19896
|
-
this._initialSourcePositions = null;
|
|
19897
|
-
this._dragOffsetX = undefined;
|
|
19898
|
-
this._dragOffsetY = undefined;
|
|
19899
19946
|
const updatedSources = this._draggedElements.map(function (source) {
|
|
19900
19947
|
const sourceGroup = self._sourcesGroup[source.id];
|
|
19901
19948
|
if (sourceGroup) {
|
|
@@ -19905,10 +19952,85 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19905
19952
|
}
|
|
19906
19953
|
return source;
|
|
19907
19954
|
});
|
|
19908
|
-
this.
|
|
19955
|
+
this.cleanupAfterDrag();
|
|
19909
19956
|
this.refresh();
|
|
19910
19957
|
this.processSourceUpdates(updatedSources);
|
|
19911
19958
|
};
|
|
19959
|
+
SourcesLayer.prototype._getInitialPixelOffsetFromClickedSource = function (draggedSourceId, clickedInitialPixelX) {
|
|
19960
|
+
if (!this._initialSourcePositions) {
|
|
19961
|
+
return null;
|
|
19962
|
+
}
|
|
19963
|
+
var initialPos = this._initialSourcePositions[draggedSourceId];
|
|
19964
|
+
if (!initialPos) {
|
|
19965
|
+
return null;
|
|
19966
|
+
}
|
|
19967
|
+
var initialPixelX = this._view.timeToPixels(initialPos.startTime);
|
|
19968
|
+
return initialPixelX - clickedInitialPixelX;
|
|
19969
|
+
};
|
|
19970
|
+
SourcesLayer.prototype._maybeCreateDraggedSourceGroupInViewport = function (draggedSource, clickedSourceX, clickedSourceY, clickedInitialPixelX, viewWidth) {
|
|
19971
|
+
if (!draggedSource || this._sourcesGroup[draggedSource.id]) {
|
|
19972
|
+
return false;
|
|
19973
|
+
}
|
|
19974
|
+
var pixelOffset = this._getInitialPixelOffsetFromClickedSource(draggedSource.id, clickedInitialPixelX);
|
|
19975
|
+
if (pixelOffset === null) {
|
|
19976
|
+
return false;
|
|
19977
|
+
}
|
|
19978
|
+
var absX = clickedSourceX + pixelOffset;
|
|
19979
|
+
var width = this._view.timeToPixels(draggedSource.endTime - draggedSource.startTime);
|
|
19980
|
+
if (absX > viewWidth || absX + width < 0) {
|
|
19981
|
+
return false;
|
|
19982
|
+
}
|
|
19983
|
+
var createdGroup = this._addSourceGroup(draggedSource);
|
|
19984
|
+
createdGroup.setDragging(true);
|
|
19985
|
+
createdGroup.moveTo(this._dragGroup);
|
|
19986
|
+
createdGroup.absolutePosition({
|
|
19987
|
+
x: absX,
|
|
19988
|
+
y: clickedSourceY
|
|
19989
|
+
});
|
|
19990
|
+
return true;
|
|
19991
|
+
};
|
|
19992
|
+
SourcesLayer.prototype._createMissingDraggedSourceGroupsInViewport = function (clickedSourceX, clickedSourceY) {
|
|
19993
|
+
if (!this._draggedElements || this._draggedElements.length <= 1 || !this._initialSourcePositions || !this._draggedElementId || !this._initialSourcePositions[this._draggedElementId]) {
|
|
19994
|
+
return;
|
|
19995
|
+
}
|
|
19996
|
+
var clickedInitialPos = this._initialSourcePositions[this._draggedElementId];
|
|
19997
|
+
var clickedInitialPixelX = this._view.timeToPixels(clickedInitialPos.startTime);
|
|
19998
|
+
var viewWidth = this._view.getWidth();
|
|
19999
|
+
for (var i = 0; i < this._draggedElements.length; i++) {
|
|
20000
|
+
var draggedSource = this._draggedElements[i];
|
|
20001
|
+
if (draggedSource && draggedSource.id !== this._draggedElementId) {
|
|
20002
|
+
this._maybeCreateDraggedSourceGroupInViewport(draggedSource, clickedSourceX, clickedSourceY, clickedInitialPixelX, viewWidth);
|
|
20003
|
+
}
|
|
20004
|
+
}
|
|
20005
|
+
};
|
|
20006
|
+
SourcesLayer.prototype._positionSecondaryDraggedSourceGroups = function (clickedSourceX, clickedSourceY) {
|
|
20007
|
+
if (!this._draggedElements || this._draggedElements.length <= 1 || !this._initialSourcePositions) {
|
|
20008
|
+
return;
|
|
20009
|
+
}
|
|
20010
|
+
var clickedInitialPos = this._initialSourcePositions[this._draggedElementId];
|
|
20011
|
+
if (!clickedInitialPos) {
|
|
20012
|
+
return;
|
|
20013
|
+
}
|
|
20014
|
+
var clickedInitialPixelX = this._view.timeToPixels(clickedInitialPos.startTime);
|
|
20015
|
+
var self = this;
|
|
20016
|
+
this._draggedElements.forEach(function (source) {
|
|
20017
|
+
if (source.id === self._draggedElementId) {
|
|
20018
|
+
return;
|
|
20019
|
+
}
|
|
20020
|
+
var sourceGroup = self._sourcesGroup[source.id];
|
|
20021
|
+
if (!sourceGroup) {
|
|
20022
|
+
return;
|
|
20023
|
+
}
|
|
20024
|
+
var pixelOffset = self._getInitialPixelOffsetFromClickedSource(source.id, clickedInitialPixelX);
|
|
20025
|
+
if (pixelOffset === null) {
|
|
20026
|
+
return;
|
|
20027
|
+
}
|
|
20028
|
+
sourceGroup.absolutePosition({
|
|
20029
|
+
x: clickedSourceX + pixelOffset,
|
|
20030
|
+
y: clickedSourceY
|
|
20031
|
+
});
|
|
20032
|
+
});
|
|
20033
|
+
};
|
|
19912
20034
|
SourcesLayer.prototype.onSourcesGroupDrag = function (draggedElement) {
|
|
19913
20035
|
var pointerPos = this._view.getPointerPosition();
|
|
19914
20036
|
this._view.updateWithAutoScroll(this._dragSourcesGroup.bind(this), null, true);
|
|
@@ -19927,29 +20049,8 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
19927
20049
|
}
|
|
19928
20050
|
var clickedSourceX = mouseX + offsetX;
|
|
19929
20051
|
var clickedSourceY = mouseY + offsetY;
|
|
19930
|
-
|
|
19931
|
-
|
|
19932
|
-
var clickedInitialPos = this._initialSourcePositions[this._draggedElementId];
|
|
19933
|
-
if (clickedInitialPos) {
|
|
19934
|
-
var clickedInitialPixelX = this._view.timeToPixels(clickedInitialPos.startTime);
|
|
19935
|
-
this._draggedElements.forEach(function (source) {
|
|
19936
|
-
if (source.id !== self._draggedElementId) {
|
|
19937
|
-
var sourceGroup = self._sourcesGroup[source.id];
|
|
19938
|
-
if (sourceGroup) {
|
|
19939
|
-
var initialPos = self._initialSourcePositions[source.id];
|
|
19940
|
-
if (initialPos) {
|
|
19941
|
-
var initialPixelX = self._view.timeToPixels(initialPos.startTime);
|
|
19942
|
-
var pixelOffset = initialPixelX - clickedInitialPixelX;
|
|
19943
|
-
sourceGroup.absolutePosition({
|
|
19944
|
-
x: clickedSourceX + pixelOffset,
|
|
19945
|
-
y: clickedSourceY
|
|
19946
|
-
});
|
|
19947
|
-
}
|
|
19948
|
-
}
|
|
19949
|
-
}
|
|
19950
|
-
});
|
|
19951
|
-
}
|
|
19952
|
-
}
|
|
20052
|
+
this._createMissingDraggedSourceGroupsInViewport(clickedSourceX, clickedSourceY);
|
|
20053
|
+
this._positionSecondaryDraggedSourceGroups(clickedSourceX, clickedSourceY);
|
|
19953
20054
|
return {
|
|
19954
20055
|
x: clickedSourceX,
|
|
19955
20056
|
y: clickedSourceY
|
|
@@ -20007,38 +20108,40 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
20007
20108
|
});
|
|
20008
20109
|
};
|
|
20009
20110
|
SourcesLayer.prototype._applyTimeChangesToSources = function (sources, initialStartTime, newStartTime, newEndTime) {
|
|
20111
|
+
if (!sources || sources.length === 0) {
|
|
20112
|
+
return;
|
|
20113
|
+
}
|
|
20010
20114
|
if (sources.length === 1) {
|
|
20011
20115
|
sources[0].updateTimes(newStartTime, newEndTime);
|
|
20012
|
-
|
|
20013
|
-
|
|
20014
|
-
|
|
20015
|
-
|
|
20016
|
-
|
|
20017
|
-
|
|
20018
|
-
|
|
20019
|
-
|
|
20116
|
+
return;
|
|
20117
|
+
}
|
|
20118
|
+
if (typeof newStartTime !== 'number') {
|
|
20119
|
+
return;
|
|
20120
|
+
}
|
|
20121
|
+
if (this.isDragInProgress() && this._draggedElementsData && this._initialSourcePositions && typeof this._draggedElementsData.initialStartTime === 'number' && isFinite(this._draggedElementsData.initialStartTime)) {
|
|
20122
|
+
var timeDiffFromDragStart = Utils.roundTime(newStartTime - this._draggedElementsData.initialStartTime);
|
|
20123
|
+
for (var d = 0; d < sources.length; d++) {
|
|
20124
|
+
var draggedSource = sources[d];
|
|
20125
|
+
var initialPos = this._initialSourcePositions[draggedSource.id];
|
|
20126
|
+
if (!initialPos) {
|
|
20127
|
+
this._initialSourcePositions[draggedSource.id] = {
|
|
20128
|
+
startTime: draggedSource.startTime,
|
|
20129
|
+
endTime: draggedSource.endTime,
|
|
20130
|
+
lineId: draggedSource.lineId
|
|
20131
|
+
};
|
|
20132
|
+
initialPos = this._initialSourcePositions[draggedSource.id];
|
|
20020
20133
|
}
|
|
20134
|
+
draggedSource.updateTimes(Utils.roundTime(initialPos.startTime + timeDiffFromDragStart), Utils.roundTime(initialPos.endTime + timeDiffFromDragStart));
|
|
20021
20135
|
}
|
|
20022
|
-
|
|
20023
|
-
|
|
20024
|
-
|
|
20025
|
-
|
|
20026
|
-
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
source.updateTimes(Utils.roundTime(initialPos.startTime + timeDiffFromInitial), Utils.roundTime(initialPos.endTime + timeDiffFromInitial));
|
|
20030
|
-
});
|
|
20031
|
-
}
|
|
20032
|
-
} else {
|
|
20033
|
-
const timeDiff = Utils.roundTime(newStartTime - initialStartTime);
|
|
20034
|
-
if (timeDiff !== 0) {
|
|
20035
|
-
sources.forEach(function (source) {
|
|
20036
|
-
source.updateTimes(Utils.roundTime(source.startTime + timeDiff), Utils.roundTime(source.endTime + timeDiff));
|
|
20037
|
-
});
|
|
20038
|
-
}
|
|
20136
|
+
return;
|
|
20137
|
+
}
|
|
20138
|
+
var timeDiff = Utils.roundTime(newStartTime - initialStartTime);
|
|
20139
|
+
if (timeDiff !== 0) {
|
|
20140
|
+
for (var s = 0; s < sources.length; s++) {
|
|
20141
|
+
var source = sources[s];
|
|
20142
|
+
source.updateTimes(Utils.roundTime(source.startTime + timeDiff), Utils.roundTime(source.endTime + timeDiff));
|
|
20039
20143
|
}
|
|
20040
20144
|
}
|
|
20041
|
-
this.refresh();
|
|
20042
20145
|
};
|
|
20043
20146
|
SourcesLayer.prototype.manageSourceMovements = function (sources, newStartTime, newEndTime, orderable, mouseX, mouseY) {
|
|
20044
20147
|
newStartTime = typeof newStartTime === 'number' ? Utils.roundTime(newStartTime) : newStartTime;
|
|
@@ -20052,6 +20155,7 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
20052
20155
|
({newStartTime, newEndTime} = this.manageCollision(sources, newStartTime, newEndTime));
|
|
20053
20156
|
this._applyTimeChangesToSources(sources, sources[0].startTime, newStartTime, newEndTime);
|
|
20054
20157
|
this._view.setTimelineLength(this._view.timeToPixels(sources[sources.length - 1].endTime) + this._view.getWidth());
|
|
20158
|
+
this.refresh();
|
|
20055
20159
|
return true;
|
|
20056
20160
|
};
|
|
20057
20161
|
SourcesLayer.prototype.manageVerticalPosition = function (sources, startTime, endTime, mouseX, mouseY) {
|
|
@@ -20074,16 +20178,25 @@ module.exports = function (SourceGroup, LineGroups, DataRetriever, Invoker, Util
|
|
|
20074
20178
|
sourceGroup = this._addSourceGroup(source);
|
|
20075
20179
|
isNewlyCreated = true;
|
|
20076
20180
|
}
|
|
20077
|
-
if (isNewlyCreated && this.
|
|
20078
|
-
|
|
20079
|
-
|
|
20080
|
-
|
|
20081
|
-
|
|
20082
|
-
|
|
20083
|
-
|
|
20084
|
-
|
|
20085
|
-
|
|
20181
|
+
if (isNewlyCreated && this._initialSourcePositions && this._initialSourcePositions[source.id]) {
|
|
20182
|
+
sourceGroup.setDragging(true);
|
|
20183
|
+
var targetAbsPos = sourceGroup.absolutePosition();
|
|
20184
|
+
var clickedId = this._draggedElementId;
|
|
20185
|
+
var clickedGroup = clickedId ? this._sourcesGroup[clickedId] : null;
|
|
20186
|
+
var clickedInitial = clickedId && this._initialSourcePositions ? this._initialSourcePositions[clickedId] : null;
|
|
20187
|
+
var currentInitial = this._initialSourcePositions[source.id];
|
|
20188
|
+
if (clickedGroup && clickedInitial && currentInitial) {
|
|
20189
|
+
var clickedAbsPos = clickedGroup.absolutePosition();
|
|
20190
|
+
var clickedInitialPixelX = this._view.timeToPixels(clickedInitial.startTime);
|
|
20191
|
+
var currentInitialPixelX = this._view.timeToPixels(currentInitial.startTime);
|
|
20192
|
+
var pixelOffset = currentInitialPixelX - clickedInitialPixelX;
|
|
20193
|
+
targetAbsPos = {
|
|
20194
|
+
x: clickedAbsPos.x + pixelOffset,
|
|
20195
|
+
y: clickedAbsPos.y
|
|
20196
|
+
};
|
|
20086
20197
|
}
|
|
20198
|
+
sourceGroup.moveTo(this._dragGroup);
|
|
20199
|
+
sourceGroup.absolutePosition(targetAbsPos);
|
|
20087
20200
|
}
|
|
20088
20201
|
return sourceGroup;
|
|
20089
20202
|
};
|
|
@@ -66,6 +66,10 @@ define([
|
|
|
66
66
|
// Pending draw flag to coalesce multiple draw requests
|
|
67
67
|
this._drawPending = false;
|
|
68
68
|
|
|
69
|
+
// Used to suppress drag lifecycle callbacks when a dragged source is
|
|
70
|
+
// temporarily stopped/restarted as part of a rebuild.
|
|
71
|
+
this._suppressDragLifecycleForSourceId = null;
|
|
72
|
+
|
|
69
73
|
this._peaks.on('handler.sources.add', this._onSourcesAdd.bind(this));
|
|
70
74
|
this._peaks.on('handler.sources.destroy', this._onSourcesDestroy.bind(this));
|
|
71
75
|
this._peaks.on('handler.sources.show', this._onSourcesShow.bind(this));
|
|
@@ -156,10 +160,44 @@ define([
|
|
|
156
160
|
var redraw = false;
|
|
157
161
|
var isSourceGroupHovered = false;
|
|
158
162
|
var isSourceGroupDragged = false;
|
|
163
|
+
var isActiveDraggedSource = false;
|
|
164
|
+
|
|
165
|
+
// If a source is updated while being dragged, we still want the update to apply.
|
|
166
|
+
// But destroying a node mid-drag without stopping the drag can leave an orphaned
|
|
167
|
+
// visual on Konva's drag layer. So we stop drag, rebuild, and resume.
|
|
168
|
+
var draggedAbsPos = null;
|
|
169
|
+
var pointerPos = null;
|
|
159
170
|
|
|
160
171
|
if (sourceGroup) {
|
|
161
172
|
isSourceGroupHovered = sourceGroup.isHovered();
|
|
162
173
|
isSourceGroupDragged = sourceGroup.isDragged();
|
|
174
|
+
|
|
175
|
+
// Only the actively mouse-dragged source should have its Konva drag
|
|
176
|
+
// stopped/restarted. Secondary sources in a multi-drag are positioned
|
|
177
|
+
// manually (absolutePosition) and should not be put into Konva's drag
|
|
178
|
+
// layer.
|
|
179
|
+
isActiveDraggedSource = Boolean(
|
|
180
|
+
isSourceGroupDragged
|
|
181
|
+
&& this.isDragInProgress()
|
|
182
|
+
&& this._draggedElementId
|
|
183
|
+
&& this._draggedElementId === source.id
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (isSourceGroupDragged) {
|
|
187
|
+
draggedAbsPos = sourceGroup.absolutePosition();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (isActiveDraggedSource) {
|
|
191
|
+
pointerPos = this._view.getPointerPosition();
|
|
192
|
+
|
|
193
|
+
// Ensure Konva's internal drag state is cleaned up before destruction.
|
|
194
|
+
// We suppress our drag lifecycle handlers so multi-drag state isn't
|
|
195
|
+
// torn down/reinitialized for a single frame.
|
|
196
|
+
this._suppressDragLifecycleForSourceId = source.id;
|
|
197
|
+
sourceGroup.stopDrag();
|
|
198
|
+
sourceGroup.setDragging(false);
|
|
199
|
+
}
|
|
200
|
+
|
|
163
201
|
this._destroySourceGroup(source);
|
|
164
202
|
redraw = true;
|
|
165
203
|
}
|
|
@@ -170,12 +208,38 @@ define([
|
|
|
170
208
|
if (isSourceGroupHovered) {
|
|
171
209
|
newSourceGroup.startHover();
|
|
172
210
|
}
|
|
211
|
+
|
|
173
212
|
if (isSourceGroupDragged) {
|
|
174
|
-
|
|
213
|
+
// Put the rebuilt group back into the drag group.
|
|
214
|
+
newSourceGroup.setDragging(true);
|
|
215
|
+
|
|
216
|
+
if (draggedAbsPos) {
|
|
217
|
+
newSourceGroup.moveTo(this._dragGroup);
|
|
218
|
+
newSourceGroup.absolutePosition(draggedAbsPos);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (isActiveDraggedSource) {
|
|
222
|
+
// Recompute offsets so the cursor-to-node relation stays stable.
|
|
223
|
+
if (pointerPos && draggedAbsPos) {
|
|
224
|
+
this._dragOffsetX = draggedAbsPos.x - pointerPos.x;
|
|
225
|
+
this._dragOffsetY = draggedAbsPos.y - pointerPos.y;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
this._dragOffsetX = undefined;
|
|
229
|
+
this._dragOffsetY = undefined;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Only resume Konva drag for the active mouse-dragged source.
|
|
233
|
+
newSourceGroup.startDrag();
|
|
234
|
+
}
|
|
175
235
|
}
|
|
176
236
|
redraw = true;
|
|
177
237
|
}
|
|
178
238
|
|
|
239
|
+
if (this._suppressDragLifecycleForSourceId === source.id) {
|
|
240
|
+
this._suppressDragLifecycleForSourceId = null;
|
|
241
|
+
}
|
|
242
|
+
|
|
179
243
|
if (redraw) {
|
|
180
244
|
this.updateSources(frameStartTime, frameEndTime);
|
|
181
245
|
}
|
|
@@ -351,9 +415,32 @@ define([
|
|
|
351
415
|
}
|
|
352
416
|
};
|
|
353
417
|
|
|
418
|
+
SourcesLayer.prototype.isDragInProgress = function() {
|
|
419
|
+
return this._draggedElements && this._draggedElements.length > 0;
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
SourcesLayer.prototype.cleanupAfterDrag = function() {
|
|
423
|
+
this._initialSourcePositions = null;
|
|
424
|
+
this._dragOffsetX = undefined;
|
|
425
|
+
this._dragOffsetY = undefined;
|
|
426
|
+
this._draggedElements = null;
|
|
427
|
+
this._draggedElementId = null;
|
|
428
|
+
this._draggedElementsData = null;
|
|
429
|
+
};
|
|
430
|
+
|
|
354
431
|
SourcesLayer.prototype.onSourcesGroupDragStart = function(element) {
|
|
355
|
-
|
|
432
|
+
if (this._suppressDragLifecycleForSourceId
|
|
433
|
+
&& element
|
|
434
|
+
&& element.currentTarget
|
|
435
|
+
&& element.currentTarget.attrs
|
|
436
|
+
&& element.currentTarget.attrs.sourceId === this._suppressDragLifecycleForSourceId) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
356
440
|
this._mouseDownX = this._view.getPointerPosition().x;
|
|
441
|
+
this._initialTimeOffset = this._view.getTimeOffset();
|
|
442
|
+
this._dragOffsetX = undefined;
|
|
443
|
+
this._dragOffsetY = undefined;
|
|
357
444
|
|
|
358
445
|
this._draggedElementId = element.currentTarget.attrs.sourceId;
|
|
359
446
|
|
|
@@ -415,12 +502,16 @@ define([
|
|
|
415
502
|
});
|
|
416
503
|
};
|
|
417
504
|
|
|
418
|
-
SourcesLayer.prototype.onSourcesGroupDragEnd = function() {
|
|
419
|
-
|
|
505
|
+
SourcesLayer.prototype.onSourcesGroupDragEnd = function(element) {
|
|
506
|
+
if (this._suppressDragLifecycleForSourceId
|
|
507
|
+
&& element
|
|
508
|
+
&& element.currentTarget
|
|
509
|
+
&& element.currentTarget.attrs
|
|
510
|
+
&& element.currentTarget.attrs.sourceId === this._suppressDragLifecycleForSourceId) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
420
513
|
|
|
421
|
-
|
|
422
|
-
this._dragOffsetX = undefined;
|
|
423
|
-
this._dragOffsetY = undefined;
|
|
514
|
+
var self = this;
|
|
424
515
|
|
|
425
516
|
const updatedSources = this._draggedElements.map(
|
|
426
517
|
function(source) {
|
|
@@ -440,12 +531,131 @@ define([
|
|
|
440
531
|
}
|
|
441
532
|
);
|
|
442
533
|
|
|
443
|
-
this.
|
|
534
|
+
this.cleanupAfterDrag();
|
|
444
535
|
|
|
445
536
|
this.refresh();
|
|
446
537
|
this.processSourceUpdates(updatedSources);
|
|
447
538
|
};
|
|
448
539
|
|
|
540
|
+
SourcesLayer.prototype._getInitialPixelOffsetFromClickedSource = function(draggedSourceId, clickedInitialPixelX) {
|
|
541
|
+
if (!this._initialSourcePositions) {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
var initialPos = this._initialSourcePositions[draggedSourceId];
|
|
546
|
+
|
|
547
|
+
if (!initialPos) {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
var initialPixelX = this._view.timeToPixels(initialPos.startTime);
|
|
552
|
+
|
|
553
|
+
return initialPixelX - clickedInitialPixelX;
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
SourcesLayer.prototype._maybeCreateDraggedSourceGroupInViewport = function(
|
|
557
|
+
draggedSource,
|
|
558
|
+
clickedSourceX,
|
|
559
|
+
clickedSourceY,
|
|
560
|
+
clickedInitialPixelX,
|
|
561
|
+
viewWidth
|
|
562
|
+
) {
|
|
563
|
+
if (!draggedSource || this._sourcesGroup[draggedSource.id]) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
var pixelOffset = this._getInitialPixelOffsetFromClickedSource(draggedSource.id, clickedInitialPixelX);
|
|
568
|
+
|
|
569
|
+
if (pixelOffset === null) {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
var absX = clickedSourceX + pixelOffset;
|
|
574
|
+
var width = this._view.timeToPixels(draggedSource.endTime - draggedSource.startTime);
|
|
575
|
+
|
|
576
|
+
// If it intersects the visible viewport, create it now.
|
|
577
|
+
if (absX > viewWidth || (absX + width) < 0) {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
var createdGroup = this._addSourceGroup(draggedSource);
|
|
582
|
+
|
|
583
|
+
createdGroup.setDragging(true);
|
|
584
|
+
createdGroup.moveTo(this._dragGroup);
|
|
585
|
+
createdGroup.absolutePosition({
|
|
586
|
+
x: absX,
|
|
587
|
+
y: clickedSourceY
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
return true;
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
SourcesLayer.prototype._createMissingDraggedSourceGroupsInViewport = function(clickedSourceX, clickedSourceY) {
|
|
594
|
+
if (!this._draggedElements
|
|
595
|
+
|| this._draggedElements.length <= 1
|
|
596
|
+
|| !this._initialSourcePositions
|
|
597
|
+
|| !this._draggedElementId
|
|
598
|
+
|| !this._initialSourcePositions[this._draggedElementId]) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
var clickedInitialPos = this._initialSourcePositions[this._draggedElementId];
|
|
603
|
+
var clickedInitialPixelX = this._view.timeToPixels(clickedInitialPos.startTime);
|
|
604
|
+
var viewWidth = this._view.getWidth();
|
|
605
|
+
|
|
606
|
+
for (var i = 0; i < this._draggedElements.length; i++) {
|
|
607
|
+
var draggedSource = this._draggedElements[i];
|
|
608
|
+
|
|
609
|
+
if (draggedSource && draggedSource.id !== this._draggedElementId) {
|
|
610
|
+
this._maybeCreateDraggedSourceGroupInViewport(
|
|
611
|
+
draggedSource,
|
|
612
|
+
clickedSourceX,
|
|
613
|
+
clickedSourceY,
|
|
614
|
+
clickedInitialPixelX,
|
|
615
|
+
viewWidth
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
SourcesLayer.prototype._positionSecondaryDraggedSourceGroups = function(clickedSourceX, clickedSourceY) {
|
|
622
|
+
if (!this._draggedElements || this._draggedElements.length <= 1 || !this._initialSourcePositions) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
var clickedInitialPos = this._initialSourcePositions[this._draggedElementId];
|
|
627
|
+
|
|
628
|
+
if (!clickedInitialPos) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
var clickedInitialPixelX = this._view.timeToPixels(clickedInitialPos.startTime);
|
|
633
|
+
var self = this;
|
|
634
|
+
|
|
635
|
+
this._draggedElements.forEach(function(source) {
|
|
636
|
+
if (source.id === self._draggedElementId) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
var sourceGroup = self._sourcesGroup[source.id];
|
|
641
|
+
|
|
642
|
+
if (!sourceGroup) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
var pixelOffset = self._getInitialPixelOffsetFromClickedSource(source.id, clickedInitialPixelX);
|
|
647
|
+
|
|
648
|
+
if (pixelOffset === null) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
sourceGroup.absolutePosition({
|
|
653
|
+
x: clickedSourceX + pixelOffset,
|
|
654
|
+
y: clickedSourceY
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
};
|
|
658
|
+
|
|
449
659
|
SourcesLayer.prototype.onSourcesGroupDrag = function(draggedElement) {
|
|
450
660
|
var pointerPos = this._view.getPointerPosition();
|
|
451
661
|
|
|
@@ -473,38 +683,13 @@ define([
|
|
|
473
683
|
var clickedSourceX = mouseX + offsetX;
|
|
474
684
|
var clickedSourceY = mouseY + offsetY;
|
|
475
685
|
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
var clickedInitialPixelX = this._view.timeToPixels(clickedInitialPos.startTime);
|
|
484
|
-
|
|
485
|
-
this._draggedElements.forEach(function(source) {
|
|
486
|
-
if (source.id !== self._draggedElementId) {
|
|
487
|
-
var sourceGroup = self._sourcesGroup[source.id];
|
|
488
|
-
|
|
489
|
-
if (sourceGroup) {
|
|
490
|
-
var initialPos = self._initialSourcePositions[source.id];
|
|
491
|
-
|
|
492
|
-
if (initialPos) {
|
|
493
|
-
// Calculate pixel offset from clicked source's initial position
|
|
494
|
-
var initialPixelX = self._view.timeToPixels(initialPos.startTime);
|
|
495
|
-
var pixelOffset = initialPixelX - clickedInitialPixelX;
|
|
496
|
-
|
|
497
|
-
// Position this source relative to clicked source's current position
|
|
498
|
-
sourceGroup.absolutePosition({
|
|
499
|
-
x: clickedSourceX + pixelOffset,
|
|
500
|
-
y: clickedSourceY
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
}
|
|
686
|
+
// If we're dragging multiple sources, some dragged sources might not yet
|
|
687
|
+
// have a SourceGroup (they were outside the view when the drag started).
|
|
688
|
+
// Create them as soon as their on-canvas bounds intersect the viewport.
|
|
689
|
+
this._createMissingDraggedSourceGroupsInViewport(clickedSourceX, clickedSourceY);
|
|
690
|
+
|
|
691
|
+
// Position all other dragged sources relative to the clicked source.
|
|
692
|
+
this._positionSecondaryDraggedSourceGroups(clickedSourceX, clickedSourceY);
|
|
508
693
|
|
|
509
694
|
return {
|
|
510
695
|
x: clickedSourceX,
|
|
@@ -607,60 +792,71 @@ define([
|
|
|
607
792
|
|
|
608
793
|
SourcesLayer.prototype._applyTimeChangesToSources = function(sources, initialStartTime, newStartTime, newEndTime
|
|
609
794
|
) {
|
|
795
|
+
if (!sources || sources.length === 0) {
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Single-source updates can be moves or resizes; Source.updateTimes handles
|
|
800
|
+
// undefined for one side.
|
|
610
801
|
if (sources.length === 1) {
|
|
611
|
-
sources[0].updateTimes(
|
|
612
|
-
|
|
613
|
-
newEndTime
|
|
614
|
-
);
|
|
802
|
+
sources[0].updateTimes(newStartTime, newEndTime);
|
|
803
|
+
return;
|
|
615
804
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
805
|
+
|
|
806
|
+
// Multi-source updates are treated as a block move, so we need a numeric
|
|
807
|
+
// start time to compute a delta. (Single-source resizes can pass null/undefined
|
|
808
|
+
// for one side, but that does not apply to multi-source moves.)
|
|
809
|
+
if (typeof newStartTime !== 'number') {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// During an active drag, always compute a single delta from the drag-start
|
|
814
|
+
// bounds and apply it from the stored drag-start positions. This prevents
|
|
815
|
+
// drift/jumps when sources are rebuilt or lines are changed repeatedly
|
|
816
|
+
// without releasing the drag.
|
|
817
|
+
if (this.isDragInProgress()
|
|
818
|
+
&& this._draggedElementsData
|
|
819
|
+
&& this._initialSourcePositions
|
|
820
|
+
&& typeof this._draggedElementsData.initialStartTime === 'number'
|
|
821
|
+
&& isFinite(this._draggedElementsData.initialStartTime)) {
|
|
822
|
+
var timeDiffFromDragStart = Utils.roundTime(newStartTime - this._draggedElementsData.initialStartTime);
|
|
823
|
+
|
|
824
|
+
for (var d = 0; d < sources.length; d++) {
|
|
825
|
+
var draggedSource = sources[d];
|
|
826
|
+
var initialPos = this._initialSourcePositions[draggedSource.id];
|
|
827
|
+
|
|
828
|
+
// Be defensive: if a source enters the dragged set mid-drag (or an
|
|
829
|
+
// entry was missing), capture its baseline once to avoid drift.
|
|
830
|
+
if (!initialPos) {
|
|
831
|
+
this._initialSourcePositions[draggedSource.id] = {
|
|
832
|
+
startTime: draggedSource.startTime,
|
|
833
|
+
endTime: draggedSource.endTime,
|
|
834
|
+
lineId: draggedSource.lineId
|
|
835
|
+
};
|
|
836
|
+
initialPos = this._initialSourcePositions[draggedSource.id];
|
|
628
837
|
}
|
|
838
|
+
|
|
839
|
+
draggedSource.updateTimes(
|
|
840
|
+
Utils.roundTime(initialPos.startTime + timeDiffFromDragStart),
|
|
841
|
+
Utils.roundTime(initialPos.endTime + timeDiffFromDragStart)
|
|
842
|
+
);
|
|
629
843
|
}
|
|
630
844
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
var timeDiffFromInitial = Utils.roundTime(newStartTime - firstInitial.startTime);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
634
847
|
|
|
635
|
-
|
|
636
|
-
var self = this;
|
|
848
|
+
var timeDiff = Utils.roundTime(newStartTime - initialStartTime);
|
|
637
849
|
|
|
638
|
-
|
|
639
|
-
|
|
850
|
+
if (timeDiff !== 0) {
|
|
851
|
+
for (var s = 0; s < sources.length; s++) {
|
|
852
|
+
var source = sources[s];
|
|
640
853
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
649
|
-
// Fallback for non-drag multi-updates.
|
|
650
|
-
const timeDiff = Utils.roundTime(newStartTime - initialStartTime);
|
|
651
|
-
|
|
652
|
-
if (timeDiff !== 0) {
|
|
653
|
-
sources.forEach(function(source) {
|
|
654
|
-
source.updateTimes(
|
|
655
|
-
Utils.roundTime(source.startTime + timeDiff),
|
|
656
|
-
Utils.roundTime(source.endTime + timeDiff)
|
|
657
|
-
);
|
|
658
|
-
});
|
|
659
|
-
}
|
|
854
|
+
source.updateTimes(
|
|
855
|
+
Utils.roundTime(source.startTime + timeDiff),
|
|
856
|
+
Utils.roundTime(source.endTime + timeDiff)
|
|
857
|
+
);
|
|
660
858
|
}
|
|
661
859
|
}
|
|
662
|
-
|
|
663
|
-
this.refresh();
|
|
664
860
|
};
|
|
665
861
|
|
|
666
862
|
// WARNING: This assumes that no sources between the start and the end are unselected
|
|
@@ -685,6 +881,8 @@ define([
|
|
|
685
881
|
this._view.timeToPixels(sources[sources.length - 1].endTime) + this._view.getWidth()
|
|
686
882
|
);
|
|
687
883
|
|
|
884
|
+
this.refresh();
|
|
885
|
+
|
|
688
886
|
return true;
|
|
689
887
|
};
|
|
690
888
|
|
|
@@ -721,22 +919,35 @@ define([
|
|
|
721
919
|
|
|
722
920
|
// If this source is being dragged and was just recreated (came back into view),
|
|
723
921
|
// set it up properly for dragging
|
|
724
|
-
if (isNewlyCreated && this.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
922
|
+
if (isNewlyCreated && this._initialSourcePositions && this._initialSourcePositions[source.id]) {
|
|
923
|
+
// Mark as dragging
|
|
924
|
+
sourceGroup.setDragging(true);
|
|
925
|
+
|
|
926
|
+
// Compute where this source should be while the group drag is in progress.
|
|
927
|
+
// We prefer positioning relative to the clicked dragged source so the
|
|
928
|
+
// source appears immediately when it enters the viewport.
|
|
929
|
+
var targetAbsPos = sourceGroup.absolutePosition();
|
|
930
|
+
|
|
931
|
+
var clickedId = this._draggedElementId;
|
|
932
|
+
var clickedGroup = clickedId ? this._sourcesGroup[clickedId] : null;
|
|
933
|
+
var clickedInitial = clickedId && this._initialSourcePositions ? this._initialSourcePositions[clickedId] : null;
|
|
934
|
+
var currentInitial = this._initialSourcePositions[source.id];
|
|
935
|
+
|
|
936
|
+
if (clickedGroup && clickedInitial && currentInitial) {
|
|
937
|
+
var clickedAbsPos = clickedGroup.absolutePosition();
|
|
938
|
+
var clickedInitialPixelX = this._view.timeToPixels(clickedInitial.startTime);
|
|
939
|
+
var currentInitialPixelX = this._view.timeToPixels(currentInitial.startTime);
|
|
940
|
+
var pixelOffset = currentInitialPixelX - clickedInitialPixelX;
|
|
941
|
+
|
|
942
|
+
targetAbsPos = {
|
|
943
|
+
x: clickedAbsPos.x + pixelOffset,
|
|
944
|
+
y: clickedAbsPos.y
|
|
945
|
+
};
|
|
739
946
|
}
|
|
947
|
+
|
|
948
|
+
// Move to drag group and apply the computed absolute position.
|
|
949
|
+
sourceGroup.moveTo(this._dragGroup);
|
|
950
|
+
sourceGroup.absolutePosition(targetAbsPos);
|
|
740
951
|
}
|
|
741
952
|
|
|
742
953
|
return sourceGroup;
|