React Konva Transformer Error "Невозможно прочитать свойство 'getStage' из неопределенного" - PullRequest
1 голос
/ 14 февраля 2020

Я использую Konva 4.0.18 в React 16.8. Приложение, которое хорошо работает до сих пор в автономном режиме (CRA). При интеграции этого рабочего решения в существующий фрейм приложения я сталкиваюсь с ошибкой, которая появляется при преобразовании прямоугольника (и постоянно появляется при перемещении мыши, даже если преобразование прямоугольника прекращается при повторном нажатии):

Transformer. js: 316 Uncaught TypeError: Невозможно прочитать свойство 'getStage' undefined в e._handleMouseMove (Transformer. js: 316) при событиях по умолчанию-пассивных. js: 6

Снимок экрана отладчика в функции 'findOne', который возвращает 'undefined'

Существует компонент Masking, который импортирует Stage, Layout и * 1014 Конвы * а также MaskingRectangle, который может быть преобразован.

import React, { useState, useEffect, useRef } from "react";
import MaskingRectangle from "./maskingRectangle";

const Masking = ({ canvas }) => {
    const stageWrapperRef = useRef(null);
    const [stageWidth, setStageWidth] = useState(600);
    const [stageHeight, setStageHeight] = useState(400);
    const [maskingRectangles, setMaskingRectangles] = useState([]);
    const [shapes, setShapes] = useState([]);
    const [selectedId, selectShape] = useState(null);

    const [Stage, setStage] = useState(null);
    const [Layer, setLayer] = useState(null);
    const [Image, setImage] = useState(null);

    const addRectangle = e => {
        const getRandomInt = max => {
            return Math.floor(Math.random() * Math.floor(max));
        };
        let rectX = getRandomInt(100);
        let rectY = getRandomInt(100);
        if (e) {
            const { x, y } = e.currentTarget.getPointerPosition();
            rectX = x;
            rectY = y;
        }

        const rect = {
            x: rectX,
            y: rectY,
            width: 100,
            height: 100,
            fill: "rgba(255,0,0,0.4)",
            id: `rect${maskingRectangles.length + 1}`
        };
        const rects = maskingRectangles.concat([rect]);
        setMaskingRectangles(rects);
        const shs = shapes.concat([`rect${maskingRectangles.length + 1}`]);
        setShapes(shs);
    };

    const deleteActiveRectangle = () => {
        setMaskingRectangles(
            maskingRectangles.filter(rect => rect.id !== selectedId)
        );
        setShapes(shapes.filter(shape => shape !== selectedId));
        selectShape(null);
    };

    const onStageClick = e => {
        if (e.target.attrs.className !== "mask-rect") {
            selectShape(null);
        }
    };

    const onStageDblClick = e => {
        const stage = e.target.parent.parent;
        const elem = e.currentTarget;

        if (elem.clickStartShape.attrs.className !== "mask-rect") {
            addRectangle(e);
        }

        if (elem.clickStartShape.attrs.id === selectedId) {
            deleteActiveRectangle();
            stage.container().style.cursor = "crosshair";
        }
    };

    useEffect(() => {
        async function loadKonvaModules() {
            await import("react-konva").then(module => {
                setStage(() => module.Stage);
                setLayer(() => module.Layer);
                setImage(() => module.Image);
            });
        }
        loadKonvaModules();
        const scaleX = stageWrapperRef.current.clientWidth / canvas.width;
        const scaleY = stageWrapperRef.current.clientHeight / canvas.height;
        const scalingFactor = Math.min(scaleX, scaleY);
        setStageWidth(canvas.width * scalingFactor);
        setStageHeight(canvas.height * scalingFactor);
    }, []);

    return (
        <div>
            <div className="stage-wrapper" ref={stageWrapperRef}>
                <Stage
                    className="stage"
                    width={stageWidth}
                    height={stageHeight}
                    onClick={onStageClick}
                    onDblClick={onStageDblClick}
                >
                    <Layer className="layer1">
                        <Image
                            image={canvas}
                            width={stageWidth}
                            height={stageHeight}
                        />

                        {maskingRectangles.map((rect, i) => {
                            return (
                                <MaskingRectangle
                                    key={i}
                                    shapeProps={rect}
                                    isSelected={rect.id === selectedId}
                                    onSelect={() => {
                                        selectShape(rect.id);
                                    }}
                                    onChange={newAttrs => {
                                        const rects = maskingRectangles.slice();
                                        rects[i] = newAttrs;
                                        setMaskingRectangles(rects);
                                    }}
                                    onMouseEnter={e => {
                                        const stage = e.target.parent.parent;
                                        stage.container().style.cursor = "move";
                                    }}
                                    onMouseOut={e => {
                                        const stage = e.target.parent.parent;
                                        stage.container().style.cursor =
                                            "crosshair";
                                    }}
                                    stageProps={{
                                        width: stageWidth,
                                        height: stageHeight
                                    }}
                                />
                            );
                        })}
                    </Layer>
                </Stage>
            </div>
        </div>
    );
};

