Skip to content

Commit

Permalink
fix(core): correcting xextents props
Browse files Browse the repository at this point in the history
xExtents can be provided via array, func, or array of funcs.
  • Loading branch information
markmcdowell committed Sep 1, 2020
1 parent 98c06ea commit ec80146
Show file tree
Hide file tree
Showing 35 changed files with 182 additions and 143 deletions.
27 changes: 16 additions & 11 deletions packages/core/src/Chart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { scaleLinear, ScaleContinuousNumeric } from "d3-scale";
import * as PropTypes from "prop-types";
import * as React from "react";

import { PureComponent } from "./utils";

export interface ChartProps {
Expand Down Expand Up @@ -87,21 +86,27 @@ export class Chart extends PureComponent<ChartProps> {

switch (type) {
case "contextmenu": {
if (onContextMenu !== undefined) {
const { currentCharts } = moreProps;
if (currentCharts.indexOf(id) > -1) {
onContextMenu(e, moreProps);
}
if (onContextMenu === undefined) {
return;
}

const { currentCharts } = moreProps;
if (currentCharts.indexOf(id) > -1) {
onContextMenu(e, moreProps);
}

break;
}
case "dblclick": {
if (onDoubleClick !== undefined) {
const { currentCharts } = moreProps;
if (currentCharts.indexOf(id) > -1) {
onDoubleClick(e, moreProps);
}
if (onDoubleClick === undefined) {
return;
}

const { currentCharts } = moreProps;
if (currentCharts.indexOf(id) > -1) {
onDoubleClick(e, moreProps);
}

break;
}
}
Expand Down
45 changes: 25 additions & 20 deletions packages/core/src/ChartCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ function getCursorStyle() {
return <style type="text/css">{tooltipStyle}</style>;
}

function getDimensions(props: ChartCanvasProps) {
function getDimensions<TXAxis extends number | Date>(props: ChartCanvasProps<TXAxis>) {
return {
height: props.height - props.margin.top - props.margin.bottom,
width: props.width - props.margin.left - props.margin.right,
};
}

function getXScaleDirection(flipXScale: any) {
function getXScaleDirection(flipXScale?: boolean) {
return flipXScale ? -1 : 1;
}

function calculateFullData(props: ChartCanvasProps) {
function calculateFullData<TXAxis extends number | Date>(props: ChartCanvasProps<TXAxis>) {
const { data: fullData, plotFull, xScale, clamp, pointsPerPxThreshold, flipXScale } = props;
const { xAccessor, displayXAccessor, minPointsPerPxThreshold } = props;

Expand All @@ -102,7 +102,7 @@ function calculateFullData(props: ChartCanvasProps) {
};
}

const resetChart = (props: ChartCanvasProps) => {
const resetChart = <TXAxis extends number | Date>(props: ChartCanvasProps<TXAxis>) => {
const state = calculateState(props);

const { xAccessor, displayXAccessor, fullData, plotData: initialPlotData, xScale } = state;
Expand Down Expand Up @@ -197,7 +197,7 @@ function updateChart(
};
}

function calculateState(props: ChartCanvasProps) {
function calculateState<TXAxis extends number | Date>(props: ChartCanvasProps<TXAxis>) {
const { xAccessor: inputXAccesor, xExtents: xExtentsProp, data, padding, flipXScale } = props;

const direction = getXScaleDirection(flipXScale);
Expand All @@ -207,7 +207,9 @@ function calculateState(props: ChartCanvasProps) {
const extent =
typeof xExtentsProp === "function"
? xExtentsProp(data)
: d3Extent(xExtentsProp.map((d: any) => functor(d)).map((each: any) => each(data, inputXAccesor)));
: (d3Extent<number | Date>(
xExtentsProp.map((d: any) => functor(d)).map((each: any) => each(data, inputXAccesor)),
) as [TXAxis, TXAxis]);

const { xAccessor, displayXAccessor, xScale, fullData, filterData } = calculateFullData(props);

Expand Down Expand Up @@ -262,7 +264,7 @@ function isInteractionEnabled(xScale: any, xAccessor: any, data: any) {
return interaction;
}

export interface ChartCanvasProps {
export interface ChartCanvasProps<TXAxis extends number | Date> {
readonly clamp?:
| boolean
| ("left" | "right" | "both")
Expand All @@ -274,7 +276,7 @@ export interface ChartCanvasProps {
readonly disableInteraction?: boolean;
readonly disablePan?: boolean;
readonly disableZoom?: boolean;
readonly displayXAccessor?: (data: any) => number | Date;
readonly displayXAccessor?: (data: any) => TXAxis;
readonly flipXScale?: boolean;
readonly height: number;
readonly margin: {
Expand All @@ -289,11 +291,11 @@ export interface ChartCanvasProps {
/**
* Called when panning left past the first data point.
*/
readonly onLoadAfter?: (start: number | Date, end: number | Date) => void;
readonly onLoadAfter?: (start: TXAxis, end: TXAxis) => void;
/**
* Called when panning right past the last data point.
*/
readonly onLoadBefore?: (start: number | Date, end: number | Date) => void;
readonly onLoadBefore?: (start: TXAxis, end: TXAxis) => void;
/**
* Click event handler.
*/
Expand All @@ -317,24 +319,27 @@ export interface ChartCanvasProps {
readonly seriesName: string;
readonly useCrossHairStyleCursor?: boolean;
readonly width: number;
readonly xAccessor: (data: any) => number | Date;
readonly xExtents?: any[] | any; // func
readonly xAccessor: (data: any) => TXAxis;
readonly xExtents: ((data: any[]) => [TXAxis, TXAxis]) | (((datum: any) => TXAxis) | TXAxis)[];
readonly xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
readonly zIndex?: number;
readonly zoomAnchor?: (options: IZoomAnchorOptions<any>) => number | Date;
readonly zoomAnchor?: (options: IZoomAnchorOptions<any>) => TXAxis;
readonly zoomMultiplier?: number;
}

interface ChartCanvasState {
xAccessor?: (data: any) => number | Date;
interface ChartCanvasState<TXAxis extends number | Date> {
xAccessor?: (data: any) => TXAxis;
displayXAccessor?: any;
filterData?: any;
chartConfig?: any;
plotData?: any;
plotData: any[];
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
}

export class ChartCanvas extends React.Component<ChartCanvasProps, ChartCanvasState> {
export class ChartCanvas<TXAxis extends number | Date> extends React.Component<
ChartCanvasProps<TXAxis>,
ChartCanvasState<TXAxis>
> {
public static defaultProps = {
clamp: false,
className: "react-financial-charts",
Expand All @@ -351,7 +356,7 @@ export class ChartCanvas extends React.Component<ChartCanvasProps, ChartCanvasSt
padding: 0,
pointsPerPxThreshold: 2,
useCrossHairStyleCursor: true,
xAccessor: identity as (data: any) => number,
xAccessor: identity as (data: any) => any,
xExtents: [min, max] as any[],
zIndex: 1,
zoomAnchor: mouseBasedZoomAnchor,
Expand Down Expand Up @@ -420,7 +425,7 @@ export class ChartCanvas extends React.Component<ChartCanvasProps, ChartCanvasSt
// tslint:disable-next-line: variable-name
private hackyWayToStopPanBeyondBounds__domain?: any[] | null;

public constructor(props: ChartCanvasProps) {
public constructor(props: ChartCanvasProps<TXAxis>) {
super(props);

const { fullData, ...state } = resetChart(props);
Expand Down Expand Up @@ -1125,7 +1130,7 @@ export class ChartCanvas extends React.Component<ChartCanvasProps, ChartCanvasSt
};
}

public UNSAFE_componentWillReceiveProps(nextProps: ChartCanvasProps) {
public UNSAFE_componentWillReceiveProps(nextProps: ChartCanvasProps<TXAxis>) {
const reset = shouldResetChart(this.props, nextProps);

const interaction = isInteractionEnabled(this.state.xScale, this.state.xAccessor, this.state.plotData);
Expand Down
30 changes: 15 additions & 15 deletions packages/core/src/EventCapture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,24 @@ interface EventCaptureProps {
readonly onMouseLeave?: (event: React.MouseEvent) => void;
readonly onPinchZoom?: (
initialPinch: {
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
touch1Pos: [number, number];
touch2Pos: [number, number];
range: number[];
readonly xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
readonly touch1Pos: [number, number];
readonly touch2Pos: [number, number];
readonly range: number[];
},
currentPinch: {
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
touch1Pos: [number, number];
touch2Pos: [number, number];
readonly xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
readonly touch1Pos: [number, number];
readonly touch2Pos: [number, number];
},
e: React.TouchEvent,
) => void;
readonly onPinchZoomEnd?: (
initialPinch: {
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
touch1Pos: [number, number];
touch2Pos: [number, number];
range: number[];
readonly xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
readonly touch1Pos: [number, number];
readonly touch2Pos: [number, number];
readonly range: number[];
},
e: React.TouchEvent,
) => void;
Expand Down Expand Up @@ -199,7 +199,7 @@ export class EventCapture extends React.Component<EventCaptureProps, EventCaptur
};

public handleWheel = (e: React.WheelEvent) => {
const { zoom, onZoom } = this.props;
const { onPan, zoom, onZoom } = this.props;
const { panInProgress } = this.state;

const yZoom = Math.abs(e.deltaY) > Math.abs(e.deltaX) && Math.abs(e.deltaY) > 0;
Expand Down Expand Up @@ -230,8 +230,8 @@ export class EventCapture extends React.Component<EventCaptureProps, EventCaptur
this.dy += e.deltaY;
const dxdy = { dx: this.dx, dy: this.dy };

if (this.props.onPan !== undefined) {
this.props.onPan(mouseXY, panStartXScale, dxdy, chartsToPan, e);
if (onPan !== undefined) {
onPan(mouseXY, panStartXScale, dxdy, chartsToPan, e);
}
} else {
const { xScale, chartConfig } = this.props;
Expand Down Expand Up @@ -623,7 +623,7 @@ export class EventCapture extends React.Component<EventCaptureProps, EventCaptur

const { chartsToPan, ...initialPinch } = pinchZoomStart;

if (zoomEnabled && onPinchZoom) {
if (zoomEnabled && onPinchZoom !== undefined) {
onPinchZoom(
initialPinch,
{
Expand Down
34 changes: 28 additions & 6 deletions packages/scales/src/discontinuousTimeScaleProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { identity, slidingWindow, zipper } from "@react-financial-charts/core";
import { slidingWindow, zipper } from "@react-financial-charts/core";
import { timeFormat, timeFormatDefaultLocale } from "d3-time-format";
import financeDiscontinuousScale from "./financeDiscontinuousScale";
import { defaultFormatters, levelDefinition, IFormatters } from "./levels";
Expand Down Expand Up @@ -116,7 +116,7 @@ const discontinuousIndexCalculatorLocalTime = discontinuousIndexCalculator.accum
},
);

function doStuff(realDateAccessor: any, inputDateAccessor: any, initialIndex: number, formatters: IFormatters) {
function createIndex(realDateAccessor: any, inputDateAccessor: any, initialIndex: number, formatters: IFormatters) {
return function (data: any[]) {
const dateAccessor = realDateAccessor(inputDateAccessor);

Expand All @@ -136,9 +136,31 @@ function doStuff(realDateAccessor: any, inputDateAccessor: any, initialIndex: nu
};
}

export interface DiscontinuousTimeScaleProviderBuilder {
(data: any[]): {
data: any[];
xScale: any;
xAccessor: (data: any) => number;
displayXAccessor: (data: any) => number;
};
initialIndex(): any;
initialIndex(x: any): DiscontinuousTimeScaleProviderBuilder;
inputDateAccessor(): any;
inputDateAccessor(accessor: (data: any) => Date): DiscontinuousTimeScaleProviderBuilder;
indexAccessor(): any;
indexAccessor(x: any): DiscontinuousTimeScaleProviderBuilder;
indexMutator(): any;
indexMutator(x: any): DiscontinuousTimeScaleProviderBuilder;
withIndex(): any;
withIndex(x: any): DiscontinuousTimeScaleProviderBuilder;
utc(): DiscontinuousTimeScaleProviderBuilder;
setLocale(locale?: any, formatters?: IFormatters): DiscontinuousTimeScaleProviderBuilder;
indexCalculator(): any;
}

export function discontinuousTimeScaleProviderBuilder() {
let initialIndex = 0;
let realDateAccessor = identity as (x: any) => any;
let realDateAccessor = (d: any) => d;
let inputDateAccessor = (d: any) => d.date;
let indexAccessor = (d: any) => d.idx;
let indexMutator = (d: any, idx: any) => ({ ...d, idx });
Expand All @@ -150,7 +172,7 @@ export function discontinuousTimeScaleProviderBuilder() {
let index = withIndex;

if (index === undefined) {
const response = doStuff(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters)(data);
const response = createIndex(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters)(data);

index = response.index;
}
Expand Down Expand Up @@ -228,10 +250,10 @@ export function discontinuousTimeScaleProviderBuilder() {
};

discontinuousTimeScaleProvider.indexCalculator = function () {
return doStuff(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters);
return createIndex(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters);
};

return discontinuousTimeScaleProvider;
return discontinuousTimeScaleProvider as DiscontinuousTimeScaleProviderBuilder;
}

export default discontinuousTimeScaleProviderBuilder();
4 changes: 2 additions & 2 deletions packages/scales/src/financeDiscontinuousScale.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { head, isDefined, last } from "@react-financial-charts/core";
import { head, last } from "@react-financial-charts/core";
import { ascending } from "d3-array";
import { scaleLinear, InterpolatorFactory } from "d3-scale";
import { levelDefinition } from "./levels";
Expand Down Expand Up @@ -126,7 +126,7 @@ export default function financeDiscontinuousScale(index: any[], backingLinearSca
scale.value = (x: any) => {
const d = Math.abs(head(index).index);
const row = index[Math.floor(x + d)];
if (isDefined(row)) {
if (row !== undefined) {
const { date } = row;
return date;
}
Expand Down
11 changes: 9 additions & 2 deletions packages/scales/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ export {
export { default as financeDiscontinuousScale } from "./financeDiscontinuousScale";
export * from "./timeFormat";

export const defaultScaleProvider = (xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>) => {
return (data: any[], xAccessor: any) => ({ data, xScale, xAccessor, displayXAccessor: xAccessor });
export const defaultScaleProvider = <TData, TXAxis extends number | Date>(
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
) => {
return (data: TData[], xAccessor: (data: TData) => TXAxis) => ({
data,
xScale,
xAccessor,
displayXAccessor: xAccessor,
});
};
6 changes: 3 additions & 3 deletions packages/stories/src/features/StockChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class StockChart extends React.Component<StockChartProps> {

const { data, xScale, xAccessor, displayXAccessor } = xScaleProvider(calculatedData);

const start = xAccessor(data[data.length - 1]);
const end = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [start, end];
const max = xAccessor(data[data.length - 1]);
const min = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [min, max + 5];

const gridHeight = height - margin.top - margin.bottom;

Expand Down
6 changes: 3 additions & 3 deletions packages/stories/src/features/annotations/Annotations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ class Annotations extends React.Component<ChartProps> {

const { data, xScale, xAccessor, displayXAccessor } = this.xScaleProvider(calculatedData);

const start = xAccessor(data[data.length - 1]);
const end = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [start, end];
const max = xAccessor(data[data.length - 1]);
const min = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [min, max];

return (
<ChartCanvas
Expand Down
6 changes: 3 additions & 3 deletions packages/stories/src/features/axis/Axis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ class AxisExample extends React.Component<ChartProps> {

const { data, xScale, xAccessor, displayXAccessor } = this.xScaleProvider(initialData);

const start = xAccessor(data[data.length - 1]);
const end = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [start, end];
const max = xAccessor(data[data.length - 1]);
const min = xAccessor(data[Math.max(0, data.length - 100)]);
const xExtents = [min, max];

return (
<ChartCanvas
Expand Down
Loading

0 comments on commit ec80146

Please sign in to comment.