Edit in JSFiddle

Util = (new function() {
    this.circleAt = function(context, point,radius) {
        context.save();
        context.beginPath();
        context.arc(point.x, point.y, radius, 0, 2 * Math.PI, false);
        context.fill();
        context.restore();
    };
    
    this.drawArrowHead = function(context, from, to) {
        var headlen = 10;   // length of head in pixels
        var angle = Math.atan2(to.y-from.y,to.x-from.x);
        var alx = to.x-headlen*Math.cos(angle-Math.PI/6),
            aly = to.y-headlen*Math.sin(angle-Math.PI/6);
            
        var arx = to.x-headlen*Math.cos(angle+Math.PI/6),
            ary = to.y-headlen*Math.sin(angle+Math.PI/6);
            
        var asx = to.x-headlen*.7*Math.cos(angle),
            asy = to.y-headlen*.7*Math.sin(angle);
        context.moveTo(to.x,to.y);
        context.lineTo(alx,aly);
        context.lineTo(asx,asy);
        context.lineTo(arx,ary);
        context.lineTo(to.x,to.y);
        context.fill();
    };
    
    this.slope=function(from,to) {
        return Math.abs((from.y-to.y) / (from.x-to.x));
    };
    
    return this;
});


function Basic3ByPortModel() {
    return this;
}

    
Basic3ByPortModel.prototype.centerOfRect = function(r) {
    return {
        x: r.left + ((r.right - r.left) / 2), 
        y: r.top + ((r.bottom-r.top)/2)
    };
};

Basic3ByPortModel.prototype.rightCenterOfRect = function(rect) {
    return {
        x: rect.right, 
        y: this.centerOfRect(rect).y
    };
};
    
Basic3ByPortModel.prototype.leftCenterOfRect = function(rect) {
        return {
            x: rect.left, 
            y: this.centerOfRect(rect).y
        };
    };
    
Basic3ByPortModel.prototype.topCenterOfRect = function(rect){
        return {
            x: this.centerOfRect(rect).x,
            y: rect.top
        };
    };
    
Basic3ByPortModel.prototype.bottomCenterOfRect = function(rect){
        return {
            x: this.centerOfRect(rect).x,
            y: rect.bottom
        };
    };
Basic3ByPortModel.prototype.calculateSlot = function(r1,r2) {
    var m = this.marker(this.centerOfRect(r1).y, this.centerOfRect(r2).y) 
        + this.marker(this.centerOfRect(r1).x, this.centerOfRect(r2).x);
    return m;
};
Basic3ByPortModel.prototype.marker = function(fromValue, toValue) {
    if (fromValue === toValue) {
        return "=";
    } else if (toValue < fromValue) {
        return "<";
    } else {
        return ">";
    }
};
Basic3ByPortModel.prototype.getPorts = function(r1,r2) {
    
    // find the port locations that would be used to connect
    // two rects.
    var toslots = {
        "<<" : { from: this.leftCenterOfRect.bind(this), to: this.rightCenterOfRect.bind(this) },
        "<<+" : { from: this.leftCenterOfRect.bind(this), to: this.bottomCenterOfRect.bind(this) },
        "<=" : { from: this.topCenterOfRect.bind(this), to: this.bottomCenterOfRect.bind(this) },
        "<>" : { from: this.rightCenterOfRect.bind(this), to: this.leftCenterOfRect.bind(this) },
        "<>+" : { from: this.rightCenterOfRect.bind(this), to: this.bottomCenterOfRect.bind(this) },
        "=<" : { from: this.leftCenterOfRect.bind(this), to: this.rightCenterOfRect.bind(this) },
        "==" : {},
        "=>" : { from: this.rightCenterOfRect.bind(this), to: this.leftCenterOfRect.bind(this) },
        "><" : { from: this.leftCenterOfRect.bind(this), to: this.rightCenterOfRect.bind(this) },
        "><+" : { from: this.leftCenterOfRect.bind(this), to: this.topCenterOfRect.bind(this) },
        ">=" : { from: this.bottomCenterOfRect.bind(this), to: this.topCenterOfRect.bind(this) },
        ">>": { from: this.rightCenterOfRect.bind(this), to: this.leftCenterOfRect.bind(this) },
        ">>+": { from: this.rightCenterOfRect.bind(this), to: this.topCenterOfRect.bind(this) }
    };
    var slot = this.calculateSlot(r1,r2);
    var ports = [
        toslots[slot].from(r1),
        toslots[slot].to(r2)
    ];
    var s = Util.slope(ports[0],ports[1]);
    if (s > 1.5 && s !== Infinity) {
        slot += "+";
    }
    ports = [
        toslots[slot].from(r1),
        toslots[slot].to(r2)
    ];
    return ports;
};





