import orderFeedDrawer from "./OrderFeed.drawer";
import {Box, useTheme} from "@mui/material";
import {TradeItem} from "../../../store/orderClusterSlice";
import {OrderFeedProps} from "./OrderFeed.props";
import {GPU} from "gpu.js";
const gpu = new GPU();

const OrderFeed = ({workerRef, symbol, settings}: OrderFeedProps) => {
  const cupParams = useSelector((state: AppState) => state.cupSlice);
  const [dpiScale, setDpiScale] = useState(Math.ceil(window.devicePixelRatio));
  const [canvasSize, setCanvasSize] = useState<CanvasSize>({height: 0, width: 0});
  const containerRef = useRef<HTMLDivElement|null>(null);
  const canvasRef = useRef<HTMLCanvasElement|null>(null);
  const size = useComponentResizeListener(canvasRef);
  const theme = useTheme();

  const draw = (trades: TradeItem[], camera: number) => {
    if (null === canvasRef || !Array.isArray(trades)) return;

    const context = canvasRef.current?.getContext("2d");

    if (context) {
      orderFeedDrawer.clear(context, canvasSize);
      orderFeedDrawer.drawLine(
        context,
        canvasSize,
        trades,
        camera,
        cupParams.aggregatedPriceStep,
        cupParams.cellHeight,
        cupParams.quantityDivider,
        !settings.minQuantity ? 0 : parseFloat(settings.minQuantity),
        dpiScale,
        theme,
      );
    }
  };

useEffect(() => {
draw(event.data.trades, event.data.camera)
  }, [workerRef.current, canvasRef.current, canvasSize, symbol, cupParams, theme, settings.minQuantity, settings.volumeAsDollars]);

  return <Box ref={containerRef} className={`${styles.canvasWrapper} scroll-block`}>
    <canvas
      ref={canvasRef}
      className={styles.canvas}
      width={canvasSize?.width}
      height={canvasSize?.height}
    />
  </Box>;
};

export default OrderFeed;


const clamp = (value: number, min: number, max: number): number => {
  return Math.min(Math.max(value, min), max);
};

const orderFeedDrawer = {
  clear: (ctx: CanvasRenderingContext2D, size: CanvasSize) => {
    ctx.clearRect(0, 0, size.width, size.height);
  },
  drawLine: (
    ctx: CanvasRenderingContext2D,
    canvasSize: CanvasSize,
    trades: TradeItem[],
    camera: number,
    aggregatedPriceStep: number,
    cupCellHeight: number,
    quantityDivider: number,
    minQuantity: number,
    dpiScale: number,
    theme: Theme,
  ) => {
    let startX = canvasSize.width - 10 * dpiScale;
    const fullHeightRowsCount = parseInt((canvasSize.height / cupCellHeight).toFixed(0));
    const startY = (fullHeightRowsCount % 2 ? fullHeightRowsCount - 1 : fullHeightRowsCount) / 2 * cupCellHeight;
    const halfCupCellHeight = cupCellHeight / 2;

    ctx.beginPath();
    ctx.strokeStyle = orderFeedOptions(theme).line.color;
    ctx.lineWidth = 2 * dpiScale;

    trades.forEach(trade => {
      const yModifier = (trade.price - (trade.price - (trade?.secondPrice || trade.price)) / 2 - camera) / aggregatedPriceStep * cupCellHeight + halfCupCellHeight;
      const width = 1.75 * clamp((trade.quantity / quantityDivider < minQuantity ? 0 : trade.radius), 5, 50) * dpiScale;

      ctx.lineTo(startX - width / 2, startY - yModifier);
      startX = startX - width;
    });

    ctx.stroke();
  },

};

export default orderFeedDrawer;

export class GPU {
  static isGPUSupported: boolean;
  static isCanvasSupported: boolean;
  static isHeadlessGLSupported: boolean;
  static isWebGLSupported: boolean;
  static isWebGL2Supported: boolean;
  static isKernelMapSupported: boolean;
  static isOffscreenCanvasSupported: boolean;
  static isGPUHTMLImageArraySupported: boolean;
  static isSinglePrecisionSupported: boolean;
  constructor(settings?: IGPUSettings);
  functions: GPUFunction<ThreadKernelVariable[]>[];
  nativeFunctions: IGPUNativeFunction[];
  setFunctions(flag: any): this;
  setNativeFunctions(flag: IGPUNativeFunction[]): this;
  addFunction<ArgTypes extends ThreadKernelVariable[] = ThreadKernelVariable[], ConstantsType = {}>(kernel: GPUFunction<ArgTypes, ConstantsType>, settings?: IGPUFunctionSettings): this;
  addNativeFunction(name: string, source: string, settings?: IGPUFunctionSettings): this;
  combineKernels(...kernels: KernelFunction[]): IKernelRunShortcut;
  combineKernels<KF extends KernelFunction>(...kernels: KF[]):
    ((...args: Parameters<KF>) =>
      ReturnType<KF>[]
      | ReturnType<KF>[][]
      | ReturnType<KF>[][][]
      | Texture
      | void
      )
    & IKernelRunShortcutBase;
  createKernel<ArgTypes extends ThreadKernelVariable[], ConstantsT extends IConstantsThis>(kernel: KernelFunction<ArgTypes, ConstantsT>, settings?: IGPUKernelSettings): IKernelRunShortcut;
  createKernel<KernelType extends KernelFunction>(kernel: KernelType, settings?: IGPUKernelSettings):
    ((...args: Parameters<KernelType>) =>
      ReturnType<KernelType>[]
      | ReturnType<KernelType>[][]
      | ReturnType<KernelType>[][][]
      | Texture
      | void
      )
    & IKernelRunShortcutBase;
  createKernelMap<
    ArgTypes extends ThreadKernelVariable[],
    ConstantsType = null,
    >(
    subKernels: ISubKernelObject,
    rootKernel: ThreadFunction<ArgTypes, ConstantsType>,
    settings?: IGPUKernelSettings): (((this: IKernelFunctionThis<ConstantsType>, ...args: ArgTypes) => IMappedKernelResult) & IKernelMapRunShortcut<typeof subKernels>);
  destroy(): Promise<void>;
  Kernel: typeof Kernel;
  mode: string;
  canvas: any;
  context: any;
}

Помимо CanvasRenderingContext2D есть еще WebGLRenderingContext.
Есть библиотека https://github.com/gpujs/gpu.js/ через которую можно инициализировать canvas с WebGL контекстом. перепиши синтаксис на библиотеку "gpu.js": "^2.16.0",