Skip to content

Commit 00af85d

Browse files
authored
Merge pull request tradingview#1957 from tradingview/add-rightoffsetpixels-option
Add rightOffsetPixels option to time scale
2 parents 19b15b2 + fbd266b commit 00af85d

File tree

3 files changed

+117
-4
lines changed

3 files changed

+117
-4
lines changed

src/model/time-scale.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ export interface HorzScaleOptions {
6767
*/
6868
rightOffset: number;
6969

70+
/**
71+
* The margin space in pixels from the right side of the chart.
72+
* This option has priority over `rightOffset`.
73+
*
74+
* @defaultValue `undefined`
75+
*/
76+
rightOffsetPixels?: number;
77+
7078
/**
7179
* The space between bars in pixels.
7280
*
@@ -284,6 +292,7 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
284292
this._rightOffset = options.rightOffset;
285293
this._barSpacing = options.barSpacing;
286294
this._model = model;
295+
this._checkRightOffsetPixels(options);
287296

288297
this._horzScaleBehavior = horzScaleBehavior;
289298

@@ -324,6 +333,7 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
324333
if (options.rightOffset !== undefined) {
325334
this._model.setRightOffset(options.rightOffset);
326335
}
336+
this._checkRightOffsetPixels(options);
327337

328338
if (options.minBarSpacing !== undefined || options.maxBarSpacing !== undefined) {
329339
// yes, if we apply bar spacing constrains then we need to correct bar spacing
@@ -518,7 +528,14 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
518528
}
519529

520530
public setBarSpacing(newBarSpacing: number): void {
531+
const oldBarSpacing = this._barSpacing;
521532
this._setBarSpacing(newBarSpacing);
533+
if (this._options.rightOffsetPixels !== undefined && oldBarSpacing !== 0) {
534+
// when in pixel mode, zooming should keep the pixel offset, so we need to
535+
// recalculate the bar offset.
536+
const newRightOffset = this._rightOffset * oldBarSpacing / this._barSpacing;
537+
this._rightOffset = newRightOffset;
538+
}
522539

523540
// do not allow scroll out of visible bars
524541
this._correctOffset();
@@ -617,7 +634,14 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
617634
this._visibleRangeInvalidated = true;
618635

619636
this.setBarSpacing(this._options.barSpacing);
620-
this.setRightOffset(this._options.rightOffset);
637+
638+
let newOffset: number;
639+
if (this._options.rightOffsetPixels !== undefined) {
640+
newOffset = this._options.rightOffsetPixels / this.barSpacing();
641+
} else {
642+
newOffset = this._options.rightOffset;
643+
}
644+
this.setRightOffset(newOffset);
621645
}
622646

623647
public setBaseIndex(baseIndex: TimePointIndex | null): void {
@@ -782,10 +806,16 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
782806
return this._baseIndexOrNull || 0 as TimePointIndex;
783807
}
784808

785-
public setVisibleRange(range: RangeImpl<TimePointIndex>): void {
809+
public setVisibleRange(range: RangeImpl<TimePointIndex>, applyDefaultOffset?: boolean): void {
786810
const length = range.count();
787-
this._setBarSpacing(this._width / length);
811+
const pixelOffset = (applyDefaultOffset && this._options.rightOffsetPixels) || 0;
812+
this._setBarSpacing((this._width - pixelOffset) / length);
788813
this._rightOffset = range.right() - this.baseIndex();
814+
if (applyDefaultOffset) {
815+
this._rightOffset = pixelOffset
816+
? pixelOffset / this.barSpacing()
817+
: this._options.rightOffset;
818+
}
789819
this._correctOffset();
790820
this._visibleRangeInvalidated = true;
791821
this._model.recalculateAllPanes();
@@ -799,7 +829,7 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
799829
return;
800830
}
801831

802-
this.setVisibleRange(new RangeImpl(first, last + this._options.rightOffset as TimePointIndex));
832+
this.setVisibleRange(new RangeImpl(first, last), true);
803833
}
804834

805835
public setLogicalRange(range: LogicalRange): void {
@@ -1074,6 +1104,13 @@ export class TimeScale<HorzScaleItem> implements ITimeScale {
10741104
}
10751105
return x; // fallback to original index
10761106
}
1107+
1108+
private _checkRightOffsetPixels(options: DeepPartial<HorzScaleOptions>): void {
1109+
if (options.rightOffsetPixels !== undefined) {
1110+
const newOffset = options.rightOffsetPixels / (options.barSpacing || this._barSpacing);
1111+
this._model.setRightOffset(newOffset);
1112+
}
1113+
}
10771114
}
10781115

10791116
function* testNearestIntegers(num: number): Generator<number, number, unknown> {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function generateBar(i, target) {
2+
const step = (i % 20) / 1000;
3+
const base = i / 5;
4+
target.open = base * (1 - step);
5+
target.high = base * (1 + 2 * step);
6+
target.low = base * (1 - 2 * step);
7+
target.close = base * (1 + step);
8+
}
9+
10+
function generateData() {
11+
const res = [];
12+
const time = new Date(Date.UTC(2018, 0, 1, 0, 0, 0, 0));
13+
for (let i = 0; i < 500; ++i) {
14+
const item = {
15+
time: time.getTime() / 1000,
16+
};
17+
time.setUTCDate(time.getUTCDate() + 1);
18+
19+
generateBar(i, item);
20+
res.push(item);
21+
}
22+
return res;
23+
}
24+
25+
function runTestCase(container) {
26+
const chart = window.chart = LightweightCharts.createChart(container, {
27+
timeScale: {
28+
rightOffset: 10,
29+
rightOffsetPixels: 60, // should override rightOffset (which would have been 120 pixels when calculated)
30+
barSpacing: 12,
31+
},
32+
layout: { attributionLogo: false },
33+
});
34+
35+
const mainSeries = chart.addSeries(LightweightCharts.CandlestickSeries);
36+
37+
mainSeries.setData(generateData());
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function generateBar(i, target) {
2+
const step = (i % 20) / 1000;
3+
const base = i / 5;
4+
target.open = base * (1 - step);
5+
target.high = base * (1 + 2 * step);
6+
target.low = base * (1 - 2 * step);
7+
target.close = base * (1 + step);
8+
}
9+
10+
function generateData() {
11+
const res = [];
12+
const time = new Date(Date.UTC(2018, 0, 1, 0, 0, 0, 0));
13+
for (let i = 0; i < 50; ++i) {
14+
const item = {
15+
time: time.getTime() / 1000,
16+
};
17+
time.setUTCDate(time.getUTCDate() + 1);
18+
19+
generateBar(i, item);
20+
res.push(item);
21+
}
22+
return res;
23+
}
24+
25+
function runTestCase(container) {
26+
const chart = window.chart = LightweightCharts.createChart(container, {
27+
timeScale: {
28+
rightOffsetPixels: 100,
29+
},
30+
layout: { attributionLogo: false },
31+
});
32+
33+
const mainSeries = chart.addSeries(LightweightCharts.CandlestickSeries);
34+
35+
mainSeries.setData(generateData());
36+
37+
chart.timeScale().fitContent();
38+
}

0 commit comments

Comments
 (0)