Usar un lienzo para representar una colección de imágenes en capas para que un usuario pueda descargar la imagen compilada después. Sin embargo, cuando se usa image.onload , coloca en capas el orden de las imágenes en términos de cuál se carga más rápido desde la CDN.
Estoy tratando de lograr que estén en capas en términos de progresión de la línea de código. ¿Hay alguna forma de lograr esto? He intentado funciones asíncronas pero realmente no he podido lograr nada. A continuación se muestra el código actual que tengo:
import React, { useRef, useEffect } from 'react'; interface CanvasProps { width: number; height: number; base: string; eyes: string; hat: string; backpack: string; clothes: string; selected: number; } const Canvas = ({ width, height, base, eyes, hat, backpack, clothes, selected }: CanvasProps) => { const canvasRef = useRef<HTMLCanvasElement>(null); const renderImages = async (context) => { var bg_image = new Image(); var base_image = new Image(); var eyes_image = new Image(); var hats_image = new Image(); var backpacks_image = new Image(); var clothes_image = new Image(); bg_image.crossOrigin="*"; base_image.crossOrigin="*"; eyes_image.crossOrigin="*"; hats_image.crossOrigin="*"; clothes_image.crossOrigin="*"; backpacks_image.crossOrigin="*"; base_image.src = base; eyes_image.src = eyes; hats_image.src = hat; clothes_image.src = backpack; backpacks_image.src = clothes; base_image.onload = function(){ context.drawImage(base_image, 0, 0, 650, 650) } eyes_image.onload = function(){ context.drawImage(eyes_image, 0, 0, 650, 650) } hats_image.onload = function(){ context.drawImage(hats_image, 0, 0, 650, 650) } clothes_image.onload = function(){ context.drawImage(clothes_image, 0, 0, 650, 650) } backpacks_image.onload = function(){ context.drawImage(backpacks_image, 0, 0, 650, 650) } } useEffect(() => { if (canvasRef.current) { const canvas = canvasRef.current; if (canvasRef.current) { const context = canvas.getContext('2d'); if (context) { context.clearRect(0, 0, 650, 650); renderImages(context); } } } },[selected]); return <canvas id="canvas" ref={canvasRef} height={height} width={width} />; }; Canvas.defaultProps = { width: window.innerWidth, height: window.innerHeight }; export default Canvas;Puede envolver la creación de su imagen en una Promise que se resuelve una vez que la imagen termina de cargarse y esperar a que finalice cada una de las cargas de imágenes, para lograr el flujo sincrónico que desea.
const getImg = (url: string) => { const img = new Image(); img.crossOrigin="*"; img.src = url; return new Promise((res, rej) => { img.onload = () => res(img); img.onerror = (err) => rej(err); }); } const renderImages = async (context) => { const baseImg = await getImg(base); context.drawImage(baseImg, 0, 0, 650, 650); const eyesImg = await getImg(eyes); context.drawImage(eyesImg, 0, 0, 650, 650); const hatImg = await getImg(hat); context.drawImage(hatImg, 0, 0, 650, 650); const backpackImg = await getImg(backpack); context.drawImage(backpackImg, 0, 0, 650, 650); const clothesImg = await getImg(clothes); context.drawImage(clothesImg, 0, 0, 650, 650); }Usaría una matriz image_sources en lugar de las muchas variables que está usando
(base, ojos, sombrero, mochila, ropa) , beneficios de este enfoque:
renderImages para dibujar secuencialmente todas las imágenes.Aquí está mi prototipo aproximado:
const renderImages = (context, index) => { if (index < image_sources.length) { let image = new Image(); image.crossOrigin = "*"; image.src = image_sources[index]; image.onload = function() { context.drawImage(image, 0, 0, 650, 650) renderImages(context, index + 1) } } } useEffect(() => { if (canvasRef.current) { const canvas = canvasRef.current; if (canvasRef.current) { const context = canvas.getContext('2d'); if (context) { context.clearRect(0, 0, 650, 650); renderImages(context, 0); } } } }, [selected]);