Задать вопрос
@Tellepuzik

Canvas на девайсах с высоким dpr. Как масштабировать динамическое содержимое canvas?

Есть вот такой компонент для кастомного Canvas

import { useResize } from "@/hooks";
import {
  ComponentPropsWithoutRef,
  forwardRef,
  useEffect,
  useImperativeHandle,
  useRef,
} from "react";

export const Canvas = forwardRef<
  HTMLCanvasElement,
  ComponentPropsWithoutRef<"canvas">
>((props, ref) => {
  const innerRef = useRef<HTMLCanvasElement | null>(null);
  const canvasRef = (ref as React.RefObject<HTMLCanvasElement>) || innerRef;
  const { width } = useResize(); 

  useImperativeHandle(ref, () => canvasRef.current, [canvasRef]);

  useEffect(() => {
    const dpr = window.devicePixelRatio || 1;

    if (dpr < 1 || !canvasRef.current) {
      return;
    }

    const canvas = canvasRef.current;
    const ctx = canvas.getContext("2d");
    if (!ctx) {
      return;
    }

    const rect = canvas.getBoundingClientRect();		

    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
		
    ctx.scale(dpr, dpr);

    canvas.style.width = `${rect.width}px`;
    canvas.style.height = `${rect.height}px`;
  }, [width, canvasRef.current]);

  return (
    <canvas
      {...props}
      ref={canvasRef}
    />
  );
});


В useEffect описана логика, для high dpr устройств, ну и полагаю для масштабирования на ctrl + mousewheel должно работать также.

Проблема в том, что вроде бы работает масштабирование, но когда доходит дело до стилей (т.е. применение старых размеров, что бы сам canvas не был гигантским), сам canvas меньше становится, а содержимое, как было огромным, так и остается.

На canvas рисуются графики, обновляются каждую секунду.
  • Вопрос задан
  • 90 просмотров
Подписаться 1 Средний 4 комментария
Решения вопроса 1
@Tellepuzik Автор вопроса
Получилось исправить!
Из-за того, что у меня графики динамические и перерисовываются каждую секунду, трансформация накапливалась.
Решить проблему оказалось довольно просто. В функции отрисовки в самом начале вызывайте context.setTransform(1, 0, 0, 1, 0, 0); и все будет корректно отображаться.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы