Skip to content

Commit

Permalink
Merge pull request #917 from vegaprotocol/chore/909-fluid-gaps-in-bar…
Browse files Browse the repository at this point in the history
…-graph

chore: make gaps between bars fluid according to amount of ms in the graph
  • Loading branch information
Maciek committed Oct 11, 2023
2 parents ac2a9e8 + 739c92c commit 242fc5e
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 65 deletions.
36 changes: 23 additions & 13 deletions src/feature/candlestick-chart/candlestick-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { parse } from "@util/scenegraph";
import {
Annotation,
Bounds,
Candle,
ChartElement,
ChartType,
Expand All @@ -37,8 +38,8 @@ import {
useState,
} from "react";

import { Colors, Dimensions, getColors, getDimensions } from "./helpers";
import { useOnReady } from "./hooks";
import { Colors, getColors } from "./helpers";
import { useGetDimensions, useOnReady } from "./hooks";

const noop = () => {};

Expand Down Expand Up @@ -132,6 +133,7 @@ export const CandlestickChart = forwardRef(
},
}));

const [width, setWidth] = useState(400);
const chartRef = useRef<ChartElement>(null!);
const styleRef = useRef<HTMLDivElement>(null!);
const listeners = useRef(dispatch("contextmenu"));
Expand All @@ -140,10 +142,7 @@ export const CandlestickChart = forwardRef(
const [internalInterval, setInternalInterval] = useState(interval);
const [colors, setColors] = useState<Colors>(getColors(null));

const [dimensions, setDimensions] = useState<Dimensions>(
getDimensions(null),
);

const dimensions = useGetDimensions(styleRef.current);
const [loading, setLoading] = useState(true);

// Callback for fetching historical data
Expand Down Expand Up @@ -185,24 +184,30 @@ export const CandlestickChart = forwardRef(
],
);

const candleWidth = getCandleWidth(internalInterval);
const [timeViewRange, setTimeViewRange] = useState(
initialNumCandles * candleWidth,
);
const pixelsToTime = timeViewRange / width;

// Compile data and view specification into scenegraph ready for rendering
const scenegraph = useMemo(
() =>
parse(
specification,
getCandleWidth(internalInterval),
dimensions.strokeWidth,
dimensions.innerPadding,
candleWidth,
dimensions,
pixelsToTime,
dataSource.decimalPlaces,
annotations,
),
[
annotations,
dataSource.decimalPlaces,
dimensions.strokeWidth,
dimensions.innerPadding,
internalInterval,
dimensions,
specification,
pixelsToTime,
candleWidth,
],
);

Expand Down Expand Up @@ -277,10 +282,14 @@ export const CandlestickChart = forwardRef(
// Hack to ensure we pick up the changed css
requestAnimationFrame(() => {
setColors(getColors(styleRef?.current));
setDimensions(getDimensions(styleRef?.current));
});
}, [theme]);

const handleBoundsChanged = useCallback((bounds: Bounds) => {
setTimeViewRange(bounds[1].getTime() - bounds[0].getTime());
setWidth(styleRef.current?.getBoundingClientRect().width ?? 0);
}, []);

const handleViewportChanged = useCallback(
(viewport: Viewport) => {
onViewportChanged(viewport);
Expand Down Expand Up @@ -369,6 +378,7 @@ export const CandlestickChart = forwardRef(
onRightClick={(event: any) => {
listeners.current.call("contextmenu", undefined, event);
}}
onBoundsChanged={handleBoundsChanged}
/>
</div>
</ErrorBoundary>
Expand Down
23 changes: 0 additions & 23 deletions src/feature/candlestick-chart/helpers/helpers-dimensions.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/feature/candlestick-chart/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./helpers-color";
export * from "./helpers-dimensions";
1 change: 1 addition & 0 deletions src/feature/candlestick-chart/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./useGetDimensions";
export * from "./useOnReady";
33 changes: 33 additions & 0 deletions src/feature/candlestick-chart/hooks/useGetDimensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { string2num } from "@util/misc";
import { useMemo } from "react";

export interface Dimensions {
strokeWidth: number;
innerPadding: number;
maxPaddingInPixels: number;
}

export function useGetDimensions(element: HTMLElement | null): Dimensions {
const cssStyleDeclaration = element ? getComputedStyle(element) : null;

const strokeWidth = string2num(
cssStyleDeclaration
?.getPropertyValue("--pennant-candlestick-stroke-width")
.trim() || "1px",
);
const innerPadding = string2num(
cssStyleDeclaration
?.getPropertyValue("--pennant-candlestick-inner-padding")
.trim() || "0.4",
);
const maxPaddingInPixels = string2num(
cssStyleDeclaration
?.getPropertyValue("--pennant-candlestick-max-padding-in-pixels")
.trim() || "2px",
);

return useMemo(
() => ({ strokeWidth, innerPadding, maxPaddingInPixels }),
[strokeWidth, innerPadding, maxPaddingInPixels],
);
}
9 changes: 8 additions & 1 deletion src/ui/components/plot-container/plot-container.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ export const Simple = Template.bind({});
Simple.args = {
interval: Interval.I5M,
overlays: [],
scenegraph: parse(specification, 100, 1, 0.4, 0, []) as Scenegraph,
scenegraph: parse(
specification,
100,
{ strokeWidth: 1, innerPadding: 0.4, maxPaddingInPixels: 2 },
100,
0,
[],
) as Scenegraph,
simple: false,
};
23 changes: 14 additions & 9 deletions src/ui/components/plot-container/plot-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export type PlotContainerProps = {
colors: Colors;
studySize: number | string;
studySizes: Array<number | string>;
onBoundsChanged?: (bounds: Bounds) => void;
onViewportChanged?: (viewport: Viewport) => void;
onRightClick?: (event: any) => void;
onGetDataRange?: (from: Date, to: Date, interval: Interval) => void;
Expand Down Expand Up @@ -72,6 +73,7 @@ export const PlotContainer = forwardRef<
studySize,
studySizes,
onViewportChanged = () => {},
onBoundsChanged = () => {},
onRightClick = () => {},
onGetDataRange = () => {},
onClosePane,
Expand All @@ -98,11 +100,6 @@ export const PlotContainer = forwardRef<
},
}));

