react-dnd:拖出一条线

react-dnd: drag out a line

我正在构建一个允许用户通过拖放来构建图表的组件。有一个节点井,他们可以在那里拖出新节点,他们可以将节点拖到 canvas 周围,等等

现在,我需要允许它们通过从一个节点的输出端拖动到下一个节点的输入端来创建边。严格来说这不是拖放,因为可拖动对象保持原样,而是显示一条线,该线源自可拖动对象并填充在光标下,直到最终,当用户将鼠标悬停在活动目标上时释放,边缘完成。

拖放似乎几乎我想要的一切。它具有悬停信号,在拖动符合条件的 Draggable 时突出显示放置目标,等等。有两件事我不知道该怎么做。一种是完全阻止可拖动对象移动。我可以通过放置两个元素副本来欺骗它,一个在另一个下面,然后禁用拖动预览,但如果有一个简单的标志会更好。

另一个似乎更像是一个表演者。收集功能不会在我拖动时连续触发事件(我知道,按设计)。我需要一些可以触发 onMouseMove 的东西来继续更新行。由于拖放确实可以完成一些我需要的事情,而且我已经承担了依赖它的大小成本,所以重用它会很棒。

到目前为止,我的最佳想法是在 beginDrag 上安装一个 onMouseMove 处理程序并清理 endDrag 上的行,在 drop 上建立任何新边缘。不幸的是,我认为某些东西正在阻止 mousemove 事件的传播,因为即使我在开始拖动时确实在此处输入 beginDrag,我的处理程序也不会触发。

     let mouseMoveHandler = (ev: JQueryMouseEventObject) => {
       console.log("Draw a line from ", node.position, " to ", { x: ev.clientX, y: ev.clientY });
     };
     console.log("Dragging");
     $("body").on("mousemove", mouseMoveHandler);
     return { id, node, mouseMoveHandler: mouseMoveHandler};
  },
  endDrag: ({id, node}, monitor: DragSourceMonitor) => {
    const item = monitor.getItem() as any;
    $("body").off("mousemove", item.mouseMoveHandler);
  }

我目前正在做的项目涉及相同的事情(绘制图形,使用react-dnd连接边缘)和运行相同的问题。但是我注意到你的假设

The collect function doesn't continuously fire events as I drag

不正确。起初我也是这么想的,但后来我意识到显示卡顿的原因是因为我的 "canvas" 渲染功能太重了。 我按照 the directions 如何优化我的反应渲染功能解决了这个问题,但将我的节点层和 links 层划分为单独的子组件,只有在它们发生变化时才重新渲染。这使我的主要渲染功能更加轻便。然后当我渲染 "pending" link 时。它完美地跟随我的鼠标光标,没有卡顿/卡顿。

这是从我的渲染函数返回的内容:

render() {
    /* 
    Don't do anything heavy in the rendering function (incl, nodelayer and link layer) - even a console.log.
    Otherwise the pending link render will b e choppy. 
    */
    const { renderPendingLink } = this;
    const { connectDropTarget } = this.props;
    const canvas = connectDropTarget(<div style={{ width: '100%', height: '1000px' }} ref={ref => this._canvasRef = ref}>
        <div style={{ position: 'absolute', width: '100%', height: '100%' }}>
            <NodesLayer nodes={this.nodesValuesArray} createLink={this.createLink} />
            <svg style={{ width: '100%', height: '100%' }}>
                <LinksLayer links={this.linksValuesArray} />
                {renderPendingLink()}
            </svg>
        </div>
    </div>)
    return (<div>
        <PanelToolboxWidget />
        {canvas}
    </div>)
}
}

并且:

renderPendingLink() {
    const { item, itemType, isDragging } = this.props;
    if (isDragging && itemType == ItemTypes.PORT) {
        const { port } = item;
        const { currentOffset } = this.props;
        if (!currentOffset | !this._canvasRef) {
            return null;
        }
        return (
            <PendingLinkWidget
                start={port.getPortCenterRelativeToCanvas}
                end={getLocalisedDropCoords(currentOffset, this._canvasRef)}
            />
        )
    }
    return null;
}

LinksLayerWidget 看起来像这样(我正在使用 mobX):

@observer class LinksLayer extends React.PureComponent {
render() {
    const { links } = this.props;
    return (<svg>
        {_.map(links, l => <LinkWidget link={l} key={l.uuid} />)}
    </svg>)
}

}

对我有用,希望对你有帮助。