private moveWhole(point: Point): void {
const snapshot = this.dragStateSnapshot;
if (!snapshot || !this.dragStartPoint) {
return;
}
if (
snapshot.startTime === null ||
snapshot.endTime === null ||
snapshot.startPrice === null ||
snapshot.endPrice === null
) {
return;
}
const offsetX = point.x - this.dragStartPoint.x;
const offsetY = point.y - this.dragStartPoint.y;
const timeOffset = this.getTimeOffsetFromPixels(offsetX);
if (timeOffset === null) {
return;
}
const nextStartTime = this.shiftTimeByOffset(snapshot.startTime, timeOffset);
const nextEndTime = this.shiftTimeByOffset(snapshot.endTime, timeOffset);
if (nextStartTime === null || nextEndTime === null) {
return;
}
const priceOffset = this.getPriceDelta(this.dragStartPoint.y, this.dragStartPoint.y + offsetY);
this.startTime = nextStartTime;
this.endTime = nextEndTime;
this.startPrice = snapshot.startPrice + priceOffset;
this.endPrice = snapshot.endPrice + priceOffset;
}
private getTimeOffsetFromPixels(offsetX: number): number | null {
const visibleRange = this.chart.timeScale().getVisibleRange();
if (!visibleRange) {
return null;
}
const { from, to } = visibleRange;
if (typeof from !== 'number' || typeof to !== 'number') {
return null;
}
const width = this.chart.timeScale().width();
if (!width) {
return null;
}
return (offsetX / width) * (to - from);
}
private shiftTimeByOffset(time: Time, offset: number): Time | null {
if (typeof time !== 'number') {
return null;
}
const nextTime = time + offset;
if (!Number.isFinite(nextTime)) {
return null;
}
return Math.round(nextTime) as Time;
}