var height = 500, width = 900 var svg = d3.select('body').append('svg').attr({width: width, height: height}) var rRadius = height, rPos = [width*3/4, height/2] var rCircleSel = svg.append('circle.large') .attr('r', rRadius) .translate(rPos) var rθ = -Math.PI/4 var rDrag = d3.behavior.drag() .on('drag', function(){ var pos = d3.mouse(rCircleSel.node()) rθ = Math.atan2(pos[0], pos[1]) render() }) var rDragSel = svg.append('rect.drag') .attr({width: 100, height: 20, x: -100, y: -20/2}) .call(rDrag) var lRadius = height, lPos = [width*1/4, height/2] var lCircleSel = svg.append('circle.large') .attr('r', lRadius) .translate(lPos) var lθ = Math.PI/4 var lDrag = d3.behavior.drag() .on('drag', function(){ var pos = d3.mouse(lCircleSel.node()) lθ = Math.atan2(pos[0], pos[1]) render() }) var lDragSel = svg.append('rect.drag') .attr({width: 100, height: 20, x: 0, y: -20/2}) .call(lDrag) var connection = svg.append('path.connection') render() function render(){ lθ = clamp(1.04, lθ, 2.07) lp = [Math.sin(lθ)*lRadius + lPos[0], Math.cos(lθ)*lRadius + lPos[1]] lDragSel.attr('transform', 'translate(' + lp + ') rotate(' + (-lθ + Math.PI/2)*180/Math.PI + ')') rθ = clamp(-2.07, rθ, -1.07) rp = [Math.sin(rθ)*rRadius + rPos[0], Math.cos(rθ)*rRadius + rPos[1]] rDragSel.attr('transform', 'translate(' + rp + ') rotate(' + (-rθ - Math.PI/2)*180/Math.PI + ')') tlp = [Math.sin(lθ + Math.PI/2)*10 + lp[0], Math.cos(lθ + Math.PI/2)*10 + lp[1]] blp = [Math.sin(lθ - Math.PI/2)*10 + lp[0], Math.cos(lθ - Math.PI/2)*10 + lp[1]] trp = [Math.sin(rθ - Math.PI/2)*10 + rp[0], Math.cos(rθ - Math.PI/2)*10 + rp[1]] brp = [Math.sin(rθ + Math.PI/2)*10 + rp[0], Math.cos(rθ + Math.PI/2)*10 + rp[1]] var rSin = Math.sin(rθ) var rCos = Math.cos(rθ) var lSin = Math.sin(lθ) var lCos = Math.cos(lθ) connection.attr('d', [ 'M', tlp, 'C', [tlp[0] - lSin*100, tlp[1] - lCos*100], [trp[0] - rSin*100, trp[1] - rCos*100], trp, 'L', brp, 'C', [brp[0] - rSin*100, brp[1] - rCos*100], [blp[0] - lSin*100, blp[1] - lCos*100], blp, // 'C', [brp[0] + 150, brp[1]], [blp[0] - 150, blp[1]], blp, // 'C', [tlp[0] - 100, tlp[1]], [trp[0] - 100, trp[1]], trp, // 'L', trp, // 'L', brp, // 'Z' ].join(' ')) } function clamp(min, v, max){ return Math.min(max, Math.max(min, v)) } function rotatePoint(p, c, θ){ var sin = Math.sin(θ*Math.PI/180) var cos = Math.cos(θ*Math.PI/180) var x0 = p.x - c.x var y0 = p.y - c.y var x1 = x0*cos - y0*sin var y1 = x0*sin + y0*cos return P(x1 + c.x, y1 + c.y) }