var ProgressBar = React.createClass({
    mixins: [React.addons.PureRenderMixin],
    render: function() {
        return <div className="progress">{this.props.percent}%</div>;
    }
});
var Pill = React.createClass({
    props:{},
    render: function() {
        return (<div onClick={this.clicked} className="pill" id={this.props.id}><span>{this.props.id}</span></div>);
    },
    clicked: function(evt) {
        alert('clicked ' + this.props.id);
    }
});
var FeatureBreakdownGrid = React.createClass({
    render: function() {
        return (
        <table id="tbl">
            <tr>
                <th></th>
                <th>Iteration 1</th>
                <th>Iteration 2</th>
                <th>Iteration 3</th>
                <th>Iteration 4</th>
            </tr>
            <tr>
                <td>Name 0</td>
                <td><ProgressBar percent="23"/></td>
                <td></td>
                <td><ProgressBar percent="23"/></td>
                <td><ProgressBar percent="23"/></td>
            </tr>
            <tr>
                <td></td>
                <td><Pill id="F0"/></td>
                <td></td>
                <td><Pill id="F1"/></td>
                <td><Pill id="F2"/></td>
            </tr>
            <tr>
                <td>Whoever</td>
                <td><ProgressBar percent="23"/></td>
                <td></td>
                <td></td>
                <td><ProgressBar percent="23"/></td>
            </tr>
            <tr>
                <td></td>
                <td><Pill id="F3"/></td>
                <td></td>
                <td></td>
                <td><Pill id="F5"/></td>
            </tr>
        
            <tr>
                <td>Name 1</td>
                <td></td>
                <td></td>
                <td><ProgressBar percent="23"/></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td>
                    <Pill id="F123"/>
                </td>
                <td></td>
            </tr>
        
            <tr>
                <td>Name 2</td>
                <td><ProgressBar percent="23"/></td>
                <td></td>
                <td><ProgressBar percent="23"/></td>
                <td><ProgressBar percent="23"/></td>
            </tr>
            <tr>
                <td></td>
                <td><Pill id="F6"/></td>
                <td></td>
                <td><Pill id="F7"/></td>
                <td><Pill id="F8"/></td>
            </tr>
        </table>
        );
    }
});




var DependenciesOverlay = React.createClass({
    props: {
        highlight:React.PropTypes.bool,
        visible:React.PropTypes.bool
    },
    updateDimensions: function() {
        this.setState(
            {width: $(window).width(), height: $(window).height()}
        );
    },
    componentWillMount: function() {
        this.updateDimensions();
    },
    componentWillUnmount: function() {
        window.removeEventListener("resize", this.updateDimensions);
    },
    render: function() {
        var style = {
            position: "absolute",
            zIndex: 300
        }
//        style.pointerEvents = 'none';
        if (this.props.highlight) {
            style.backgroundColor = 'red';
        }
        var children = React.addons.cloneWithProps(this.props.children, {
            ref:"grid"
        });
        return (<div><canvas onClick={this.propagateClick} ref="canvas" style={style} id="can"></canvas>{children}</div>);
    },
    componentDidUpdate: function ( prevProps,  prevState) {
        this.drawOverlay();
    },
    propagateClick: function(evt) {
        console.log("propagateClick",evt);
        var canvas = this.refs.canvas.getDOMNode();
        var d = canvas.style.display;
        canvas.style.display = 'none';

        var under = document.elementFromPoint(evt.clientX, evt.clientY);
        canvas.style.display = d;
        under.click(evt);
    },
    componentDidMount: function() {
        window.addEventListener("resize",
            this.updateDimensions);
        this.updateDimensions();
    },
    drawOverlay: function() {
        var grid = this.refs.grid.getDOMNode();
        var gridRect = grid.getBoundingClientRect();

        var canvas = this.refs.canvas.getDOMNode(),
            context = canvas.getContext('2d');
        canvas.width = gridRect.width;
        canvas.height = gridRect.height;
        canvas.style.left = (gridRect.left+window.scrollX) + "px";
        canvas.style.top = (gridRect.top+window.scrollY) + "px";

        if (!this.props.visible) return;
        context.save();
        // account for scrolled content
        var x = this.props.deps.map(function(d) {
            return d.split("->");
        }).filter(function(d) {
            return !!!this.props.dep || d[0] === this.props.dep;
        }.bind(this));
        context.translate(-gridRect.left,-gridRect.top);
        x.forEach(function(d) {
            this.drawDependencies(context, d[0], d[1]);
        }.bind(this));
        context.restore();
     },
     
     
     
    drawDependencies: function(context, fromid, toid) {
        var fromElement = document.getElementById(fromid);
        var toElement = document.getElementById(toid);
        var ports = new Basic3ByPortModel().getPorts(
            fromElement.getBoundingClientRect(),
            toElement.getBoundingClientRect());
        ports[0].name = fromid;
        ports[1].name = toid;
        this.drawDependencyLine(context, ports[0], ports[1]);
    },
    

    drawDependencyLine: function(context, from, to) {
        context.save();
        context.beginPath();
        if (context.setLineDash) {
            context.setLineDash([5,2]);
        }
        context.moveTo(from.x, from.y);
        context.lineTo(to.x, to.y);
        context.lineWidth=2;
        context.stroke();
        context.restore();
        Util.circleAt(context, from,3);
        Util.drawArrowHead(context, from, to);
    }
});

var Page = React.createClass({
    getInitialState: function() {
        return {
            highlight:false,
            visible:true
        };
    },
    render: function() {
        return (<div>
            <DependenciesOverlay visible={this.state.visible} highlight={this.state.highlight} dep={""} deps={this.props.deps}>
                <FeatureBreakdownGrid/>
            </DependenciesOverlay>
            <button onClick={this.toggleHighlight}>Toggle Canvas BG</button>
            <button onClick={this.toggleVisible}>Toggle Visible</button>
        </div>);
    },
    toggleHighlight: function() {
        var s = this.state;
        s.highlight = !s.highlight;
        this.setState(s);
        console.log("state",s);
    },
    toggleVisible: function() {
        var s = this.state;
        s.visible = !s.visible;
        this.setState(s);
        console.log("state",s);
    }    
});
var deps = Immutable.List()
    .push("F123->F8")
    .push("F123->F0")
    .push("F123->F1")
    .push("F123->F2")
    .push("F123->F3")
    .push("F123->F5")
    .push("F123->F6")
    .push("F123->F7")
    .push("F123->F8")
    .push("F6->F7")
    .push("F1->F0");    


    
React.render(<Page deps={deps}/>, document.body);

<div id="output"></div>
<script src="https://fb.me/react-js-fiddle-integration.js"></script>