Skip to content

Commit

Permalink
fix(series): correcting props & dealing with undefined data
Browse files Browse the repository at this point in the history
Removing classnames.
Renamed interpolation to curve.
Added docs.
Allowing y undefined in SarSeries, ScatterSeries.
  • Loading branch information
markmcdowell committed Aug 29, 2020
1 parent 2205163 commit 99664ba
Show file tree
Hide file tree
Showing 17 changed files with 262 additions and 168 deletions.
8 changes: 4 additions & 4 deletions packages/series/src/AlternatingFillAreaSeries.tsx
Expand Up @@ -18,7 +18,7 @@ export interface AlternatingFillAreaSeriesProps {
/**
* A factory for a curve generator for the area and line.
*/
readonly interpolation?: CurveFactory;
readonly curve?: CurveFactory;
/**
* Color, gradient, or pattern to use for the stroke.
*/
Expand Down Expand Up @@ -77,7 +77,7 @@ export class AlternatingFillAreaSeries extends React.Component<AlternatingFillAr
const {
className,
yAccessor,
interpolation,
curve,
strokeStyle = AlternatingFillAreaSeries.defaultProps.strokeStyle,
strokeWidth = AlternatingFillAreaSeries.defaultProps.strokeWidth,
strokeDasharray = AlternatingFillAreaSeries.defaultProps.strokeDasharray,
Expand All @@ -90,7 +90,7 @@ export class AlternatingFillAreaSeries extends React.Component<AlternatingFillAr
<AreaSeries
canvasClip={this.topClip}
yAccessor={yAccessor}
interpolation={interpolation}
curve={curve}
baseAt={this.baseAt}
fillStyle={fillStyle.top}
strokeStyle={strokeStyle.top}
Expand All @@ -100,7 +100,7 @@ export class AlternatingFillAreaSeries extends React.Component<AlternatingFillAr
<AreaSeries
canvasClip={this.bottomClip}
yAccessor={yAccessor}
interpolation={interpolation}
curve={curve}
baseAt={this.baseAt}
fillStyle={fillStyle.bottom}
strokeStyle={strokeStyle.bottom}
Expand Down
17 changes: 10 additions & 7 deletions packages/series/src/AreaOnlySeries.tsx
@@ -1,9 +1,12 @@
import { first, functor, getAxisCanvas, GenericChartComponent } from "@react-financial-charts/core";
import { ScaleContinuousNumeric } from "d3-scale";
import { area as d3Area, CurveFactory } from "d3-shape";
import { area, CurveFactory } from "d3-shape";
import * as React from "react";

export interface AreaOnlySeriesProps {
/**
* The base y value to draw the area to.
*/
readonly base?:
| number
| ((yScale: ScaleContinuousNumeric<number, number>, d: [number, number], moreProps: any) => number | undefined);
Expand All @@ -19,7 +22,7 @@ export interface AreaOnlySeriesProps {
/**
* A factory for a curve generator for the area.
*/
readonly interpolation?: CurveFactory;
readonly curve?: CurveFactory;
/**
* Selector for data to plot.
*/
Expand All @@ -39,7 +42,7 @@ export class AreaOnlySeries extends React.Component<AreaOnlySeriesProps> {
private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
const {
fillStyle,
interpolation,
curve,
canvasClip,
yAccessor,
defined = AreaOnlySeries.defaultProps.defined,
Expand All @@ -64,22 +67,22 @@ export class AreaOnlySeries extends React.Component<AreaOnlySeriesProps> {

ctx.beginPath();
const newBase = functor(base);
const areaSeries = d3Area()
const areaSeries = area()
.defined((d) => defined(yAccessor(d)))
.x((d) => Math.round(xScale(xAccessor(d))))
.y0((d) => newBase(yScale, d, moreProps))
.y1((d) => Math.round(yScale(yAccessor(d))))
.context(ctx);

if (interpolation !== undefined) {
areaSeries.curve(interpolation);
if (curve !== undefined) {
areaSeries.curve(curve);
}

areaSeries(plotData);

ctx.fill();

if (canvasClip) {
if (canvasClip !== undefined) {
ctx.restore();
}
};
Expand Down
11 changes: 7 additions & 4 deletions packages/series/src/AreaSeries.tsx
Expand Up @@ -6,6 +6,9 @@ import { AreaOnlySeries } from "./AreaOnlySeries";
import { LineSeries } from "./LineSeries";

export interface AreaSeriesProps {
/**
* The base y value to draw the area to.
*/
readonly baseAt?:
| number
| ((yScale: ScaleContinuousNumeric<number, number>, d: [number, number], moreProps: any) => number);
Expand All @@ -18,7 +21,7 @@ export interface AreaSeriesProps {
/**
* A factory for a curve generator for the area and line.
*/
readonly interpolation?: CurveFactory;
readonly curve?: CurveFactory;
/**
* Color, gradient, or pattern to use for the stroke.
*/
Expand Down Expand Up @@ -57,7 +60,7 @@ export class AreaSeries extends Component<AreaSeriesProps> {
strokeWidth,
strokeDasharray,
fillStyle,
interpolation,
curve,
canvasClip,
yAccessor,
} = this.props;
Expand All @@ -66,7 +69,7 @@ export class AreaSeries extends Component<AreaSeriesProps> {
<g className={className}>
<AreaOnlySeries
yAccessor={yAccessor}
interpolation={interpolation}
curve={curve}
base={baseAt}
fillStyle={fillStyle}
canvasClip={canvasClip}
Expand All @@ -76,7 +79,7 @@ export class AreaSeries extends Component<AreaSeriesProps> {
strokeStyle={strokeStyle}
strokeWidth={strokeWidth}
strokeDasharray={strokeDasharray}
interpolation={interpolation}
curve={curve}
canvasClip={canvasClip}
highlightOnHover={false}
/>
Expand Down
33 changes: 25 additions & 8 deletions packages/series/src/BarSeries.tsx
Expand Up @@ -6,15 +6,23 @@ import {
plotDataLengthBarWidth,
} from "@react-financial-charts/core";
import { group } from "d3-array";
import { ScaleContinuousNumeric } from "d3-scale";
import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
import * as React from "react";
import { drawOnCanvasHelper, identityStack } from "./StackedBarSeries";

interface IBar {
readonly x: number;
readonly y: number;
readonly height: number;
readonly width: number;
readonly fillStyle: string;
}

export interface BarSeriesProps {
readonly baseAt?:
| number
| ((
xScale: ScaleContinuousNumeric<number, number>,
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
yScale: ScaleContinuousNumeric<number, number>,
d: [number, number],
moreProps: any,
Expand Down Expand Up @@ -91,7 +99,12 @@ export class BarSeries extends React.Component<BarSeriesProps> {
}
};

private readonly getBars = (moreProps: any) => {
private readonly getBars = (moreProps: {
chartConfig: any;
xAccessor: (data: any) => number | Date;
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
plotData: any[];
}) => {
const { baseAt, fillStyle, width, yAccessor } = this.props;

const {
Expand All @@ -114,14 +127,17 @@ export class BarSeries extends React.Component<BarSeriesProps> {
const offset = Math.floor(0.5 * barWidth);

return plotData
.filter((d: any) => yAccessor(d) !== undefined)
.map((d: any) => {
const xValue = xAccessor(d);
.map((d) => {
const yValue = yAccessor(d);
let y = yScale(yValue);
if (yValue === undefined) {
return undefined;
}

const xValue = xAccessor(d);
const x = Math.round(xScale(xValue)) - offset;

let y = yScale(yValue);

let h = getBase(xScale, yScale, d) - yScale(yValue);
if (h < 0) {
y = y + h;
Expand All @@ -135,6 +151,7 @@ export class BarSeries extends React.Component<BarSeriesProps> {
width: offset * 2,
fillStyle: getFill(d),
};
});
})
.filter((d) => d !== undefined) as IBar[];
};
}
38 changes: 13 additions & 25 deletions packages/series/src/CandlestickSeries.tsx
@@ -1,13 +1,12 @@
import { functor, getAxisCanvas, GenericChartComponent, plotDataLengthBarWidth } from "@react-financial-charts/core";
import { group } from "d3-array";
import { ScaleContinuousNumeric } from "d3-scale";
import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
import * as React from "react";

export interface ICandle {
readonly x: number;
readonly y: number;
readonly height: number;
readonly className?: string;
readonly fill: string;
readonly stroke: string;
readonly direction: number;
Expand All @@ -23,30 +22,22 @@ export interface ICandle {
}

export interface CandlestickSeriesProps {
readonly candleClassName?: string;
readonly candleStrokeWidth?: number;
readonly className?: string;
readonly classNames?: string | (() => string);
readonly clip?: boolean;
readonly fill?: string | ((data: any) => string);
readonly stroke?: string | ((data: any) => string);
readonly wickClassName?: string;
readonly wickStroke?: string | ((data: any) => string);
readonly width?: number | ((props: CandlestickSeriesProps, moreProps: any) => number);
readonly widthRatio?: number;
readonly yAccessor?: (data: any) => { open: number; high: number; low: number; close: number };
readonly yAccessor: (data: any) => { open: number; high: number; low: number; close: number } | undefined;
}

export class CandlestickSeries extends React.Component<CandlestickSeriesProps> {
public static defaultProps = {
candleClassName: "react-financial-charts-candlestick-candle",
candleStrokeWidth: 0.5,
className: "react-financial-charts-candlestick",
classNames: (d: any) => (d.close > d.open ? "up" : "down"),
clip: true,
fill: (d: any) => (d.close > d.open ? "#26a69a" : "#ef5350"),
stroke: (d: any) => (d.close > d.open ? "#26a69a" : "#ef5350"),
wickClassName: "react-financial-charts-candlestick-wick",
wickStroke: (d: any) => (d.close > d.open ? "#26a69a" : "#ef5350"),
width: plotDataLengthBarWidth,
widthRatio: 0.8,
Expand Down Expand Up @@ -125,23 +116,16 @@ export class CandlestickSeries extends React.Component<CandlestickSeriesProps> {
};

private readonly getCandleData = (
xAccessor: (data: any) => number,
xScale: ScaleContinuousNumeric<number, number>,
xAccessor: (data: any) => number | Date,
xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
yScale: ScaleContinuousNumeric<number, number>,
plotData: any[],
): ICandle[] => {
const {
classNames,
fill: fillProp,
stroke: strokeProp,
yAccessor = CandlestickSeries.defaultProps.yAccessor,
wickStroke: wickStrokeProp,
} = this.props;
) => {
const { fill: fillProp, stroke: strokeProp, yAccessor, wickStroke: wickStrokeProp } = this.props;

const wickStroke = functor(wickStrokeProp);
const className = functor(classNames);
const fill = functor(fillProp);
const stroke = functor(strokeProp);
const wickStroke = functor(wickStrokeProp);
const widthFunctor = functor(this.props.width);
const width = widthFunctor(this.props, {
xScale,
Expand All @@ -156,6 +140,10 @@ export class CandlestickSeries extends React.Component<CandlestickSeriesProps> {
.filter((d) => d.close !== undefined)
.map((d) => {
const ohlc = yAccessor(d);
if (ohlc === undefined) {
return undefined;
}

const x = Math.round(xScale(xAccessor(d)));
const y = Math.round(yScale(Math.max(ohlc.open, ohlc.close)));
const height = Math.max(1, Math.round(Math.abs(yScale(ohlc.open) - yScale(ohlc.close))));
Expand All @@ -173,11 +161,11 @@ export class CandlestickSeries extends React.Component<CandlestickSeriesProps> {
},
height,
width: offset * 2,
className: className(ohlc),
fill: fill(ohlc),
stroke: stroke(ohlc),
direction: ohlc.close - ohlc.open,
};
});
})
.filter((d) => d !== undefined) as ICandle[];
};
}

0 comments on commit 99664ba

Please sign in to comment.