import * as React from "react"; import { functor } from "@fishbot/chart-core"; export interface TriangleProps { readonly className?: string; readonly direction?: "top" | "bottom" | "left" | "right" | "hide" | ((datum: any) => any); readonly fillStyle?: string | ((datum: any) => string); readonly point: { x: number; y: number; datum: any; }; readonly strokeStyle?: string | ((datum: any) => string); readonly strokeWidth?: number; readonly width?: number | ((datum: any) => number); } export class Triangle extends React.Component { public static defaultProps = { direction: "top", fillStyle: "#4682B4", className: "react-financial-charts-marker-triangle", }; public static drawOnCanvas = ( props: TriangleProps, point: { x: number; y: number; datum: unknown }, ctx: CanvasRenderingContext2D, ) => { const { fillStyle, strokeStyle, strokeWidth, width } = props; if (strokeStyle !== undefined) { ctx.strokeStyle = functor(strokeStyle)(point.datum); } if (strokeWidth !== undefined) { ctx.lineWidth = strokeWidth; } if (fillStyle !== undefined) { ctx.fillStyle = functor(fillStyle)(point.datum); } const w = functor(width)(point.datum); const { x, y } = point; const { innerOpposite, innerHypotenuse } = getTrianglePoints(w); const rotationDeg = getRotationInDegrees(props, point); ctx.beginPath(); ctx.moveTo(x, y - innerHypotenuse); ctx.lineTo(x + w / 2, y + innerOpposite); ctx.lineTo(x - w / 2, y + innerOpposite); // TODO: rotation does not work // example: https://gist.github.com/geoffb/6392450 if (rotationDeg !== null && rotationDeg !== 0) { ctx.save(); ctx.translate(x, y); ctx.rotate((rotationDeg * Math.PI) / 180); // 45 degrees ctx.fill(); ctx.restore(); } ctx.fill(); if (strokeStyle !== undefined) { ctx.stroke(); } }; public render() { const { className, fillStyle, strokeStyle, strokeWidth, point, width } = this.props; const rotation = getRotationInDegrees(this.props, point); if (rotation == null) { return null; } const fillColor = functor(fillStyle)(point.datum); const strokeColor = functor(strokeStyle)(point.datum); const w = functor(width)(point.datum); const { x, y } = point; const { innerOpposite, innerHypotenuse } = getTrianglePoints(w); const points = ` ${x} ${y - innerHypotenuse}, ${x + w / 2} ${y + innerOpposite}, ${x - w / 2} ${y + innerOpposite} `; return ( ); } } const getTrianglePoints = (width: number) => { const innerHypotenuse = (width / 2) * (1 / Math.cos((30 * Math.PI) / 180)); const innerOpposite = (width / 2) * (1 / Math.tan((60 * Math.PI) / 180)); return { innerOpposite, innerHypotenuse, }; }; const getRotationInDegrees = (props: TriangleProps, point: any) => { const { direction = Triangle.defaultProps.direction } = props; const directionVal = functor(direction)(point.datum); if (directionVal === "hide") { return null; } let rotate = 0; switch (directionVal) { case "bottom": rotate = 180; break; case "left": rotate = -90; break; case "right": rotate = 90; break; } return rotate; };