<div id="root"></div>
class Sample extends React.Component {
  constructor() {
    super();
    this.state = {points: [
      {x: 30, y: 900},
      {x: 30, y: 30},
      {x: 900, y: 30},
      {x: 900, y: 900},
    ]};
  }
  
  render() {
    const points = this.state.points;
    return (
      <svg viewBox="0 0 1000 1000" ref={(svg) => this.svg = svg}>
        <path
          d={`M ${points[0].x} ${points[0].y} C ${points[1].x} ${points[1].y}, ${points[2].x} ${points[2].y}, ${points[3].x} ${points[3].y}`}
          fill="transparent"
          stroke="blue"
          strokeWidth="3"
        />
        <path
          d={`M ${points[0].x} ${points[0].y} L ${points[1].x} ${points[1].y} M ${points[2].x} ${points[2].y} L ${points[3].x} ${points[3].y}`}
          fill="transparent"
          stroke="gray"
          strokeWidth="2"
        />
        {
          points.map((point, i) => (
            <g transform="translate(-15, -15)">
              <rect
                x={point.x}
                y={point.y}
                key={i}
                width="30"
                height="30"
                onMouseDown={(e) => this.startDrag(e, i)}
              />
            </g>
          ))
        }
      </svg>
    );
  }
  
  startDrag = (event, index) => {
    event.preventDefault();
    
    const mousemove = (event) => {
      event.preventDefault();
      let cursorPoint = this.svg.createSVGPoint();
      cursorPoint.x = event.clientX;
      cursorPoint.y = event.clientY;
      cursorPoint = cursorPoint.matrixTransform(this.svg.getScreenCTM().inverse());
      this.setState({
        points: this.state.points.map(
          (p, i) => (index === i ? {
            x: Math.max(Math.min(cursorPoint.x, 1000), 0),
            y: Math.max(Math.min(cursorPoint.y, 1000), 0)
          } : p))
      })
    };
    
    const mouseup = (event) => {
      document.removeEventListener("mousemove", mousemove);
      document.removeEventListener("mouseup", mouseup);
    };
    
    document.addEventListener("mousemove", mousemove);
    document.addEventListener("mouseup", mouseup);
  };
}

ReactDOM.render(
  <Sample/>,
  document.getElementById('root')
);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js