Spaces:
Running
Running
// https://github.com/1wheel/swoopy-drag Copyright (c) 2016 Adam Pearce | |
(function (global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3')) : | |
typeof define === 'function' && define.amd ? define(['exports', 'd3'], factory) : | |
(factory((global.d3 = global.d3 || {}),global.d3)); | |
}(this, function (exports,d3) { 'use strict'; | |
function swoopyDrag(){ | |
var x = function(d){ return d } | |
var y = function(d){ return d } | |
var annotations = [] | |
var annotationSel | |
var draggable = false | |
var dispatch = d3.dispatch('drag') | |
var textDrag = d3.drag() | |
.on('drag', function(d){ | |
var x = d3.event.x | |
var y = d3.event.y | |
d.textOffset = [x, y].map(Math.round) | |
d3.select(this).call(translate, d.textOffset) | |
dispatch.call('drag') | |
}) | |
.subject(function(d){ return {x: d.textOffset[0], y: d.textOffset[1]} }) | |
var circleDrag = d3.drag() | |
.on('drag', function(d){ | |
var x = d3.event.x | |
var y = d3.event.y | |
d.pos = [x, y].map(Math.round) | |
var parentSel = d3.select(this.parentNode) | |
var path = '' | |
var points = parentSel.selectAll('circle').data() | |
if (points[0].type == 'A'){ | |
path = calcCirclePath(points) | |
} else{ | |
points.forEach(function(d){ path = path + d.type + d.pos }) | |
} | |
parentSel.select('path').attr('d', path).datum().path = path | |
d3.select(this).call(translate, d.pos) | |
dispatch.call('drag') | |
}) | |
.subject(function(d){ return {x: d.pos[0], y: d.pos[1]} }) | |
var rv = function(sel){ | |
annotationSel = sel.html('').selectAll('g') | |
.data(annotations).enter() | |
.append('g') | |
.call(translate, function(d){ return [x(d), y(d)] }) | |
var textSel = annotationSel.append('text') | |
.call(translate, ƒ('textOffset')) | |
.text(ƒ('text')) | |
annotationSel.append('path') | |
.attr('d', ƒ('path')) | |
if (!draggable) return | |
annotationSel.style('cursor', 'pointer') | |
textSel.call(textDrag) | |
annotationSel.selectAll('circle').data(function(d){ | |
var points = [] | |
if (~d.path.indexOf('A')){ | |
//handle arc paths seperatly -- only one circle supported | |
var pathNode = d3.select(this).select('path').node() | |
var l = pathNode.getTotalLength() | |
points = [0, .5, 1].map(function(d){ | |
var p = pathNode.getPointAtLength(d*l) | |
return {pos: [p.x, p.y], type: 'A'} | |
}) | |
} else{ | |
var i = 1 | |
var type = 'M' | |
var commas = 0 | |
for (var j = 1; j < d.path.length; j++){ | |
var curChar = d.path[j] | |
if (curChar == ',') commas++ | |
if (curChar == 'L' || curChar == 'C' || commas == 2){ | |
points.push({pos: d.path.slice(i, j).split(','), type: type}) | |
type = curChar | |
i = j + 1 | |
commas = 0 | |
} | |
} | |
points.push({pos: d.path.slice(i, j).split(','), type: type}) | |
} | |
return points | |
}).enter().append('circle') | |
.attr('r', 8) | |
.attr('fill', 'rgba(0,0,0,0)') | |
.attr('stroke', '#333') | |
.attr('stroke-dasharray', '2 2') | |
.call(translate, ƒ('pos')) | |
.call(circleDrag) | |
dispatch.call('drag') | |
} | |
rv.annotations = function(_x){ | |
if (typeof(_x) == 'undefined') return annotations | |
annotations = _x | |
return rv | |
} | |
rv.x = function(_x){ | |
if (typeof(_x) == 'undefined') return x | |
x = _x | |
return rv | |
} | |
rv.y = function(_x){ | |
if (typeof(_x) == 'undefined') return y | |
y = _x | |
return rv | |
} | |
rv.draggable = function(_x){ | |
if (typeof(_x) == 'undefined') return draggable | |
draggable = _x | |
return rv | |
} | |
rv.on = function() { | |
var value = dispatch.on.apply(dispatch, arguments); | |
return value === dispatch ? rv : value; | |
} | |
return rv | |
//convert 3 points to an Arc Path | |
function calcCirclePath(points){ | |
var a = points[0].pos | |
var b = points[2].pos | |
var c = points[1].pos | |
var A = dist(b, c) | |
var B = dist(c, a) | |
var C = dist(a, b) | |
var angle = Math.acos((A*A + B*B - C*C)/(2*A*B)) | |
//calc radius of circle | |
var K = .5*A*B*Math.sin(angle) | |
var r = A*B*C/4/K | |
r = Math.round(r*1000)/1000 | |
//large arc flag | |
var laf = +(Math.PI/2 > angle) | |
//sweep flag | |
var saf = +((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0]) < 0) | |
return ['M', a, 'A', r, r, 0, laf, saf, b].join(' ') | |
} | |
function dist(a, b){ | |
return Math.sqrt( | |
Math.pow(a[0] - b[0], 2) + | |
Math.pow(a[1] - b[1], 2)) | |
} | |
//no jetpack dependency | |
function translate(sel, pos){ | |
sel.attr('transform', function(d){ | |
var posStr = typeof(pos) == 'function' ? pos(d) : pos | |
return 'translate(' + posStr + ')' | |
}) | |
} | |
function ƒ(str){ return function(d){ return d[str] } } | |
} | |
exports.swoopyDrag = swoopyDrag; | |
Object.defineProperty(exports, '__esModule', { value: true }); | |
})); | |