【问题标题】:How to use the rotation properties of the group to rotate the group ,and reposition it exactly in Konva.js with react如何使用组的旋转属性来旋转组,并在 Konva.js 中使用 react 重新定位它
【发布时间】:2019-01-12 06:36:38
【问题描述】:

首先,感谢您花时间回答我的问题。

我正在为一个小型图像编辑器项目工作,基于 konva.js 和 react。但是我遇到了一些问题,困扰了我几天。 我想使用组的旋转属性来旋转组和其中的所有形状,当单击旋转按钮时,它可以正常工作,但是当我单击文本按钮并想在图像上绘制它并重新定位时确切地说,pic1 是我的预期结果,但实际上,我得到了意想不到的结果显示为 pic2,我该怎么做才能准确地旋转组和其中的所有形状。

我的简单示例如下所示:

class Test extends React.Component{

    constructor(props) {
        super(props)
        this.state = {
            historyArray: [],
            isTexting: true,
            image: new window.Image(),
            layerPos:{
                x: 300,
                y: 100,
            },
            imageWidth: 0,
            imageHeight: 0,
            rotateDegrees: 0,
        }
    }
    componentDidMount() {

        const {historyArray} = this.state;
        this.state.image.setAttribute("crossOrigin", "anonymous");
        this.state.image.src = "https://vd.youniwote.com/homework/44evmey2cbd/submit/44evmey2cbe.jpg";
        this.state.image.onload = () => {
            let imageWidth = this.state.image.width > 620 ? 620 / (parseFloat(this.state.image.height) / parseFloat(this.state.image.width)) : this.state.image.width;
            let imageHeight = this.state.image.height > 620 ? 620 : this.state.image.height;
            let imageObj = {
                mode: 'image',
                image: this.state.image,
                width: imageWidth,
                height: imageHeight,
            }
            historyArray.push(imageObj);
            this.setState({
                historyArray,
                imageWidth,
                imageHeight,
            })
        }
    }
    clickStage = (event) => {
        const {mode, isTexting, historyArray} = this.state;
        if (mode == 'text') {
            if (isTexting) {
                let textarea = document.createElement('textarea');
                document.body.appendChild(textarea);
                textarea.style.position = 'absolute';
                textarea.style.top = event.evt.pageY + 'px';
                textarea.style.left = event.evt.pageX + 'px';
                textarea.style.width = 100;
                textarea.focus();

                this.setState({
                    isTexting: false,
                })

                textarea.addEventListener('keydown',  (e) => {
                    if (e.keyCode === 13) {
                        historyArray.push({
                            mode: "text",
                            x:this.getActualPosInStage(event).x,
                            y: this.getActualPosInStage(event).y,
                            text: textarea.value,
                        })

                        document.body.removeChild(textarea);
                        this.setState({
                            isTexting: true,
                            historyArray
                        })
                    }
                });
            }
        }
    }

    getActualPosInStage = (e) => {
        const {layerPos} = this.state;
        let stageBox = this.stage.getStage().getContainer().getBoundingClientRect();
        let mousePos = {
            x: e.evt.clientX,
            y: e.evt.clientY,
        }
        let x = Math.abs(mousePos.x - stageBox.left - layerPos.x);
        let y = Math.abs(mousePos.y - stageBox.top - layerPos.y);
        return {x,y}
    }
    render() {
        return (
            <div>
                <div style={{top: 0, left: 0}}>
                    <Button onClick={() => {
                        this.setState({
                            mode: 'text',
                            groupDraggable: false,
                        })
                    }}>Text</Button>

                    <Button style={{marginLeft: 20}} onClick={() => {
                        const {rotateDegrees} = this.state;
                        this.setState({
                            rotateDegrees: rotateDegrees + 90,
                            groupDraggable: false,
                            mode: 'rotate',
                        })

                        this.group.offsetX(this.group.width() / 2);
                        this.group.offsetY(this.group.height() / 2);

                        this.group.x(this.group.width() / 2);
                        this.group.y(this.group.height() / 2);

                    }}>Rotate</Button>
                </div>
                <Stage
                    onClick={(e) => {this.clickStage(e)}}
                    width={1000}
                    height={1000}
                    ref={node => {
                        this.stage = node;
                    }}
                >
                    <Layer
                        x={this.state.layerPos.x}
                        y={this.state.layerPos.y}
                        ref={node => {
                            this.layer = node;
                        }}
                    >
                        <Group
                            rotation={this.state.rotateDegrees}
                            width={this.state.imageWidth}
                            height={this.state.imageHeight}
                            ref={node => {
                                this.group = node;
                            }}
                        >
                            {
                                this.state.historyArray.map((item, index) => {
                                    if (item.mode == 'image') {
                                        return (
                                            <Image
                                                key={index}
                                                width={item.width}
                                                height={item.height}
                                                image={this.state.image}
                                                ref={node => {
                                                    this.imageNode = node;
                                                }}
                                            />
                                        )
                                    } else if (item.mode == 'text') {
                                        return(
                                            <Text
                                                key={index}
                                                x={item.x}
                                                y={item.y}
                                                text={item.text}
                                                fontSize={24}
                                                fill='red'
                                            />
                                        )
                                    }
                                })
                            }
                        </Group>
                    </Layer>
                </Stage>
            </div>
        )
    }
}

这些问题困扰了我好几天,如果有人能回答我的问题,我会感谢它

【问题讨论】:

标签: konvajs


【解决方案1】:

作为文本的位置,您需要使用相对于组的位置。在您的代码中,您使用的是相对于舞台左上角的位置。它给你不正确的结果,因为你的组被移动和旋转。

所以你需要计算相对于组的位置。简单的方法是将组的绝对变换矩阵反转并应用于鼠标点:

const stage = e.target.getStage();
const pos = stage.getPointerPosition();

const absTransform = this.group.getAbsoluteTransform();

const invertedTransform = new Konva.Transform(
  absTransform.getMatrix()
).invert();

const shapePos = invertedTransform.point(pos);

演示:https://codesandbox.io/s/l2k4k3y7n9

【讨论】:

  • 它有效,非常感谢您的帮助。你为我节省了很多时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-10
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
相关资源
最近更新 更多