首页 > 解决方案 > 反应 konva 在舞台上放大时保持一层固定

问题描述

我正在 Konva 中开发地图(绿色矩形)和在其上绘制的路径(黑线):

在此处输入图像描述

地图具有固定尺寸,而路径是从 API 调用中获取的。

我希望能够使用鼠标滚动或单击我创建的按钮 + o 来缩放地图。

我按照这个示例如何对滚动进行 react-konva 缩放以实现缩放,但是当我滚动时,按钮也会改变它们的位置,见下图。

在此处输入图像描述

我想将按钮固定在地图的底部。

这是我的一段代码,我定义了一些自定义组件为MapGroundWholePathGroundButtonsButton

export const Map = ( props ) => {
    const [mouseScale, setMouseScale] = useState(1);
    const [x0, setX0] = useState(0);
    const [y0, setY0] = useState(0);

    const scaleBy = 1.02;
    const handleWheel = (e)  => {
      const group = e.target.getStage();
      e.evt.preventDefault();
      const mousePointTo = {
        x: group.getPointerPosition().x / mouseScale - group.x() / mouseScale,
        y: group.getPointerPosition().y / mouseScale - group.y() / mouseScale
      };
      const newScale = e.evt.deltaY < 0 ? mouseScale * scaleBy : mouseScale / scaleBy;
      setMouseScale(newScale);
      setX0(-(mousePointTo.x - group.getPointerPosition().x / newScale) * newScale );
      setY0(-(mousePointTo.y - group.getPointerPosition().y / newScale) * newScale );
    };

    const SimulateMouseWheel = (e, BtnType, mScale = scaleBy) => {
      const newScale = BtnType > 0 ? mouseScale * mScale : mouseScale / mScale;
      setMouseScale(newScale);
    };

    const onClickPlus = (e) => {
        SimulateMouseWheel(e, +1, 1.08);
    };

    const onClickMinus = (e) => {
        SimulateMouseWheel(e, -1, 1.08);
    };

    return (
        <Stage
            width={800}
            height={400}
            draggable={true}
            onWheel={handleWheel}
            scaleX={mouseScale}
            scaleY={mouseScale}
            x={x0}
            y={y0}
        >
            <Layer>
                <Ground pitch={props.pitch}/>
                <WholePath path={props.path}/>
            </Layer>
            <Layer>
                <GroundButtons reference={props.reference} onClickMinus={onClickMinus} onClickPlus={onClickPlus} />
            </Layer>
        </Stage>
    )
}


const GroundButtons = ( props ) => {
    return (
        <Group>
            <Button xText={10} yText={5} text={"+"} x={790} y={360}  side={30} onClick={props.onClickPlus}/>
            <Button xText={12} yText={5} text={"-"} x={790} y={360}  side={30} onClick={props.onClickMinus}/>
        </Group>
    )
}

const Button = props => {
    return (
            <Group x={props.x} y={props.y} onClick={props.onClick}>
                <Rect
                    width={props.side}
                    height={props.side}
                    fill='#f2f1f0'
                    stroke='#777'
                    strokeWidth={1}
                />
                <Text
                  x={props.xText}
                  y={props.yText}
                  fontSize={20}
                  text={props.text}
                  stroke='#777'
                  align="center"
                  strokeWidth={1}
                />
            </Group>
    )
}

这是我实施的解决方案: 感谢 Ondolin 的回答。

export const Map = ( props ) => {
    const [mouseScale, setMouseScale] = useState(1);
    const [x0, setX0] = useState(0);
    const [y0, setY0] = useState(0);

    const scaleBy = 1.02;
    const handleWheel = (e)  => {
      const group = e.target.getStage();
      e.evt.preventDefault();
      const mousePointTo = {
        x: group.getPointerPosition().x / mouseScale - group.x() / mouseScale,
        y: group.getPointerPosition().y / mouseScale - group.y() / mouseScale
      };
      const newScale = e.evt.deltaY < 0 ? mouseScale * scaleBy : mouseScale / scaleBy;
      setMouseScale(newScale);
      setX0(-(mousePointTo.x - group.getPointerPosition().x / newScale) * newScale );
      setY0(-(mousePointTo.y - group.getPointerPosition().y / newScale) * newScale );
    };

    const SimulateMouseWheel = (e, BtnType, mScale = scaleBy) => {
      const newScale = BtnType > 0 ? mouseScale * mScale : mouseScale / mScale;
      setMouseScale(newScale);
    };

    const onClickPlus = (e) => {
        SimulateMouseWheel(e, +1, 1.08);
    };

    const onClickMinus = (e) => {
        SimulateMouseWheel(e, -1, 1.08);
    };

    return (
        <div>
        <Stage
            width={800}
            height={400}
            draggable={true}
            onWheel={handleWheel}
            scaleX={mouseScale}
            scaleY={mouseScale}
            x={x0}
            y={y0}
        >
            <Layer>
                <Ground pitch={props.pitch}/>
                <WholePath path={props.path}/>
            </Layer>
            <Layer>
                <GroundButtons reference={props.reference} onClickMinus={onClickMinus} onClickPlus={onClickPlus} />
            </Layer>
        </Stage>
            <button className="ground_controls" onClick={onClickPlus}><i className="fa fa-plus" aria-hidden="true"></i></button>
            <button className="ground_controls" onClick={onClickMinus}><i className="fa fa-minus" aria-hidden="true"></i></button>
        </div>
    )
}

标签: reactjskonvajsreact-konvakonvakonvajs-reactjs

解决方案


我强烈建议您不要使用在画布(舞台)上绘制的按钮。您应该使用标准的 HTML 按钮。您可以使用 css(绝对位置)将它们放置在舞台顶部。

如果你这样做,对你有很多好处。例如,您可以更轻松更好地设计它。此外,它更高效,也解决了这个问题的问题。


推荐阅读