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 }); | |
| })); | |