import { FC, useEffect, useRef } from "react"; const drawArrow = (ctx: CanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number) => { const [dx, dy] = [x1 - x2, y1 - y2]; const norm = Math.sqrt(dx * dx + dy * dy); const [udx, udy] = [dx / norm, dy / norm]; const size = norm / 7; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.moveTo(x2, y2); ctx.lineTo(x2 + udx * size - udy * size, y2 + udx * size + udy * size); ctx.moveTo(x2, y2); ctx.lineTo(x2 + udx * size + udy * size, y2 - udx * size + udy * size); ctx.stroke(); }; export interface ICurveProps { ethReserve: number; tokenReserve: number; addingEth: number; addingToken: number; width: number; height: number; } export const Curve: FC = (props: ICurveProps) => { const ref = useRef(null); useEffect(() => { const canvas = ref.current; if (!canvas) { return; } const textSize = 12; const width = canvas.width; const height = canvas.height; if (props.ethReserve && props.tokenReserve) { const k = props.ethReserve * props.tokenReserve; const ctx = canvas.getContext("2d"); if (ctx == null) { return; } ctx.clearRect(0, 0, width, height); let maxX = k / (props.ethReserve / 4); let minX = 0; if (props.addingEth || props.addingToken) { maxX = k / (props.ethReserve * 0.4); //maxX = k/(props.ethReserve*0.8) minX = k / Math.max(0, 500 - props.ethReserve); } const maxY = (maxX * height) / width; const minY = (minX * height) / width; const plotX = (x: number) => { return ((x - minX) / (maxX - minX)) * width; }; const plotY = (y: number) => { return height - ((y - minY) / (maxY - minY)) * height; }; ctx.strokeStyle = "#000000"; ctx.fillStyle = "#000000"; ctx.font = textSize + "px Arial"; // +Y axis ctx.beginPath(); ctx.moveTo(plotX(minX), plotY(0)); ctx.lineTo(plotX(minX), plotY(maxY)); ctx.stroke(); // +X axis ctx.beginPath(); ctx.moveTo(plotX(0), plotY(minY)); ctx.lineTo(plotX(maxX), plotY(minY)); ctx.stroke(); ctx.lineWidth = 2; ctx.beginPath(); let first = true; for (let x = minX; x <= maxX; x += maxX / width) { ///// const y = k / x; ///// if (first) { ctx.moveTo(plotX(x), plotY(y)); first = false; } else { ctx.lineTo(plotX(x), plotY(y)); } } ctx.stroke(); ctx.lineWidth = 1; if (props.addingEth) { const newEthReserve = props.ethReserve + parseFloat(props.addingEth.toString()); ctx.fillStyle = "#bbbbbb"; ctx.beginPath(); ctx.arc(plotX(newEthReserve), plotY(k / newEthReserve), 5, 0, 2 * Math.PI); ctx.fill(); ctx.strokeStyle = "#009900"; drawArrow( ctx, plotX(props.ethReserve), plotY(props.tokenReserve), plotX(newEthReserve), plotY(props.tokenReserve), ); ctx.fillStyle = "#000000"; ctx.fillText( "" + props.addingEth + " ETH input", plotX(props.ethReserve) + textSize, plotY(props.tokenReserve) - textSize, ); ctx.strokeStyle = "#990000"; drawArrow(ctx, plotX(newEthReserve), plotY(props.tokenReserve), plotX(newEthReserve), plotY(k / newEthReserve)); const amountGained = Math.round((10000 * (props.addingEth * props.tokenReserve)) / newEthReserve) / 10000; ctx.fillStyle = "#000000"; ctx.fillText( "" + amountGained + " 🎈 output (-0.3% fee)", plotX(newEthReserve) + textSize, plotY(k / newEthReserve), ); } else if (props.addingToken) { const newTokenReserve = props.tokenReserve + parseFloat(props.addingToken.toString()); ctx.fillStyle = "#bbbbbb"; ctx.beginPath(); ctx.arc(plotX(k / newTokenReserve), plotY(newTokenReserve), 5, 0, 2 * Math.PI); ctx.fill(); //console.log("newTokenReserve",newTokenReserve) ctx.strokeStyle = "#990000"; drawArrow( ctx, plotX(props.ethReserve), plotY(props.tokenReserve), plotX(props.ethReserve), plotY(newTokenReserve), ); ctx.fillStyle = "#000000"; ctx.fillText( "" + props.addingToken + " 🎈 input", plotX(props.ethReserve) + textSize, plotY(props.tokenReserve), ); ctx.strokeStyle = "#009900"; drawArrow( ctx, plotX(props.ethReserve), plotY(newTokenReserve), plotX(k / newTokenReserve), plotY(newTokenReserve), ); const amountGained = Math.round((10000 * (props.addingToken * props.ethReserve)) / newTokenReserve) / 10000; //console.log("amountGained",amountGained) ctx.fillStyle = "#000000"; ctx.fillText( "" + amountGained + " ETH output (-0.3% fee)", plotX(k / newTokenReserve) + textSize, plotY(newTokenReserve) - textSize, ); } ctx.fillStyle = "#0000FF"; ctx.beginPath(); ctx.arc(plotX(props.ethReserve), plotY(props.tokenReserve), 5, 0, 2 * Math.PI); ctx.fill(); } }, [props]); return (
-- ETH Reserve --{">"}
-- Token Reserve --{">"}
); };