import { strokeDashTypes } from "@fishbot/chart-core"; import { ScaleContinuousNumeric } from "d3-scale"; import { CurveFactory } from "d3-shape"; import * as React from "react"; import { AreaSeries } from "./AreaSeries"; import { SVGComponent } from "./SVGComponent"; export interface AlternatingFillAreaSeriesProps { readonly baseAt: number; /** * Wether to connect the area between undefined data points. */ readonly connectNulls?: boolean; /** * Color, gradient, or pattern to use for fill. */ readonly fillStyle?: { top: string; bottom: string; }; /** * A factory for a curve generator for the area and line. */ readonly curve?: CurveFactory; /** * Color, gradient, or pattern to use for the stroke. */ readonly strokeStyle?: { top: string; bottom: string; }; /** * Stroke dash. */ readonly strokeDasharray?: { top: strokeDashTypes; bottom: strokeDashTypes; }; /** * Stroke width. */ readonly strokeWidth?: { top: number; bottom: number; }; /** * Selector for data to plot. */ readonly yAccessor: (data: any) => number | undefined; } /** * `AlternatingFillAreaSeries` component is similar to a `AreaSeries` but with different colors above and below the base. */ export class AlternatingFillAreaSeries extends React.Component { public static defaultProps = { connectNulls: false, fillStyle: { top: "rgba(38, 166, 154, 0.1)", bottom: "rgba(239, 83, 80, 0.1)", }, strokeStyle: { top: "#26a69a", bottom: "#ef5350", }, strokeWidth: { top: 2, bottom: 2, }, strokeDasharray: { top: "Solid" as strokeDashTypes, bottom: "Solid" as strokeDashTypes, }, }; private clipPathId1 = `alternating-area-clip-${String(Math.round(Math.random() * 10000 * 10000))}`; private clipPathId2 = `alternating-area-clip-${String(Math.round(Math.random() * 10000 * 10000))}`; public render() { const { connectNulls, yAccessor, curve, strokeStyle = AlternatingFillAreaSeries.defaultProps.strokeStyle, strokeWidth = AlternatingFillAreaSeries.defaultProps.strokeWidth, strokeDasharray = AlternatingFillAreaSeries.defaultProps.strokeDasharray, fillStyle = AlternatingFillAreaSeries.defaultProps.fillStyle, } = this.props; return ( {this.renderClip} ); } private readonly baseAt = (yScale: ScaleContinuousNumeric) => { return yScale(this.props.baseAt); }; private readonly renderClip = (moreProps: any) => { const { chartConfig } = moreProps; const { baseAt } = this.props; const { yScale, width, height } = chartConfig; return ( ); }; private readonly bottomClip = (ctx: CanvasRenderingContext2D, moreProps: any) => { const { chartConfig } = moreProps; const { baseAt } = this.props; const { yScale, width, height } = chartConfig; ctx.beginPath(); ctx.rect(0, yScale(baseAt), width, height - yScale(baseAt)); ctx.clip(); }; private readonly topClip = (ctx: CanvasRenderingContext2D, moreProps: any) => { const { chartConfig } = moreProps; const { baseAt } = this.props; const { yScale, width } = chartConfig; ctx.beginPath(); ctx.rect(0, 0, width, yScale(baseAt)); ctx.clip(); }; }