Skip to content

Commit

Permalink
refactor: add onTouch callback for all touch events
Browse files Browse the repository at this point in the history
  • Loading branch information
maryia-deriv committed Aug 5, 2024
1 parent bd76665 commit 86aa3b8
Showing 1 changed file with 55 additions and 68 deletions.
123 changes: 55 additions & 68 deletions src/store/ChartAdapterStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import { safeParse } from 'src/utils';
import { capitalize } from 'src/components/ui/utils';
import MainStore from '.';

type CustomWheelEventHandler = (e: WheelEvent) => void;
type CustomTouchEventHandler = (e: TouchEvent) => void;

export default class ChartAdapterStore {
private mainStore: MainStore;
isChartLoaded = false;
Expand Down Expand Up @@ -57,8 +54,7 @@ export default class ChartAdapterStore {
makeObservable(this, {
onMount: action.bound,
onTickHistory: action.bound,
onTouchStart: action.bound,
onTouchEnd: action.bound,
onTouch: action.bound,
onChartLoad: action.bound,
onTick: action.bound,
loadHistory: action.bound,
Expand Down Expand Up @@ -205,29 +201,21 @@ export default class ChartAdapterStore {
runChartApp();
}

window.flutterChartElement?.addEventListener('wheel', this.onWheel as CustomWheelEventHandler, {
capture: true,
});
window.flutterChartElement?.addEventListener('touchstart', this.onTouchStart, { capture: true });
window.flutterChartElement?.addEventListener('touchmove', this.onWheel as CustomTouchEventHandler, {
capture: true,
});
window.flutterChartElement?.addEventListener('touchend', this.onTouchEnd, { capture: true });
window.flutterChartElement?.addEventListener('wheel', this.onWheel, { capture: true });
window.flutterChartElement?.addEventListener('touchstart', this.onTouch, { capture: true });
window.flutterChartElement?.addEventListener('touchmove', this.onTouch, { capture: true });
window.flutterChartElement?.addEventListener('touchend', this.onTouch, { capture: true });
window.flutterChartElement?.addEventListener('dblclick', this.onDoubleClick, { capture: true });
window.addEventListener('mousemove', this.onMouseMove, { capture: true });
}

onUnmount() {
window._flutter.initState.isMounted = false;

window.flutterChartElement?.removeEventListener('wheel', this.onWheel as CustomWheelEventHandler, {
capture: true,
});
window.flutterChartElement?.removeEventListener('touchstart', this.onTouchStart, { capture: true });
window.flutterChartElement?.removeEventListener('touchmove', this.onWheel as CustomTouchEventHandler, {
capture: true,
});
window.flutterChartElement?.removeEventListener('touchend', this.onTouchEnd, { capture: true });
window.flutterChartElement?.removeEventListener('wheel', this.onWheel, { capture: true });
window.flutterChartElement?.removeEventListener('touchstart', this.onTouch, { capture: true });
window.flutterChartElement?.removeEventListener('touchmove', this.onTouch, { capture: true });
window.flutterChartElement?.removeEventListener('touchend', this.onTouch, { capture: true });
window.flutterChartElement?.removeEventListener('dblclick', this.onDoubleClick, { capture: true });
window.removeEventListener('mousemove', this.onMouseMove, { capture: true });
clearTimeout(this.enableVerticalScrollTimer);
Expand All @@ -248,47 +236,22 @@ export default class ChartAdapterStore {
}
}

onTouchStart(e: TouchEvent) {
const chartNode = this.mainStore.chart.chartNode;
if (chartNode && !this.mainStore.state.isVerticalScrollEnabled && e.touches.length === 1) {
const { screenX, screenY } = e.touches[0];
this.touchValues = { x: screenX, y: screenY };
}
}
onTouchEnd(e: TouchEvent) {
const chartNode = this.mainStore.chart.chartNode;
if (chartNode && !this.mainStore.state.isVerticalScrollEnabled && e.touches.length === 1) {
this.touchValues = { yOnTouchEnd: e.touches[0].screenY };
}
}

get scrollableChartParent() {
const chartNode = this.mainStore.chart.chartNode;
if (!chartNode) return undefined;
let parent = chartNode.parentElement;
while (parent) {
const { overflow } = window.getComputedStyle(parent);
if (overflow.split(' ').every(o => o === 'auto' || o === 'scroll')) {
return parent;
}
parent = parent.parentElement;
}
return document.documentElement;
}

onWheel = (e: WheelEvent & TouchEvent) => {
if (e.type === 'wheel') e.preventDefault();

// Prevent vertical scroll on the chart if isVerticalScrollEnabled is false:
onTouch(e: TouchEvent) {
const chartNode = this.mainStore.chart.chartNode;
if (chartNode && !this.mainStore.state.isVerticalScrollEnabled) {
const nonScrollableAreaWidth = chartNode.offsetWidth - this.mainStore.chart.yAxisWidth;
const { left } = chartNode.getBoundingClientRect();
// Prevent vertical scroll on the chart for touch devices by forcing scroll on a scrollable parent of the chart:
if (
chartNode &&
this.scrollableChartParent &&
!this.mainStore.state.isVerticalScrollEnabled &&
e.touches.length === 1
) {
const { pageX, screenX, screenY } = e.touches[0];
if (['touchstart', 'touchend'].includes(e.type)) {
this.touchValues = e.type === 'touchstart' ? { x: screenX, y: screenY } : { yOnTouchEnd: screenY };
} else if (e.type === 'touchmove') {
const nonScrollableAreaWidth = chartNode.offsetWidth - this.mainStore.chart.yAxisWidth;
const { left } = chartNode.getBoundingClientRect();

if (e.type === 'touchmove') {
// Touch devices approach - forcing scroll on a scrollable parent of the chart:
if (e.touches.length > 1 && !this.scrollableChartParent) return;
const { pageX, screenX, screenY } = e.touches[0];
if (this.touchValues.x && this.touchValues.y) {
const deltaX = Math.abs(screenX - this.touchValues.x);
const deltaY = Math.abs(screenY - this.touchValues.y);
Expand All @@ -306,10 +269,18 @@ export default class ChartAdapterStore {
}
}
this.touchValues = { x: screenX, y: screenY };
return;
}
}
}

// Wheel devices approach - disabling pointer events on the chart to make its parent scrollable:
onWheel = (e: WheelEvent) => {
e.preventDefault();

// Prevent vertical scroll on the chart on wheel devices by disabling pointer events to make chart parent scrollable:
const chartNode = this.mainStore.chart.chartNode;
if (chartNode && !this.mainStore.state.isVerticalScrollEnabled) {
const nonScrollableAreaWidth = chartNode.offsetWidth - this.mainStore.chart.yAxisWidth;
const { left } = chartNode.getBoundingClientRect();
const isVerticalScroll = e.deltaY && e.deltaX === 0;
const x = e.pageX - left;
if (x < nonScrollableAreaWidth && isVerticalScroll) {
Expand Down Expand Up @@ -543,22 +514,24 @@ export default class ChartAdapterStore {
let delta_x, delta_y, ratio;

// Here we interpolate the pixel distance between two adjacent ticks.
if (bar && bar.DT! < date) {
if (bar && (bar.DT as Date) < date) {
const barNext = this.mainStore.chart.feed?.quotes[tickIdx + 1];
const barPrev = tickIdx > 0 ? this.mainStore.chart.feed?.quotes[tickIdx - 1] : null;

if (barNext && barNext.Close && barNext.DT! > date) {
delta_x = this.getXFromEpoch(barNext.DT!.getTime()) - x;
if (barNext && barNext.Close && (barNext.DT as Date) > date) {
delta_x = this.getXFromEpoch((barNext.DT as Date).getTime()) - x;

ratio =
((date as unknown as number) - bar.DT!.getTime()) / (barNext.DT!.getTime() - bar.DT!.getTime());
((date as unknown as number) - (bar.DT as Date).getTime()) /
((barNext.DT as Date).getTime() - (bar.DT as Date).getTime());

if (price) delta_y = barNext.Close - price;
} else if (barPrev && barPrev.Close) {
delta_x = x - this.getXFromEpoch(barPrev.DT!.getTime());
delta_x = x - this.getXFromEpoch((barPrev.DT as Date).getTime());

ratio =
((date as unknown as number) - bar.DT!.getTime()) / (bar.DT!.getTime() - barPrev.DT!.getTime());
((date as unknown as number) - (bar.DT as Date).getTime()) /
((bar.DT as Date).getTime() - (barPrev.DT as Date).getTime());

if (price) delta_y = price - barPrev.Close;
}
Expand Down Expand Up @@ -601,4 +574,18 @@ export default class ChartAdapterStore {
getQuoteFromY(y: number) {
return this.flutterChart?.app.getQuoteFromY(y) ?? 0;
}

get scrollableChartParent() {
const chartNode = this.mainStore.chart.chartNode;
if (!chartNode) return undefined;
let parent = chartNode.parentElement;
while (parent) {
const { overflow } = window.getComputedStyle(parent);
if (overflow.split(' ').every(o => o === 'auto' || o === 'scroll')) {
return parent;
}
parent = parent.parentElement;
}
return document.documentElement;
}
}

0 comments on commit 86aa3b8

Please sign in to comment.