From 99664ba609692aab7b56edb81c0fec31a4922422 Mon Sep 17 00:00:00 2001 From: Mark McDowell Date: Sat, 29 Aug 2020 10:25:50 +0100 Subject: [PATCH] fix(series): correcting props & dealing with undefined data Removing classnames. Renamed interpolation to curve. Added docs. Allowing y undefined in SarSeries, ScatterSeries. --- .../series/src/AlternatingFillAreaSeries.tsx | 8 +- packages/series/src/AreaOnlySeries.tsx | 17 +-- packages/series/src/AreaSeries.tsx | 11 +- packages/series/src/BarSeries.tsx | 33 ++++-- packages/series/src/CandlestickSeries.tsx | 38 +++---- packages/series/src/KagiSeries.tsx | 103 ++++++++++-------- packages/series/src/LineSeries.tsx | 44 ++++++-- packages/series/src/MACDSeries.tsx | 4 +- packages/series/src/SARSeries.tsx | 29 +++-- packages/series/src/ScatterSeries.tsx | 67 ++++++++---- packages/series/src/StraightLine.tsx | 4 +- packages/series/src/VolumeProfileSeries.tsx | 55 +++++----- packages/series/src/index.ts | 6 +- .../series/src/{ => markers}/CircleMarker.tsx | 8 +- .../series/src/{ => markers}/SquareMarker.tsx | 0 .../src/{ => markers}/TriangleMarker.tsx | 0 packages/series/src/markers/index.ts | 3 + 17 files changed, 262 insertions(+), 168 deletions(-) rename packages/series/src/{ => markers}/CircleMarker.tsx (91%) rename packages/series/src/{ => markers}/SquareMarker.tsx (100%) rename packages/series/src/{ => markers}/TriangleMarker.tsx (100%) create mode 100644 packages/series/src/markers/index.ts diff --git a/packages/series/src/AlternatingFillAreaSeries.tsx b/packages/series/src/AlternatingFillAreaSeries.tsx index d409d751..e44627eb 100644 --- a/packages/series/src/AlternatingFillAreaSeries.tsx +++ b/packages/series/src/AlternatingFillAreaSeries.tsx @@ -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. */ @@ -77,7 +77,7 @@ export class AlternatingFillAreaSeries extends React.Component, d: [number, number], moreProps: any) => number | undefined); @@ -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. */ @@ -39,7 +42,7 @@ export class AreaOnlySeries extends React.Component { private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => { const { fillStyle, - interpolation, + curve, canvasClip, yAccessor, defined = AreaOnlySeries.defaultProps.defined, @@ -64,22 +67,22 @@ export class AreaOnlySeries extends React.Component { 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(); } }; diff --git a/packages/series/src/AreaSeries.tsx b/packages/series/src/AreaSeries.tsx index 0fa3c042..d1b8d29f 100644 --- a/packages/series/src/AreaSeries.tsx +++ b/packages/series/src/AreaSeries.tsx @@ -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, d: [number, number], moreProps: any) => number); @@ -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. */ @@ -57,7 +60,7 @@ export class AreaSeries extends Component { strokeWidth, strokeDasharray, fillStyle, - interpolation, + curve, canvasClip, yAccessor, } = this.props; @@ -66,7 +69,7 @@ export class AreaSeries extends Component { { strokeStyle={strokeStyle} strokeWidth={strokeWidth} strokeDasharray={strokeDasharray} - interpolation={interpolation} + curve={curve} canvasClip={canvasClip} highlightOnHover={false} /> diff --git a/packages/series/src/BarSeries.tsx b/packages/series/src/BarSeries.tsx index fc5b7bda..dac4a07a 100644 --- a/packages/series/src/BarSeries.tsx +++ b/packages/series/src/BarSeries.tsx @@ -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, + xScale: ScaleContinuousNumeric | ScaleTime, yScale: ScaleContinuousNumeric, d: [number, number], moreProps: any, @@ -91,7 +99,12 @@ export class BarSeries extends React.Component { } }; - private readonly getBars = (moreProps: any) => { + private readonly getBars = (moreProps: { + chartConfig: any; + xAccessor: (data: any) => number | Date; + xScale: ScaleContinuousNumeric | ScaleTime; + plotData: any[]; + }) => { const { baseAt, fillStyle, width, yAccessor } = this.props; const { @@ -114,14 +127,17 @@ export class BarSeries extends React.Component { 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; @@ -135,6 +151,7 @@ export class BarSeries extends React.Component { width: offset * 2, fillStyle: getFill(d), }; - }); + }) + .filter((d) => d !== undefined) as IBar[]; }; } diff --git a/packages/series/src/CandlestickSeries.tsx b/packages/series/src/CandlestickSeries.tsx index a1d9b294..4d84acce 100644 --- a/packages/series/src/CandlestickSeries.tsx +++ b/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; @@ -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 { 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, @@ -125,23 +116,16 @@ export class CandlestickSeries extends React.Component { }; private readonly getCandleData = ( - xAccessor: (data: any) => number, - xScale: ScaleContinuousNumeric, + xAccessor: (data: any) => number | Date, + xScale: ScaleContinuousNumeric | ScaleTime, yScale: ScaleContinuousNumeric, 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, @@ -156,6 +140,10 @@ export class CandlestickSeries extends React.Component { .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)))); @@ -173,11 +161,11 @@ export class CandlestickSeries extends React.Component { }, height, width: offset * 2, - className: className(ohlc), fill: fill(ohlc), stroke: stroke(ohlc), direction: ohlc.close - ohlc.open, }; - }); + }) + .filter((d) => d !== undefined) as ICandle[]; }; } diff --git a/packages/series/src/KagiSeries.tsx b/packages/series/src/KagiSeries.tsx index e47e4c72..8120285f 100644 --- a/packages/series/src/KagiSeries.tsx +++ b/packages/series/src/KagiSeries.tsx @@ -2,12 +2,21 @@ import * as React from "react"; import { isDefined, isNotDefined, getAxisCanvas, GenericChartComponent } from "@react-financial-charts/core"; export interface KagiSeriesProps { + /** + * Current value stroke + */ readonly currentValueStroke?: string; - readonly fill?: { + /** + * Fill values. + */ + readonly fill: { yang: string; yin: string; }; - readonly stroke?: { + /** + * Stroke values. + */ + readonly stroke: { yang: string; yin: string; }; @@ -39,7 +48,7 @@ export class KagiSeries extends React.Component { } private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => { - const { stroke = KagiSeries.defaultProps.stroke, strokeWidth, currentValueStroke } = this.props; + const { stroke, strokeWidth, currentValueStroke } = this.props; const { xAccessor, xScale, @@ -47,7 +56,7 @@ export class KagiSeries extends React.Component { plotData, } = moreProps; - const paths = helper(plotData, xAccessor); + const paths = this.helper(plotData, xAccessor); let begin = true; @@ -94,53 +103,53 @@ export class KagiSeries extends React.Component { ctx.lineTo(x, y2); ctx.stroke(); }; -} -const helper = (plotData: any[], xAccessor: any) => { - const kagiLine: any[] = []; - let kagi: { - added?: boolean; - plot?: any; - type?: any; - } = {}; - let d = plotData[0]; - let idx = xAccessor(d); - - // tslint:disable-next-line: prefer-for-of - for (let i = 0; i < plotData.length; i++) { - d = plotData[i]; - - if (isNotDefined(d.close)) { - continue; - } - if (isNotDefined(kagi.type)) { - kagi.type = d.startAs; - } - if (isNotDefined(kagi.plot)) { - kagi.plot = []; - } + private readonly helper = (plotData: any[], xAccessor: any) => { + const kagiLine: any[] = []; + let kagi: { + added?: boolean; + plot?: any; + type?: any; + } = {}; + let d = plotData[0]; + let idx = xAccessor(d); + + // tslint:disable-next-line: prefer-for-of + for (let i = 0; i < plotData.length; i++) { + d = plotData[i]; + + if (isNotDefined(d.close)) { + continue; + } + if (isNotDefined(kagi.type)) { + kagi.type = d.startAs; + } + if (isNotDefined(kagi.plot)) { + kagi.plot = []; + } - idx = xAccessor(d); - kagi.plot.push([idx, d.open]); + idx = xAccessor(d); + kagi.plot.push([idx, d.open]); - if (isDefined(d.changeTo)) { - kagi.plot.push([idx, d.changePoint]); - kagi.added = true; - kagiLine.push(kagi); + if (isDefined(d.changeTo)) { + kagi.plot.push([idx, d.changePoint]); + kagi.added = true; + kagiLine.push(kagi); - kagi = { - type: d.changeTo, - plot: [], - added: false, - }; - kagi.plot.push([idx, d.changePoint]); + kagi = { + type: d.changeTo, + plot: [], + added: false, + }; + kagi.plot.push([idx, d.changePoint]); + } } - } - if (!kagi.added) { - kagi.plot.push([idx, d.close, d.current, d.reverseAt]); - kagiLine.push(kagi); - } + if (!kagi.added) { + kagi.plot.push([idx, d.close, d.current, d.reverseAt]); + kagiLine.push(kagi); + } - return kagiLine; -}; + return kagiLine; + }; +} diff --git a/packages/series/src/LineSeries.tsx b/packages/series/src/LineSeries.tsx index 4c5143c4..6391e927 100644 --- a/packages/series/src/LineSeries.tsx +++ b/packages/series/src/LineSeries.tsx @@ -6,24 +6,54 @@ import { getMouseCanvas, GenericChartComponent, } from "@react-financial-charts/core"; -import { line as d3Line, CurveFactoryLineOnly, CurveFactory } from "d3-shape"; +import { line, CurveFactoryLineOnly, CurveFactory } from "d3-shape"; import * as React from "react"; export interface LineSeriesProps { readonly canvasClip?: (context: CanvasRenderingContext2D, moreProps: any) => void; + /** + * Wether to connect the line between undefined data points. + */ readonly connectNulls?: boolean; + /** + * A factory for a curve generator for the line. + */ + readonly curve?: CurveFactory | CurveFactoryLineOnly; + /** + * Function to decide if a data point has been defined. + */ readonly defined?: (d: number | undefined) => boolean; + /** + * Whether to highlight the line when within the `hoverTolerance`. + */ readonly highlightOnHover?: boolean; + /** + * Width to increase the line to on hover. + */ readonly hoverStrokeWidth?: number; + /** + * The distance between the cursor and the closest point in the line. + */ readonly hoverTolerance?: number; /** - * A factory for a curve generator for the line. + * Click handler. */ - readonly interpolation?: CurveFactory | CurveFactoryLineOnly; readonly onClick?: (e: React.MouseEvent, moreProps: any) => void; + /** + * Double click handler. + */ readonly onDoubleClick?: (e: React.MouseEvent, moreProps: any) => void; + /** + * Hover handler. + */ readonly onHover?: (e: React.MouseEvent, moreProps: any) => void; + /** + * Unhover handler. + */ readonly onUnHover?: (e: React.MouseEvent, moreProps: any) => void; + /** + * Context menu handler. + */ readonly onContextMenu?: (e: React.MouseEvent, moreProps: any) => void; /** * Color, gradient, or pattern to use for the stroke. @@ -102,7 +132,7 @@ export class LineSeries extends React.Component { yAccessor, hoverStrokeWidth = LineSeries.defaultProps.hoverStrokeWidth, defined = LineSeries.defaultProps.defined, - interpolation, + curve, canvasClip, strokeStyle, strokeWidth = LineSeries.defaultProps.strokeWidth, @@ -131,12 +161,12 @@ export class LineSeries extends React.Component { ctx.setLineDash(lineDash); } - const dataSeries = d3Line() + const dataSeries = line() .x((d) => Math.round(xScale(xAccessor(d)))) .y((d) => Math.round(yScale(yAccessor(d)))); - if (interpolation !== undefined) { - dataSeries.curve(interpolation); + if (curve !== undefined) { + dataSeries.curve(curve); } if (!connectNulls) { diff --git a/packages/series/src/MACDSeries.tsx b/packages/series/src/MACDSeries.tsx index 6133d20d..566a14a2 100644 --- a/packages/series/src/MACDSeries.tsx +++ b/packages/series/src/MACDSeries.tsx @@ -1,4 +1,4 @@ -import { ScaleContinuousNumeric } from "d3-scale"; +import { ScaleContinuousNumeric, ScaleTime } from "d3-scale"; import * as React from "react"; import { BarSeries } from "./BarSeries"; import { LineSeries } from "./LineSeries"; @@ -69,7 +69,7 @@ export class MACDSeries extends React.Component { } private readonly yAccessorForDivergenceBase = ( - xScale: ScaleContinuousNumeric, + xScale: ScaleContinuousNumeric | ScaleTime, yScale: ScaleContinuousNumeric, ) => { return yScale(0); diff --git a/packages/series/src/SARSeries.tsx b/packages/series/src/SARSeries.tsx index 8191cedd..c651088b 100644 --- a/packages/series/src/SARSeries.tsx +++ b/packages/series/src/SARSeries.tsx @@ -6,11 +6,15 @@ export interface SARSeriesProps { falling: string; rising: string; }; + readonly strokeStyle?: { + falling: string; + rising: string; + }; readonly highlightOnHover?: boolean; readonly onClick?: (e: React.MouseEvent, moreProps: any) => void; readonly onDoubleClick?: (e: React.MouseEvent, moreProps: any) => void; readonly onContextMenu?: (e: React.MouseEvent, moreProps: any) => void; - readonly yAccessor: (datum: any) => number; + readonly yAccessor: (datum: any) => number | undefined; } /** @@ -25,7 +29,7 @@ export class SARSeries extends React.Component { falling: "#4682B4", rising: "#15EC2E", }, - highlightOnHover: true, + highlightOnHover: false, }; public render() { @@ -54,7 +58,7 @@ export class SARSeries extends React.Component { } private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => { - const { yAccessor, fillStyle = SARSeries.defaultProps.fillStyle } = this.props; + const { yAccessor, fillStyle = SARSeries.defaultProps.fillStyle, strokeStyle } = this.props; const { xAccessor, plotData, @@ -68,19 +72,28 @@ export class SARSeries extends React.Component { const d = ((width / plotData.length) * 0.5) / 2; const radius = Math.min(2, Math.max(0.5, d)) + (hovering ? 2 : 0); - plotData.forEach((each: any) => { + (plotData as any[]).forEach((each) => { + const yValue = yAccessor(each); + if (yValue === undefined) { + return; + } + const centerX = xScale(xAccessor(each)); - const centerY = yScale(yAccessor(each)); - const color = yAccessor(each) > each.close ? fillStyle.falling : fillStyle.rising; + const centerY = yScale(yValue); + const color = yValue > each.close ? fillStyle.falling : fillStyle.rising; ctx.fillStyle = color; - ctx.strokeStyle = color; + if (strokeStyle !== undefined) { + ctx.strokeStyle = yValue > each.close ? strokeStyle.falling : strokeStyle.rising; + } ctx.beginPath(); ctx.ellipse(centerX, centerY, radius, radius, 0, 0, 2 * Math.PI); ctx.closePath(); ctx.fill(); - ctx.stroke(); + if (strokeStyle !== undefined) { + ctx.stroke(); + } }); }; diff --git a/packages/series/src/ScatterSeries.tsx b/packages/series/src/ScatterSeries.tsx index c04f625c..7fbecdf6 100644 --- a/packages/series/src/ScatterSeries.tsx +++ b/packages/series/src/ScatterSeries.tsx @@ -1,12 +1,25 @@ import { functor, getAxisCanvas, GenericChartComponent } from "@react-financial-charts/core"; import { group } from "d3-array"; +import { ScaleContinuousNumeric, ScaleTime } from "d3-scale"; import * as React from "react"; export interface ScatterSeriesProps { - readonly marker?: any; // func - readonly markerProvider?: any; // func + /** + * A Marker to draw. + */ + readonly marker?: any; + /** + * Given the data point return a Marker. + */ + readonly markerProvider?: (datum: any) => any; + /** + * Props to pass to the marker. + */ readonly markerProps?: object; - readonly yAccessor: (data: any) => number; + /** + * Accessor for y value. + */ + readonly yAccessor: (data: any) => number | undefined; } export class ScatterSeries extends React.Component { @@ -43,7 +56,12 @@ export class ScatterSeries extends React.Component { }); }; - private readonly getMarkers = (moreProps: any) => { + private readonly getMarkers = (moreProps: { + xAccessor: (data: any) => number | Date; + xScale: ScaleContinuousNumeric | ScaleTime; + chartConfig: any; + plotData: any[]; + }) => { const { yAccessor, markerProvider, markerProps } = this.props; const { @@ -58,24 +76,33 @@ export class ScatterSeries extends React.Component { throw new Error("required prop, either marker or markerProvider missing"); } - return plotData.map((d: any) => { - if (markerProvider) { - Marker = markerProvider(d); - } + return plotData + .map((d: any) => { + const yValue = yAccessor(d); + if (yValue === undefined) { + return undefined; + } - const mProps = { ...Marker.defaultProps, ...markerProps }; + const xValue = xAccessor(d); - const fill = functor(mProps.fillStyle); - const stroke = functor(mProps.strokeStyle); + if (markerProvider) { + Marker = markerProvider(d); + } - return { - x: xScale(xAccessor(d)), - y: yScale(yAccessor(d)), - fillStyle: fill(d), - strokeStyle: stroke(d), - datum: d, - marker: Marker, - }; - }); + const mProps = { ...Marker.defaultProps, ...markerProps }; + + const fill = functor(mProps.fillStyle); + const stroke = functor(mProps.strokeStyle); + + return { + x: xScale(xValue), + y: yScale(yValue), + fillStyle: fill(d), + strokeStyle: stroke(d), + datum: d, + marker: Marker, + }; + }) + .filter((marker) => marker !== undefined); }; } diff --git a/packages/series/src/StraightLine.tsx b/packages/series/src/StraightLine.tsx index 3de34082..3876ca07 100644 --- a/packages/series/src/StraightLine.tsx +++ b/packages/series/src/StraightLine.tsx @@ -1,4 +1,4 @@ -import { ScaleContinuousNumeric } from "d3-scale"; +import { ScaleContinuousNumeric, ScaleTime } from "d3-scale"; import * as React from "react"; import { getAxisCanvas, @@ -61,7 +61,7 @@ export class StraightLine extends React.Component { private readonly getLineCoordinates = ( type: "horizontal" | "vertical" | undefined, - xScale: ScaleContinuousNumeric, + xScale: ScaleContinuousNumeric | ScaleTime, yScale: ScaleContinuousNumeric, xValue: number | undefined, yValue: number | undefined, diff --git a/packages/series/src/VolumeProfileSeries.tsx b/packages/series/src/VolumeProfileSeries.tsx index 2737af2f..d0c73703 100644 --- a/packages/series/src/VolumeProfileSeries.tsx +++ b/packages/series/src/VolumeProfileSeries.tsx @@ -3,7 +3,6 @@ import { scaleLinear } from "d3-scale"; import * as React from "react"; import { accumulatingWindow, - colorToRGBA, functor, head, identity, @@ -13,30 +12,38 @@ import { } from "@react-financial-charts/core"; export interface VolumeProfileSeriesProps { - readonly className?: string; - readonly opacity?: number; - readonly showSessionBackground?: boolean; + readonly absoluteChange: (datum: any) => number; + readonly bins: number; + readonly bySession?: boolean; + readonly fill?: (widthType: { type: "up" | "down"; width: number }) => string; + readonly maxProfileWidthPercent: number; + readonly orient?: "left" | "right"; + readonly partialStartOK?: boolean; + readonly partialEndOK?: boolean; readonly sessionBackGround?: string; + readonly sessionStart: ({ d, i, plotData }: any) => boolean; + readonly showSessionBackground?: boolean; + readonly source: (d: number, i: number, data: ArrayLike) => number; + readonly stroke?: string; + readonly volume: (datum: any) => number; } export class VolumeProfileSeries extends React.Component { public static defaultProps = { - className: "line ", - bins: 20, - opacity: 0.5, - maxProfileWidthPercent: 50, - fill: ({ type }: any) => (type === "up" ? "#6BA583" : "#FF0000"), - stroke: "#FFFFFF", - showSessionBackground: false, - sessionBackGround: "rgba(70, 130, 180, 0.3)", - source: (d: any) => d.close, - volume: (d: any) => d.volume, absoluteChange: (d: any) => d.absoluteChange, + bins: 20, bySession: false, - sessionStart: ({ d, i, plotData }: any) => i > 0 && plotData[i - 1].date.getMonth() !== d.date.getMonth(), + fill: ({ type }: { type: "up" | "down"; width: number }) => (type === "up" ? "#6BA583" : "#FF0000"), + maxProfileWidthPercent: 50, orient: "left", partialStartOK: true, partialEndOK: true, + sessionBackGround: "rgba(70, 130, 180, 0.3)", + sessionStart: ({ d, i, plotData }: any) => i > 0 && plotData[i - 1].date.getMonth() !== d.date.getMonth(), + showSessionBackground: false, + source: (d: any) => d.close, + stroke: "#FFFFFF", + volume: (d: any) => d.volume, }; public render() { @@ -48,16 +55,11 @@ export class VolumeProfileSeries extends React.Component { - const { opacity, sessionBackGround, showSessionBackground } = props; + private readonly drawOnCanvasContext = (ctx: CanvasRenderingContext2D, rects: any[], sessionBg: any[]) => { + const { sessionBackGround, showSessionBackground } = this.props; if (showSessionBackground) { if (sessionBackGround !== undefined) { @@ -78,7 +80,7 @@ export class VolumeProfileSeries extends React.Component 0) { - ctx.fillStyle = colorToRGBA(fill1, opacity); + ctx.fillStyle = fill1; if (stroke1 !== "none") { ctx.strokeStyle = stroke1; } @@ -94,7 +96,7 @@ export class VolumeProfileSeries extends React.Component 0) { - ctx.fillStyle = colorToRGBA(fill2, opacity); + ctx.fillStyle = fill2; if (stroke2 !== "none") { ctx.strokeStyle = stroke2; } @@ -111,7 +113,7 @@ export class VolumeProfileSeries extends React.Component { + private readonly helper = (props: VolumeProfileSeriesProps, moreProps: any, xAccessor: any, width: number) => { const { xScale: realXScale, chartConfig: { yScale }, @@ -124,7 +126,6 @@ export class VolumeProfileSeries extends React.Component { return sessionStart({ d, i, ...moreProps }); diff --git a/packages/series/src/index.ts b/packages/series/src/index.ts index db18712c..4399c9e0 100644 --- a/packages/series/src/index.ts +++ b/packages/series/src/index.ts @@ -1,14 +1,12 @@ export * from "./AreaSeries"; export * from "./AlternatingFillAreaSeries"; export * from "./AreaOnlySeries"; -export * from "./CircleMarker"; -export * from "./TriangleMarker"; -export * from "./SquareMarker"; +export * from "./markers"; export * from "./LineSeries"; export * from "./CandlestickSeries"; export * from "./OHLCSeries"; export * from "./BarSeries"; -export { StackedBarSeries } from "./StackedBarSeries"; +export { StackedBarSeries, StackedBarSeriesProps } from "./StackedBarSeries"; export * from "./GroupedBarSeries"; export * from "./KagiSeries"; export * from "./PointAndFigureSeries"; diff --git a/packages/series/src/CircleMarker.tsx b/packages/series/src/markers/CircleMarker.tsx similarity index 91% rename from packages/series/src/CircleMarker.tsx rename to packages/series/src/markers/CircleMarker.tsx index 4051492d..7537f18c 100644 --- a/packages/series/src/CircleMarker.tsx +++ b/packages/series/src/markers/CircleMarker.tsx @@ -41,11 +41,13 @@ export class CircleMarker extends React.Component { ctx.fillStyle = fillStyle; } - const radius = functor(r)(point.datum); + const { datum, x, y } = point; + + const radius = functor(r)(datum); - ctx.moveTo(point.x, point.y); + ctx.moveTo(x, y); ctx.beginPath(); - ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI, false); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); ctx.stroke(); ctx.fill(); }; diff --git a/packages/series/src/SquareMarker.tsx b/packages/series/src/markers/SquareMarker.tsx similarity index 100% rename from packages/series/src/SquareMarker.tsx rename to packages/series/src/markers/SquareMarker.tsx diff --git a/packages/series/src/TriangleMarker.tsx b/packages/series/src/markers/TriangleMarker.tsx similarity index 100% rename from packages/series/src/TriangleMarker.tsx rename to packages/series/src/markers/TriangleMarker.tsx diff --git a/packages/series/src/markers/index.ts b/packages/series/src/markers/index.ts new file mode 100644 index 00000000..ee9a95a2 --- /dev/null +++ b/packages/series/src/markers/index.ts @@ -0,0 +1,3 @@ +export * from "./CircleMarker"; +export * from "./SquareMarker"; +export * from "./TriangleMarker";