Skip to content

Commit

Permalink
added usePannign hook, fixed useRenderer lint issue
Browse files Browse the repository at this point in the history
  • Loading branch information
ctw-joao-luis committed Jan 9, 2025
1 parent 0393e7e commit 553fa0b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 87 deletions.
90 changes: 4 additions & 86 deletions packages/suite-base/src/panels/Plot/Plot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/

import { Button, Tooltip, Fade, useTheme } from "@mui/material";
import Hammer from "hammerjs";
import * as _ from "lodash-es";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useMountedState } from "react-use";
Expand All @@ -33,11 +32,11 @@ import useGlobalVariables from "@lichtblick/suite-base/hooks/useGlobalVariables"
import { VerticalBars } from "@lichtblick/suite-base/panels/Plot/VerticalBars";
import { defaultSidebarDimension } from "@lichtblick/suite-base/panels/Plot/constants";
import useHoverHandlers from "@lichtblick/suite-base/panels/Plot/hooks/useHoverHandlers";
import usePanning from "@lichtblick/suite-base/panels/Plot/hooks/usePanning";
import { PlotProps, TooltipStateSetter } from "@lichtblick/suite-base/panels/Plot/types";
import { PANEL_TITLE_CONFIG_KEY } from "@lichtblick/suite-base/util/layout";
import { getLineColor } from "@lichtblick/suite-base/util/plotColors";

import { OffscreenCanvasRenderer } from "./OffscreenCanvasRenderer";
import { useStyles } from "./Plot.style";
import { PlotCoordinator } from "./PlotCoordinator";
import { PlotLegend } from "./PlotLegend";
Expand All @@ -47,6 +46,7 @@ import { IndexDatasetsBuilder } from "./builders/IndexDatasetsBuilder";
import { TimestampDatasetsBuilder } from "./builders/TimestampDatasetsBuilder";
import { downloadCSV } from "./csv";
import useGlobalSync from "./hooks/useGlobalSync";
import { useRenderer } from "./hooks/useRenderer";
import useSubscriptions from "./hooks/useSubscriptions";
import { usePlotPanelSettings } from "./settings";