export default Masking;

Мой MaskinRectangle componeht выглядит следующим образом:

import React from "react";
import { Rect, Transformer } from "react-konva";

const MaskingRectangle = ({
    shapeProps,
    isSelected,
    onSelect,
    onChange,
    stageProps,
    onMouseEnter,
    onMouseOver,
    onMouseOut,
    onMouseMove
}) => {
    const shapeRef = React.useRef();
    const trRef = React.useRef();

    React.useEffect(() => {
        if (isSelected) {
            trRef.current.setNode(shapeRef.current);
            trRef.current.getLayer().batchDraw();
        }
    }, [isSelected]);

    const dragBoundFunc = pos => {
        //Limit Min/Max x,y position
        const stageWidth = (stageProps && stageProps.width) || 800;
        const stageHeight = (stageProps && stageProps.height) || 600;
        const minX = 0;
        const minY = 0;
        const maxX = stageWidth - shapeRef.current.attrs.width;
        const maxY = stageHeight - shapeRef.current.attrs.height;
        const newX = pos.x < minX ? minX : pos.x > maxX ? maxX : pos.x;
        const newY = pos.y < minY ? minY : pos.y > maxY ? maxY : pos.y;

        return {
            x: newX,
            y: newY
        };
    };

    return (
        <>
            <Rect
                className="mask-rect"
                onClick={onSelect}
                onTap={onSelect}
                ref={shapeRef}
                {...shapeProps}
                draggable
                onTouchMove={null}
                onDragEnd={e => {
                    onChange({
                        ...shapeProps,

                        x: e.target.x(),
                        y: e.target.y()
                    });
                }}
                onTransformEnd={e => {
                    const node = shapeRef.current;
                    const scaleX = node.scaleX();
                    const scaleY = node.scaleY();
                    node.scaleX(1);
                    node.scaleY(1);
                    onChange({
                        ...shapeProps,
                        x: node.x(),
                        y: node.y(),
                        width: node.width() * scaleX,
                        height: node.height() * scaleY
                    });
                    e.evt.preventDefault();
                }}
                dragBoundFunc={dragBoundFunc}
                onMouseOver={onMouseOver}
                onFocus={onMouseOver}
                onMouseEnter={onMouseEnter}
                onMouseOut={onMouseOut}
                onBlur={onMouseOut}
                onMouseMove={onMouseMove}
            />
            {isSelected && <Transformer ref={trRef} rotateEnabled={false} />}
        </>
    );
};

export default MaskingRectangle;

Некоторые мысли / догадки: интересно, почему это отлично работает как отдельное приложение, но не работает, если включено в существующую HTML страницу (которая, кстати, включает в себя также такие библиотеки, как jquery и Angular 1.x).

Может быть, вы можно г Вот несколько советов, как искать или отвечать на один из этих вопросов:

  1. Существует несколько обработчиков событий (click, mousemove), зарегистрированных на теле и других элементах вне самого React App, но они не должно влиять на приложение реакции, или я здесь не прав?
  2. Я вижу упоминание default-passive-events в ошибке. Как это может быть связано с проблемой (и если да, то как этого можно избежать)?
  3. Вероятность возникновения проблемы в библиотеке Konva. js (см. Скриншот прилагается)

Заранее спасибо за любую помощь, комментарии, предложения, где / как искать

...