如何为同一个画布设置多个上下文?

问题描述

首先,我从一个空白的白色画布开始,它代表背景画布。 当用户上传图片时,该图片将被设置为全尺寸作为背景图片。 现在,我想为用户提供多种工具来操作相对于父背景画布上传的图像。这些工具是:

  1. 增加/减少鼠标滚轮输入的图像上下文(缩放会增加图像大小,缩小会减小大小)
  2. 通过数字输入字段旋转图像
  3. 在画布内移动图像以使其更适合

这是我的 ReferenceGrid.js 文件的样子:

import React,{useState,useEffect} from 'react'

const ReferenceGrid = ({onHandleSubmit}) => {

var bounds = null;
var ctx = null;
var hasLoaded = false;

var startX = 0;
var startY = 0;
var mouseX = 0;
var mouseY = 0;
let isDragging = false;
let dragStartPosition = [];

let imgHeight;
let imgWidth;
let imgPosX;
let imgPosY;

var scale = 1.5;
var originx = 0;
var originy = 0;

function onBgDown (e){
    let cs = bgCanvasRef.current;
    bounds = cs.getBoundingClientRect();

    imgHeight = imageObjRef.current.height;
    imgWidth = imageObjRef.current.width;
    imgPosX = imagePosition.current[0];
    imgPosY = imagePosition.current[1];
    
    if ((mouseX >= imgPosX && mouseX <= imgWidth + imgPosX) && (mouseY >= imgPosY && mouseY <= imgHeight + imgPosY)){
        isDragging = true;
        dragStartPosition = [mouseX - imagePosition.current[0],mouseY - imagePosition.current[1]]
    }
}

function onBgUp (e){
    let cs = bgCanvasRef.current;
    bounds = cs.getBoundingClientRect();

    mouseX = e.clientX - bounds.left;
    mouseY = e.clientY - bounds.top;

    isDragging = false;
    dragStartPosition = [];
}

function onBgMove (e){
    let cs = bgCanvasRef.current;    
    bounds = cs.getBoundingClientRect();

    mouseX = e.clientX - bounds.left;
    mouseY = e.clientY - bounds.top;
    imgHeight = imageObjRef.current && imageObjRef.current.height;
    imgWidth = imageObjRef.current && imageObjRef.current.width;
    imgPosX = imagePosition.current[0];
    imgPosY = imagePosition.current[1];

    if ((mouseX >= imgPosX && mouseX <= imgWidth + imgPosX) && (mouseY >= imgPosY && mouseY <= imgHeight + imgPosY)){
        cs.style.cursor = "all-scroll"
    }
    else {
        cs.style.cursor = "default"
    }

    if(isDragging){
        imagePosition.current = [mouseX - dragStartPosition[0],mouseY - dragStartPosition[1]];
        window.requestAnimationFrame(drawBgImage);
    }
}

function onBgOut (e){
    isDragging = false;
}

function onBgMousewheel (e){
    console.log("SCROLLED WITH MOUSE WHEEL: ",e.wheelDelta)

    //let cs = bgCanvasRef.current.getContext("2d");

    var mousex = e.clientX - bgCanvasRef.offsetLeft;
    var mousey = e.clientY - bgCanvasRef.offsetTop;
    var wheel = e.wheelDelta / 120; //n or -n

    //according to Chris comment
    var zoom = Math.pow(1 + Math.abs(wheel) / 2,wheel > 0 ? 1 : -1);

    bgCanvasRef.current.getContext("2d").translate(
      originx,originy
    );
    bgCanvasRef.current.getContext("2d").scale(zoom,zoom);
    bgCanvasRef.current.getContext("2d").translate(
      -(mousex / scale + originx - mousex / (scale * zoom)),-(mousey / scale + originy - mousey / (scale * zoom))
    );

    originx = (mousex / scale + originx - mousex / (scale * zoom));
    originy = (mousey / scale + originy - mousey / (scale * zoom));
    scale *= zoom;

    //bgCanvasRef.current.getContext("2d").clearRect(0,bgCanvasRef.current.width,bgCanvasRef.current.height);

    window.requestAnimationFrame(drawBgImage);
}

const onLoadFunc = () => {
    let bgCanvas = bgCanvasRef.current;
    bgCanvas.width = 1200;
    bgCanvas.height = 600;

    bgCanvas.onmousedown = onBgDown;
    bgCanvas.onmouseup = onBgUp;
    bgCanvas.onmousemove = onBgMove;
    bgCanvas.onmouSEOut = onBgOut;
    bgCanvas.addEventListener('wheel',onBgMousewheel,{passive: true});

    bounds = bgCanvas.getBoundingClientRect();
    ctx = bgCanvas.getContext("2d");
    ctx.fillStyle = "white";
    ctx.fillRect(0,bgCanvas.width,bgCanvas.height);
    bgCanvas && console.log("canvas loaded")
}

const loadImage = (path) => {
    let bgImage = new Image();
    let promise = new Promise((resolve,reject) => {
      bgImage.onload = () => resolve(bgImage);
      bgImage.onerror = reject;
    });
    bgImage.src = path;
    return promise;
}
  

function drawBgImage() {
    let cs = bgCanvasRef.current;
    let ctx = cs.getContext("2d");

    ctx.clearRect(0,cs.width,cs.height);
    ctx.save();

    ctx.setTransform(1,1,0);

    ctx.translate( 1200/2,600/2 );
    ctx.rotate( angle * Math.PI / 180 );
    ctx.translate( -(1200/2),-(600/2) );

    imageObjRef.current && ctx.drawImage(imageObjRef.current,imagePosition.current[0],imagePosition.current[1]);

    ctx.restore();
}

const onChangeInputFile = (e) => {
    if (e.target.files){
        console.log("FILE UPLOADED: ",e.target.files[0])
        setInputFile(e.target.files[0]);
    }
}

const [inputFile,setInputFile] = useState();
const imageRef = React.useRef();
const [editimage,setEditimage] = useState(false);
const [angle,setAngle] = useState(0);
const bgCanvasRef = React.useRef();
const imagePosition = React.useRef([]);
const imageObjRef = React.useRef();


useEffect(() => { 
    imageRef.current = inputFile;     
    if(inputFile){
        imagePosition.current = [0,0];
        let imgSrc = imageRef.current ? URL.createObjectURL(imageRef.current) : URL.createObjectURL(inputFile);
        loadImage(imgSrc).then((image) => {
            imageObjRef.current = image;
            drawBgImage();
        });
    }
},[inputFile])

useEffect(() => {
    //console.log("REDRAWN AFTER STATE SET",angle);
    window.requestAnimationFrame(drawBgImage);
},[angle])

useEffect(() => {
    console.log("------------- RENDERING REFERENCEGRID --------------")
    onLoadFunc();
},[])

return (
    <Wrapper>
        <h5>Reference Grid</h5>            
        <input onChange={(e) => onChangeInputFile(e)} type="file" id="input-img" accept=".png,.jpg,.jpeg"></input>
        <button hidden={!inputFile} onClick={() => setEditimage(!editimage)}>{editimage ? "Bild sichern" : "Bild bearbeiten"}</button>
        {  editimage &&
            <input type="number" step="0.01" min="-180" max="180" value={angle} onChange={(e) => setAngle(e.target.value)} placeholder="Winkel"></input>
        }
        <CanvasWrapper>
            <Canvas ref={bgCanvasRef} id="bgCanvas"></Canvas>
        </CanvasWrapper>
    </Wrapper>
)
  }

  export default ReferenceGrid

我想在滚动鼠标滚轮时更改 bgCanvas 的上下文,以便将其转换为另一个比例。 我现在的问题是,当我尝试缩放/变换时,更改角度时画布的上下文与上下文发生冲突。 为了转换画布上下文,我应该在绘制图像之前恢复保存的上下文。但是为了通过用户输入绘制旋转的图像,必须在我这样绘制图像后恢复上下文:

context.save();

// Use the identity matrix while clearing the canvas
context.setTransform(1,0);
context.clearRect(0,canvas.width,canvas.height);

// Restore the transform
context.restore();

// Draw on transformed context    
context.drawImage(imageObj,300,300);

那么现在我如何设置我的 bgCanvas 的上下文,这样既可以在用户输入角度上旋转,又可以在用户滚动时进行变换和“缩放”?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...