Expand Down Expand Up @@ -101,9 +101,9 @@ export function Plot(props: PlotProps): React.JSX.Element {
const [focusedPath, setFocusedPath] = useState<undefined | string[]>(undefined);
const [subscriberId] = useState(() => uuidv4());
const [canvasDiv, setCanvasDiv] = useState<HTMLDivElement | ReactNull>(ReactNull);
const [renderer, setRenderer] = useState<OffscreenCanvasRenderer | undefined>(undefined);
const [coordinator, setCoordinator] = useState<PlotCoordinator | undefined>(undefined);
const shouldSync = config.xAxisVal === "timestamp" && config.isSynced;
const renderer = useRenderer(canvasDiv, theme);

const { onMouseMove, onMouseOut, onResetView, onWheel, onClick } = useHoverHandlers(
coordinator,
Expand All @@ -118,6 +118,7 @@ export function Plot(props: PlotProps): React.JSX.Element {
usePlotPanelSettings(config, saveConfig, focusedPath);
useSubscriptions(config, subscriberId);
useGlobalSync(coordinator, setCanReset, { shouldSync }, subscriberId);
usePanning(canvasDiv, coordinator, draggingRef);

const onClickPath = useCallback((index: number) => {
setFocusedPath(["paths", String(index)]);
Expand Down Expand Up @@ -203,30 +204,6 @@ export function Plot(props: PlotProps): React.JSX.Element {
}
}, [datasetsBuilder, globalVariables, xAxisPath]);

useEffect(() => {
if (!canvasDiv) {
return;
}

const clientRect = canvasDiv.getBoundingClientRect();

const canvas = document.createElement("canvas");
canvas.style.width = "100%";
canvas.style.height = "100%";
// So the canvas does not affect the size of the parent
canvas.style.position = "absolute";
canvas.width = clientRect.width;
canvas.height = clientRect.height;
canvasDiv.appendChild(canvas);

const offscreenCanvas = canvas.transferControlToOffscreen();
setRenderer(new OffscreenCanvasRenderer(offscreenCanvas, theme));

return () => {
canvasDiv.removeChild(canvas);
};
}, [canvasDiv, theme]);

useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions
if (!renderer || !datasetsBuilder || !canvasDiv) {
Expand Down Expand Up @@ -289,65 +266,6 @@ export function Plot(props: PlotProps): React.JSX.Element {
) : undefined;
}, [activeTooltip, colorsByDatasetIndex, labelsByDatasetIndex, numSeries]);

// panning
useEffect(() => {
if (!canvasDiv || !coordinator) {
return;
}

const hammerManager = new Hammer.Manager(canvasDiv);
const threshold = 10;
hammerManager.add(new Hammer.Pan({ threshold }));

hammerManager.on("panstart", (event) => {
draggingRef.current = true;
const boundingRect = event.target.getBoundingClientRect();
coordinator.addInteractionEvent({
type: "panstart",
cancelable: false,
deltaY: event.deltaY,
deltaX: event.deltaX,
center: {
x: event.center.x,
y: event.center.y,
},
boundingClientRect: boundingRect.toJSON(),
});
});

hammerManager.on("panmove", (event) => {
const boundingRect = event.target.getBoundingClientRect();
coordinator.addInteractionEvent({
type: "panmove",
cancelable: false,
deltaY: event.deltaY,
deltaX: event.deltaX,
boundingClientRect: boundingRect.toJSON(),
});
});

hammerManager.on("panend", (event) => {
const boundingRect = event.target.getBoundingClientRect();
coordinator.addInteractionEvent({
type: "panend",
cancelable: false,
deltaY: event.deltaY,
deltaX: event.deltaX,
boundingClientRect: boundingRect.toJSON(),
});

// We need to do this a little bit later so that the onClick handler still sees
// draggingRef.current===true and can skip the seek.
setTimeout(() => {
draggingRef.current = false;
}, 0);
});

return () => {
hammerManager.destroy();
};
}, [canvasDiv, coordinator]);

const hoveredValuesBySeriesIndex = useMemo(() => {
if (!config.showPlotValuesInLegend) {
return;
Expand Down
73 changes: 73 additions & 0 deletions packages/suite-base/src/panels/Plot/hooks/usePanning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)<[email protected]>
// SPDX-License-Identifier: MPL-2.0

import Hammer from "hammerjs";
import { useEffect } from "react";

import { PlotCoordinator } from "@lichtblick/suite-base/panels/Plot/PlotCoordinator";

const usePanning = (
canvasDiv: HTMLDivElement | ReactNull,
coordinator: PlotCoordinator | undefined,
draggingRef: React.MutableRefObject<boolean>,
): void => {
useEffect(() => {
if (!canvasDiv || !coordinator) {
return;
}

const hammerManager = new Hammer.Manager(canvasDiv);
const threshold = 10;
hammerManager.add(new Hammer.Pan({ threshold }));

hammerManager.on("panstart", (event) => {
draggingRef.current = true;
const boundingRect = event.target.getBoundingClientRect();
coordinator.addInteractionEvent({
type: "panstart",
cancelable: false,
deltaY: event.deltaY,
deltaX: event.deltaX,
center: {
x: event.center.x,
y: event.center.y,
},
boundingClientRect: boundingRect.toJSON(),
});
});

hammerManager.on("panmove", (event) => {
const boundingRect = event.target.getBoundingClientRect();
coordinator.addInteractionEvent({
type: "panmove",
cancelable: false,
deltaY: event.deltaY,
deltaX: event.deltaX,
boundingClientRect: boundingRect.toJSON(),
});
});

hammerManager.on("panend", (event) => {
const boundingRect = event.target.getBoundingClientRect();
coordinator.addInteractionEvent({
type: "panend",
cancelable: false,
deltaY: event.deltaY,
deltaX: event.deltaX,
boundingClientRect: boundingRect.toJSON(),
});

// We need to do this a little bit later so that the onClick handler still sees
// draggingRef.current===true and can skip the seek.
setTimeout(() => {
draggingRef.current = false;
}, 0);
});

return () => {
hammerManager.destroy();
};
}, [canvasDiv, coordinator, draggingRef]);
};

export default usePanning;
2 changes: 1 addition & 1 deletion packages/suite-base/src/panels/Plot/hooks/useRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useEffect, useState } from "react";
import { OffscreenCanvasRenderer } from "../OffscreenCanvasRenderer";

export function useRenderer(
canvasDiv: HTMLDivElement | undefined,
canvasDiv: HTMLDivElement | ReactNull,
theme: Theme,
): OffscreenCanvasRenderer | undefined {
const [renderer, setRenderer] = useState<OffscreenCanvasRenderer | undefined>(undefined);
Expand Down

0 comments on commit 553fa0b

Please sign in to comment.