如何使用组的旋转属性旋转组,并通过react在Konva.js中准确地重新定位

时间:2018-08-04 18:10:11

标签: konvajs

首先,谢谢您抽出宝贵的时间回答我的问题。

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

pic

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>
    )
}

}

这些问题困扰了我几天,如果有人可以回答我的问题,我会提出来

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

尝试遵循解决方案,因为我遇到了同样的问题。鼠标从哪里介入?我有一个旋转按钮,但是当我旋转较高级别的Konva Images时,位置似乎会改变。我注意到x,y相同,但是x,y位置在视觉上是不同的。

如果Bhargav Rao不会无故删除我的信息,则更愿意。 谢谢

示例:

pic 1

pic 1