Skip to content

Commit

Permalink
feat(react-component): adding context menu per chart
Browse files Browse the repository at this point in the history
  • Loading branch information
mnischay committed Aug 4, 2023
1 parent b66de3b commit a368eb9
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 53 deletions.
17 changes: 9 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"@iot-app-kit/core-util": "7.1.0",
"@iot-app-kit/source-iottwinmaker": "7.1.0",
"color": "^4.2.3",
"copy-to-clipboard": "^3.3.3",
"d3-array": "^3.2.3",
"d3-format": "^3.1.0",
"d3-shape": "^3.2.0",
Expand Down
30 changes: 27 additions & 3 deletions packages/react-components/src/components/chart/baseChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useECharts } from '../../hooks/useECharts';
import { ChartOptions } from './types';
import { useVisualizedDataStreams } from './hooks/useVisualizedDataStreams';
import { convertOptions } from './converters/convertOptions';
import { SeriesOption, YAXisComponentOption } from 'echarts';
import { ElementEvent, SeriesOption, YAXisComponentOption } from 'echarts';
import { convertYAxis } from './converters/convertAxis';
import { convertSeriesAndYAxis, reduceSeriesAndYAxis } from './converters/convertSeriesAndYAxis';
import { HotKeys, KeyMap } from 'react-hotkeys';
Expand All @@ -14,6 +14,7 @@ import Legend from './legend/legend';
import { CHART_RESIZE_INITIAL_FACTOR, CHART_RESIZE_MAX_FACTOR, CHART_RESIZE_MIN_FACTOR } from './eChartsConstants';
import { v4 as uuid } from 'uuid';
import './chart.css';
import ChartContextMenu, { Action } from './contextMenu/ChartContextMenu';

const keyMap: KeyMap = {
commandDown: { sequence: 'command', action: 'keydown' },
Expand Down Expand Up @@ -42,6 +43,8 @@ const Chart = ({ viewport, queries, size = { width: 500, height: 500 }, ...optio

const [trendCursors, setTrendCursors] = useState(options.graphic ?? []);
const [isInCursorAddMode, setIsInCursorAddMode] = useState(false);
const [showContextMenu, setShowContextMenu] = useState(false);
const [contextMenuPos, setContextMenuPos] = useState({ x: 0, y: 0 });

const option = {
...convertOptions({
Expand Down Expand Up @@ -69,8 +72,14 @@ const Chart = ({ viewport, queries, size = { width: 500, height: 500 }, ...optio
groupId: options?.groupId,
});

const handleContextMenu = (e: ElementEvent) => {
setContextMenuPos({ x: e.offsetX, y: e.offsetY });
setShowContextMenu(!showContextMenu);
e.stop();
};

// this will handle all the Trend Cursors operations
useTrendCursors({
const { onContextMenuClickHandler } = useTrendCursors({
ref,
graphic: trendCursors,
size: { width, height: size.height },
Expand All @@ -82,13 +91,19 @@ const Chart = ({ viewport, queries, size = { width: 500, height: 500 }, ...optio
chartId,
viewport,
groupId: options.groupId,
onContextMenu: handleContextMenu,
});

const handlers = {
commandDown: () => setIsInCursorAddMode(true),
commandUp: () => setIsInCursorAddMode(false),
};

const menuOptionClickHandler = ({ action }: { action: Action; e: React.MouseEvent }) => {
onContextMenuClickHandler({ action, posX: contextMenuPos.x });
setShowContextMenu(false);
};

return (
<div className='base-chart-container'>
<Resizable
Expand All @@ -99,8 +114,17 @@ const Chart = ({ viewport, queries, size = { width: 500, height: 500 }, ...optio
minConstraints={[size.width * CHART_RESIZE_MIN_FACTOR, size.height]}
maxConstraints={[size.width * CHART_RESIZE_MAX_FACTOR, size.height]}
>
<HotKeys keyMap={keyMap} handlers={handlers}>
<HotKeys keyMap={keyMap} handlers={handlers} style={{ position: 'relative' }}>
<div ref={ref} className='base-chart-element' style={{ height: size.height, width: width }} />
{/*TODO: should not show when in dashboard */}
{showContextMenu && (
<ChartContextMenu
position={{ x: contextMenuPos.x, y: contextMenuPos.y }}
onOutSideClickHandler={() => setShowContextMenu(false)}
menuOptionClickHandler={menuOptionClickHandler}
trendCursors={trendCursors}
/>
)}
</HotKeys>
</Resizable>
<div style={{ height: size.height, width: size.width - width }}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { describe, expect } from '@jest/globals';
import { render } from '@testing-library/react';
import React from 'react';
import ChartContextMenu from './ChartContextMenu';

describe('ChartContextMenu', () => {
const menuOptionClickHandler = jest.fn();
const onOutSideClickHandler = jest.fn();
const component = render(
<ChartContextMenu
menuOptionClickHandler={menuOptionClickHandler}
onOutSideClickHandler={onOutSideClickHandler}
position={{ x: 100, y: 100 }}
trendCursors={[]}
/>
);
it('renders', () => {
expect(component).not.toBeNull();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { Menu, MenuOption } from '../../menu';
import { InternalGraphicComponentGroupOption } from '../types';
import { MAX_TREND_CURSORS } from '../eChartsConstants';

export type Action = 'add' | 'delete' | 'copy';
interface ChartContextMenu {
position: { x: number; y: number };
menuOptionClickHandler: ({ action, e }: { action: Action; e: React.MouseEvent }) => void;
onOutSideClickHandler: (e: PointerEvent) => void;
trendCursors: InternalGraphicComponentGroupOption[];
}
const ChartContextMenu = ({
position,
menuOptionClickHandler,
onOutSideClickHandler,
trendCursors,
}: ChartContextMenu) => {
return (
<Menu
styles={{ position: 'absolute', top: `${position.y}px`, left: `${position.x}px` }}
onClickOutside={onOutSideClickHandler}
>
<MenuOption
label='Add trend cursor'
onClick={(e) => menuOptionClickHandler({ action: 'add', e })}
disabled={trendCursors.length >= MAX_TREND_CURSORS}
/>
<MenuOption
label='Copy to clipboard'
onClick={(e) => menuOptionClickHandler({ action: 'copy', e })}
disabled={trendCursors.length === 0}
/>
<MenuOption
label='Delete trend cursor'
onClick={(e) => menuOptionClickHandler({ action: 'delete', e })}
disabled={trendCursors.length === 0}
/>
</Menu>
);
};

export default ChartContextMenu;
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ const useTrendCursors = ({
chartId,
viewport,
groupId,
onContextMenu,
}: UseTrendCursorsProps) => {
// for debugging purposes
console.log(`useTrendCursors for chart id : ${chartId}`);

const isInSyncMode = useDataStore((state) => (groupId ? !!state.trendCursorGroups[groupId] : false));

// hook for handling all user events
useTrendCursorsEvents({
const { onContextMenuClickHandler } = useTrendCursorsEvents({
ref,
graphic,
size,
Expand All @@ -35,13 +36,16 @@ const useTrendCursors = ({
yMax,
isInSyncMode,
groupId,
onContextMenu,
});

// for handling the resize of chart
handleResize({ series, size, yMin, yMax, graphic, setGraphic, viewport });

// handling the trend cursor sync mode
handleSync({ ref, isInSyncMode, graphic, setGraphic, viewport, series, yMin, yMax, size, groupId });

return { onContextMenuClickHandler };
};

export default useTrendCursors;

0 comments on commit a368eb9

Please sign in to comment.