const onViewportChangedThrottled = useMemo(
() => throttle(onViewportChanged, 200),
[onViewportChanged],
);

const onGetDataRangeThrottled = useMemo(
() => throttle(onGetDataRange, 800),
[onGetDataRange],
Expand All @@ -115,9 +112,17 @@ export const PlotContainer = forwardRef<
const xAxisRef = useRef<HTMLDivElement>(null!);
const allotmentRef = useRef<AllotmentHandle>(null!);

const handleBoundsChanged = useMemo(
() => throttle(setBounds, THROTTLE_INTERVAL),
[],
const handleBoundsChanged = useCallback(
(bounds: Bounds) => {
setBounds(bounds);
onBoundsChanged?.(bounds);
},
[onBoundsChanged],
);

const handleThrottledBoundsChanged = useMemo(
() => throttle(handleBoundsChanged, THROTTLE_INTERVAL),
[handleBoundsChanged],
);

const handleDataIndexChanged = useMemo(
Expand Down Expand Up @@ -178,7 +183,7 @@ export const PlotContainer = forwardRef<
chartRef.current?.requestRedraw();
})
.on("bounds_changed", (bounds: Bounds) => {
handleBoundsChanged(bounds);
handleThrottledBoundsChanged(bounds);
})
.on("viewport_changed", (viewport: Viewport) => {
handleViewportChanged(viewport);
Expand Down
1 change: 1 addition & 0 deletions src/ui/core/helpers/helpers-core-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export function measureXAxis(
for (const plotArea of Object.values(plotAreas)) {
plotArea.xScale(xr);
}
onBoundsChanged(xr.domain() as [Date, Date]);
}

export function drawXAxis(event: any, xAxis: XAxis) {
Expand Down
11 changes: 10 additions & 1 deletion src/util/misc/scenegraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { COLORS } from ".";

export const PADDING_INNER = 0.4;
export const MAX_PADDING = 2;

export function createElement(type: Mark, options: any): PositionalElement {
if (type === "area") {
Expand Down Expand Up @@ -69,18 +70,26 @@ export function getBarConfig(
stroke: string | null,
lineWidth: number | null,
innerPadding = PADDING_INNER,
maxPaddingInPixels = MAX_PADDING,
pixelsToTime = 1000,
) {
let base = 0;

if (y2) {
base = d[y2];
}

const strokesWidth = stroke && lineWidth ? lineWidth * 2 * pixelsToTime : 0;
const calculatedPadding = Math.min(
width * innerPadding,
maxPaddingInPixels * pixelsToTime + strokesWidth,
);

return {
x: d[x],
y: Math.max(d[y] as number, base),
height: Math.abs(base - (d[y] as number)),
width: width * (1 - innerPadding),
width: width - calculatedPadding,
fill: fill,
stroke: stroke,
lineWidth: lineWidth ?? 1,
Expand Down
27 changes: 24 additions & 3 deletions src/util/scenegraph/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ test("simple case", () => {
],
};

const scenegraph = parse(input, 10, 1, 0.4, 0, []);
const scenegraph = parse(
input,
10,
{ strokeWidth: 1, innerPadding: 0.4, maxPaddingInPixels: 2 },
100,
0,
[],
);

expect(scenegraph).toHaveProperty("panes");
expect(scenegraph?.panes).toHaveLength(1);
Expand Down Expand Up @@ -112,7 +119,14 @@ test("candlestick chart with study", () => {
],
};

const scenegraph = parse(input, 10, 1, 0.4, 0, []);
const scenegraph = parse(
input,
10,
{ strokeWidth: 1, innerPadding: 0.4, maxPaddingInPixels: 2 },
100,
0,
[],
);

expect(scenegraph).toHaveProperty("panes");
expect(scenegraph?.panes).toHaveLength(2);
Expand Down Expand Up @@ -198,7 +212,14 @@ test("recursively parse a layer", () => {
],
};

const layer = parseLayer(input, { values: [] }, {}, 10, 1, 0.4);
const layer = parseLayer(
input,
{ values: [] },
{},
10,
{ strokeWidth: 1, innerPadding: 0.4, maxPaddingInPixels: 2 },
100,
);

expect(layer).toHaveLength(4);
});
Loading

0 comments on commit 242fc5e

Please sign in to comment.