Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drag and drop doesn’t work with SVG elements #395

Closed
shunxing opened this issue Feb 27, 2016 · 7 comments
Closed

Drag and drop doesn’t work with SVG elements #395

shunxing opened this issue Feb 27, 2016 · 7 comments
Labels

Comments

@shunxing
Copy link

Hi everyone,
I'm new in React so I haven't get used to its way of thinking.

I'm trying to create a network editor with react. I would like to drag and drop svg circles like d3js.

I cloned the repository and begin from the "Naive Drag Around" example.
I replaced the two div by two different circles and modify the source code into a ES6 format.

On firefox 38.0.5, I can drag these circles. However, after dragging the first circle, I have to CLICK first on the second circle. Then I can drag the second one. It seems like it activates the future dragging when I click on it.

On Chrome Version 48.0.2564.116 (64-bit), it was possible to drag the node sometimes (the circles weren't reacting everytime, I should click somewhere randomly on the svg before dragging) when I was in ES7 format. After encoding to ES6, the dragging doesn't work.

I've rendered first my GraphEditor where I wrapped the DragDropContext.

class GraphEditor extends Component {
 constructor(props) {
    super(props);
  }
  render() {
      return (<Container />)
   }     
}
export default DragDropContext(HTML5Backend)(GraphEditor);

Then I got my svgContainer where I Wrapped as my DropTarget.

const boxTarget = {
  drop(props, monitor, component) {
    const item = monitor.getItem();
    const delta = monitor.getDifferenceFromInitialOffset();
    const left = Math.round(item.left + delta.x);
    const top = Math.round(item.top + delta.y);
    component.updateCircle(item.id, left, top);
  }
};

class Container extends Component {
  constructor(props) {
    super(props);
    this.state = {
      boxes: {
        'a': { top: 20, left: 80, title: 'Drag me around' },
        'b': { top: 180, left: 20, title: 'Drag me too' }
      }
    };
  }

  updateCircle(id, left, top) {
    this.setState(update(this.state, {
      boxes: {
        [id]: {
          $merge: {
            left: left,
            top: top
          }
        }
      }
    }));
  }

  render() {
    const { connectDropTarget } = this.props;
    const { boxes} = this.state;
    return connectDropTarget(
      <svg style={stylesvg}>
        {Object.keys(boxes).map(key => {
          const { left, top } = boxes[key];
          return (
            <Graphic key={key}
                 id={key}
                 left={left}
                 top={top}/>
          );
        })}
      </svg>
    );
  }
}

Container.propTypes = {
    connectDropTarget: PropTypes.func.isRequired
  };
export default DropTarget(ItemTypes.CIRCLE, boxTarget, connect => ({
  connectDropTarget: connect.dropTarget()
}))(Container);

Inside this svgContainer, I got 2 elements in which I got one wrapped as a DragSource

const boxSource = {
  beginDrag(props) {
    const { id, left, top } = props;
    return { id, left, top };
  }
};

class Circle extends Component {
  render() {
    const { hideSourceOnDrag, left, top, connectDragSource, isDragging, children } = this.props;
    console.log(this.props)
    if (isDragging && hideSourceOnDrag) {
      return null;
    }
    return connectDragSource(
        <circle cx={left} cy={top} r="40" stroke="black" fill="red"> </circle>
    );
  }
}

export default DragSource(ItemTypes.CIRCLE, boxSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
  isDragging: monitor.isDragging()
}))(Circle)

Is it how I've written the code or the SVG elements which could not work with react-dnd?

I found some issues with svg and react facebook/react#3192

where does my random circles dragging come from ?

@gaearon
Copy link
Member

gaearon commented Feb 28, 2016

Can you please share a complete project reproducing the issue? Otherwise it’s hard to guess what went wrong.

On firefox 38.0.5, I can drag these circles. However, after dragging the first circle, I have to CLICK first on the second circle. Then I can drag the second one. It seems like it activates the future dragging when I click on it.

Are there any errors in the console?

it was possible to drag the node sometimes when I was in ES7 format. After encoding to ES6, the dragging doesn't work.

There can be no difference in behavior between using ES6 or decorators. If there is a difference it means there is a mistake in the ES6 code.

Is it how I've written the code or the SVG elements which could not work with react-dnd?

To be honest I wouldn’t be surprised if HTML5 drag and drop API (which is what https://github.com/gaearon/react-dnd-html5-backend uses under the hood) doesn’t work well with SVG elements. Try replacing them with divs and see if the issue persists. If it is solved then unfortunately this is due to broken browser support of drag and drop for SVG elements, and you can use onMouseMove manually without React DnD or write a custom react-dnd-mousemove-backend.

@shunxing
Copy link
Author

Can you please share a complete project reproducing the issue? Otherwise it’s hard to guess what went wrong.

https://github.com/shunxing/react-dnd-svg
Here's the full project I created. Sorry for different mistakes I made in my code and unused variables because I'm trying all the logic of react (and also integrating redux after)

Are there any errors in the console?

No error... I just log in the console when I drag the circle and this log doesn't appear when I click for the first time ("to activate it")

Try replacing them with divs and see if the issue persists.

When I cloned the example from Github where you got div inside, it works perfectly. No problem with my browser.
By the way, it also works when I put a static svg circle inside a draggable div

@gaearon
Copy link
Member

gaearon commented Feb 28, 2016

Yep, apparently HTML5 drag and drop API doesn’t work on SVG elements.

So you can either use React DnD with a custom backend a la https://github.com/yahoo/react-dnd-touch-backend/ (except you’d handle mousemove instead), use some other library, or use onMouseMove directly. Or you can wrap your svg elements in divs.

@gaearon gaearon closed this as completed Feb 28, 2016
@gaearon gaearon changed the title Drag working weirdly Drag and drop doesn’t work with SVG elements Feb 28, 2016
@benjamine
Copy link

@gaearon d3-drag seems to be doing drag n drop with SVG, in case it works as inspiration.

@masonk
Copy link

masonk commented Dec 18, 2016

The touch backend with mouse events enabled works well with svg elements. I don't know what bugginess they're warning about in the docs, but I assume that if it's a fundamental limitation of the non-native HTML5 API, then d3 will suffer from the same thing.

@LinusU
Copy link

LinusU commented Feb 20, 2017

This backend seems to work nice for SVG elements: https://github.com/zyzo/react-dnd-mouse-backend

@ig43
Copy link

ig43 commented Aug 3, 2017

LinusU: Thank you for raising awareness of the Mouse Backend. I had been struggling with SVG DND for a couple of days, having already got it working with non-svg elements. It now works perfectly in my app!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants