Skip to content

Commit

Permalink
Merge pull request #1387 from tradingview/add-dbl-click-for-main-pane
Browse files Browse the repository at this point in the history
Add dbl click for main pane
  • Loading branch information
SlicedSilver committed Jul 24, 2023
2 parents 68c02fa + 6b5ecf4 commit 981ca1b
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 7 deletions.
8 changes: 4 additions & 4 deletions .size-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ module.exports = [
{
name: 'CJS',
path: 'dist/lightweight-charts.production.cjs',
limit: '46.97 KB',
limit: '47.07 KB',
},
{
name: 'ESM',
path: 'dist/lightweight-charts.production.mjs',
limit: '46.90 KB',
limit: '47.01 KB',
},
{
name: 'Standalone-ESM',
path: 'dist/lightweight-charts.standalone.production.mjs',
limit: '48.59 KB',
limit: '48.70 KB',
},
{
name: 'Standalone',
path: 'dist/lightweight-charts.standalone.production.js',
limit: '48.64 KB',
limit: '48.74 KB',
},
];
19 changes: 19 additions & 0 deletions src/api/chart-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export class ChartApi implements IChartApi, DataUpdatesConsumer<SeriesType> {
private readonly _seriesMapReversed: Map<Series, SeriesApi<SeriesType>> = new Map();

private readonly _clickedDelegate: Delegate<MouseEventParams> = new Delegate();
private readonly _dblClickedDelegate: Delegate<MouseEventParams> = new Delegate();
private readonly _crosshairMovedDelegate: Delegate<MouseEventParams> = new Delegate();

private readonly _timeScaleApi: TimeScaleApi;
Expand All @@ -138,6 +139,14 @@ export class ChartApi implements IChartApi, DataUpdatesConsumer<SeriesType> {
},
this
);
this._chartWidget.dblClicked().subscribe(
(paramSupplier: MouseEventParamsImplSupplier) => {
if (this._dblClickedDelegate.hasListeners()) {
this._dblClickedDelegate.fire(this._convertMouseParams(paramSupplier()));
}
},
this
);
this._chartWidget.crosshairMoved().subscribe(
(paramSupplier: MouseEventParamsImplSupplier) => {
if (this._crosshairMovedDelegate.hasListeners()) {
Expand All @@ -153,6 +162,7 @@ export class ChartApi implements IChartApi, DataUpdatesConsumer<SeriesType> {

public remove(): void {
this._chartWidget.clicked().unsubscribeAll(this);
this._chartWidget.dblClicked().unsubscribeAll(this);
this._chartWidget.crosshairMoved().unsubscribeAll(this);

this._timeScaleApi.destroy();
Expand All @@ -162,6 +172,7 @@ export class ChartApi implements IChartApi, DataUpdatesConsumer<SeriesType> {
this._seriesMapReversed.clear();

this._clickedDelegate.destroy();
this._dblClickedDelegate.destroy();
this._crosshairMovedDelegate.destroy();
this._dataLayer.destroy();
}
Expand Down Expand Up @@ -252,6 +263,14 @@ export class ChartApi implements IChartApi, DataUpdatesConsumer<SeriesType> {
this._clickedDelegate.unsubscribe(handler);
}

public subscribeDblClick(handler: MouseEventHandler): void {
this._dblClickedDelegate.subscribe(handler);
}

public unsubscribeDblClick(handler: MouseEventHandler): void {
this._dblClickedDelegate.unsubscribe(handler);
}

public subscribeCrosshairMove(handler: MouseEventHandler): void {
this._crosshairMovedDelegate.subscribe(handler);
}
Expand Down
30 changes: 30 additions & 0 deletions src/api/ichart-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,36 @@ export interface IChartApi {
*/
unsubscribeClick(handler: MouseEventHandler): void;

/**
* Subscribe to the chart double-click event.
*
* @param handler - Handler to be called on mouse double-click.
* @example
* ```js
* function myDblClickHandler(param) {
* if (!param.point) {
* return;
* }
*
* console.log(`Double Click at ${param.point.x}, ${param.point.y}. The time is ${param.time}.`);
* }
*
* chart.subscribeDblClick(myDblClickHandler);
* ```
*/
subscribeDblClick(handler: MouseEventHandler): void;

/**
* Unsubscribe a handler that was previously subscribed using {@link subscribeDblClick}.
*
* @param handler - Previously subscribed handler
* @example
* ```js
* chart.unsubscribeDblClick(myDblClickHandler);
* ```
*/
unsubscribeDblClick(handler: MouseEventHandler): void;

/**
* Subscribe to the crosshair move event.
*
Expand Down
17 changes: 17 additions & 0 deletions src/gui/chart-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class ChartWidget implements IDestroyable {
private _invalidateMask: InvalidateMask | null = null;
private _drawPlanned: boolean = false;
private _clicked: Delegate<MouseEventParamsImplSupplier> = new Delegate();
private _dblClicked: Delegate<MouseEventParamsImplSupplier> = new Delegate();
private _crosshairMoved: Delegate<MouseEventParamsImplSupplier> = new Delegate();
private _onWheelBound: (event: WheelEvent) => void;
private _observer: ResizeObserver | null = null;
Expand Down Expand Up @@ -151,6 +152,7 @@ export class ChartWidget implements IDestroyable {
for (const paneWidget of this._paneWidgets) {
this._tableElement.removeChild(paneWidget.getElement());
paneWidget.clicked().unsubscribeAll(this);
paneWidget.dblClicked().unsubscribeAll(this);
paneWidget.destroy();
}
this._paneWidgets = [];
Expand All @@ -168,6 +170,7 @@ export class ChartWidget implements IDestroyable {

this._crosshairMoved.destroy();
this._clicked.destroy();
this._dblClicked.destroy();

this._uninstallObserver();
}
Expand Down Expand Up @@ -234,6 +237,10 @@ export class ChartWidget implements IDestroyable {
return this._clicked;
}

public dblClicked(): ISubscription<MouseEventParamsImplSupplier> {
return this._dblClicked;
}

public crosshairMoved(): ISubscription<MouseEventParamsImplSupplier> {
return this._crosshairMoved;
}
Expand Down Expand Up @@ -684,6 +691,7 @@ export class ChartWidget implements IDestroyable {
const paneWidget = ensureDefined(this._paneWidgets.pop());
this._tableElement.removeChild(paneWidget.getElement());
paneWidget.clicked().unsubscribeAll(this);
paneWidget.dblClicked().unsubscribeAll(this);
paneWidget.destroy();

// const paneSeparator = this._paneSeparators.pop();
Expand All @@ -696,6 +704,7 @@ export class ChartWidget implements IDestroyable {
for (let i = actualPaneWidgetsCount; i < targetPaneWidgetsCount; i++) {
const paneWidget = new PaneWidget(this, panes[i]);
paneWidget.clicked().subscribe(this._onPaneWidgetClicked.bind(this), this);
paneWidget.dblClicked().subscribe(this._onPaneWidgetDblClicked.bind(this), this);

this._paneWidgets.push(paneWidget);

Expand Down Expand Up @@ -777,6 +786,14 @@ export class ChartWidget implements IDestroyable {
this._clicked.fire(() => this._getMouseEventParamsImpl(time, point, event));
}

private _onPaneWidgetDblClicked(
time: TimePointIndex | null,
point: Point | null,
event: TouchMouseEventData
): void {
this._dblClicked.fire(() => this._getMouseEventParamsImpl(time, point, event));
}

private _onPaneWidgetCrosshairMoved(
time: TimePointIndex | null,
point: Point | null,
Expand Down
24 changes: 22 additions & 2 deletions src/gui/pane-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class PaneWidget implements IDestroyable, MouseEventHandlers {
private _startScrollingPos: StartScrollPosition | null = null;
private _isScrolling: boolean = false;
private _clicked: Delegate<TimePointIndex | null, Point, TouchMouseEventData> = new Delegate();
private _dblClicked: Delegate<TimePointIndex | null, Point, TouchMouseEventData> = new Delegate();
private _prevPinchScale: number = 0;
private _longTap: boolean = false;
private _startTrackPoint: Point | null = null;
Expand Down Expand Up @@ -266,6 +267,17 @@ export class PaneWidget implements IDestroyable, MouseEventHandlers {
this._fireClickedDelegate(event);
}

public mouseDoubleClickEvent(event: MouseEventHandlerMouseEvent | MouseEventHandlerTouchEvent): void {
if (this._state === null) {
return;
}
this._fireMouseClickDelegate(this._dblClicked, event);
}

public doubleTapEvent(event: MouseEventHandlerTouchEvent): void {
this.mouseDoubleClickEvent(event);
}

public pressedMouseMoveEvent(event: MouseEventHandlerMouseEvent): void {
this._onMouseEvent();
this._pressedMouseTouchMoveEvent(event);
Expand Down Expand Up @@ -313,6 +325,10 @@ export class PaneWidget implements IDestroyable, MouseEventHandlers {
return this._clicked;
}

public dblClicked(): ISubscription<TimePointIndex | null, Point, TouchMouseEventData> {
return this._dblClicked;
}

public pinchStartEvent(): void {
this._prevPinchScale = 1;
this._model().stopTimeScaleAnimation();
Expand Down Expand Up @@ -501,10 +517,14 @@ export class PaneWidget implements IDestroyable, MouseEventHandlers {
}

private _fireClickedDelegate(event: MouseEventHandlerEventBase): void {
this._fireMouseClickDelegate(this._clicked, event);
}

private _fireMouseClickDelegate(delegate: Delegate<TimePointIndex | null, Point, TouchMouseEventData>, event: MouseEventHandlerEventBase): void {
const x = event.localX;
const y = event.localY;
if (this._clicked.hasListeners()) {
this._clicked.fire(this._model().timeScale().coordinateToIndex(x), { x, y }, event);
if (delegate.hasListeners()) {
delegate.fire(this._model().timeScale().coordinateToIndex(x), { x, y }, event);
}
}

Expand Down
5 changes: 4 additions & 1 deletion tests/e2e/helpers/perform-interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
doVerticalDrag,
} from './mouse-drag-actions';
import { doMouseScroll } from './mouse-scroll-actions';
import { pageTimeout } from './page-timeout';
import { doLongTouch, doPinchZoomTouch, doSwipeTouch } from './touch-actions';
import { doZoomInZoomOut } from './zoom-action';

Expand Down Expand Up @@ -84,7 +85,9 @@ async function performAction(
await target.click({ button: 'left' });
break;
case 'doubleClick':
await target.click({ button: 'left', clickCount: 2 });
await target.click({ button: 'left' });
await pageTimeout(page, 200);
await target.click({ button: 'left' });
break;
case 'outsideClick':
{
Expand Down
78 changes: 78 additions & 0 deletions tests/e2e/interactions/test-cases/mouse/double-click-pane.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
function generateData() {
const res = [];
const time = new Date(Date.UTC(2018, 0, 1, 0, 0, 0, 0));
for (let i = 0; i < 500; ++i) {
res.push({
time: time.getTime() / 1000,
value: i,
});

time.setUTCDate(time.getUTCDate() + 1);
}
return res;
}

function initialInteractionsToPerform() {
return [{ action: 'doubleClick', target: 'pane' }];
}

function finalInteractionsToPerform() {
return [];
}

let chart;
let clickCount = 0;
let dblClickCount = 0;

function beforeInteractions(container) {
chart = LightweightCharts.createChart(container);

const mainSeries = chart.addLineSeries();

const mainSeriesData = generateData();
mainSeries.setData(mainSeriesData);

chart.subscribeDblClick(mouseParams => {
if (!mouseParams) {
return;
}
dblClickCount += 1;
});
chart.subscribeClick(mouseParams => {
if (!mouseParams) {
return;
}
clickCount += 1;
});

return new Promise(resolve => {
requestAnimationFrame(() => {
resolve();
});
});
}

function afterInitialInteractions() {
return new Promise(resolve => {
requestAnimationFrame(resolve);
});
}

function afterFinalInteractions() {
if (clickCount < 1) {
throw new Error('Expected click event handler to be evoked.');
}
if (dblClickCount < 1) {
throw new Error('Expected double click event handler to be evoked.');
}
if (clickCount > 1) {
throw new Error('Expected click event handler to be evoked only once.');
}
if (dblClickCount > 1) {
throw new Error(
'Expected double click event handler to be evoked only once.'
);
}

return Promise.resolve();
}

0 comments on commit 981ca1b

Please sign in to comment.