2016-12-16 2 views
1

Je construis un composant qui permet à l'utilisateur de construire un graphique par glisser-déposer. Il y a un noeud où ils peuvent glisser de nouveaux nœuds, ils peuvent faire glisser les nœuds autour du canevas, etc.réagir-DND: faites glisser une ligne

Maintenant, je dois leur permettre de créer des arêtes en glissant de la sortie d'un nœud au côté d'entrée du nœud suivant. . Strictement parlant, ce n'est pas drag-n-drop, car le draggable reste en place et à la place une ligne doit être affichée à partir du draggable et se remplir sous le curseur, jusqu'à ce que finalement, lorsque l'utilisateur est libéré en survolant une cible active, le bord est terminé. Drag-n-drop semble faire presque tout ce que je veux. Il a le signal de survol, mettant en évidence les cibles de largage lorsqu'un draggable éligible est en train de glisser, et ainsi de suite. Il y a deux choses que je n'arrive pas à comprendre. L'un est d'arrêter le déplacement du tout. Je peux tromper en plaçant deux copies de l'élément, l'une en dessous de l'autre, puis en désactivant l'aperçu de la traînée, mais s'il y a un drapeau simple, ce serait mieux.

L'autre semble plus d'un show-bouchon. La fonction de collecte ne déclenche pas continuellement les événements lorsque je fais glisser (je sais, par conception). J'ai besoin de quelque chose qui se déclenche surMouseMove pour continuer à mettre à jour la ligne. Comme drag-n-drop fait ce dont j'ai besoin, et comme j'ai déjà supporté le coût de la taille, ça serait génial de le réutiliser.

La meilleure idée que je l'ai eu à ce jour est d'installer un gestionnaire onMouseMove sur beginDrag et le nettoyage de la ligne sur endDrag, en établissant tout nouveau bord sur drop. Malheureusement, je pense que quelque chose interrompt la propagation des événements mousemove, car mon gestionnaire ne se déclenche jamais même si j'entre le beginDrag ici quand je commence à glisser.

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

Répondre

0

Le projet sur lequel je travaille actuellement sur implique la même chose (dessiner un graphique, connectez-bords avec réagir DND) et a couru dans le même problème. Cependant, je remarque que votre hypothèse que

La fonction Collect ne se déclenche pas en permanence les événements que je fais glisser

est incorrect. Au début, je le pensais aussi, mais je me suis rendu compte que la raison pour laquelle l'affichage bégayait était parce que ma fonction de rendu «toile» était trop lourde. Je résolu le problème en suivant the directions sur la façon d'optimiser ma réaction rendre la fonction, mais en divisant mon noeuds couche et liens couche en sous distinctes re composant graphique-rendent seulement s'ils ont changé. Cela a rendu ma fonction de rendu principale beaucoup plus légère. Puis, quand j'ai rendu mon lien "en attente". il a suivi mon curseur de souris magnifiquement, sans un bégaiement/jank.

Voici ce qui est retruned de ma rendre fonction:

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

Et:

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

Le LinksLayerWidget ressemble à ceci (j'utilise MOBX):

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

}

Ca marche pour moi, et j'espère que ça t'aide.