Completed
Pull Request — develop (#75)
by
unknown
01:05
created

forcegraph.js ➔ ... ➔ d3Drag.drag.drag   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
nc 1
dl 0
loc 5
rs 9.4285
nop 0
1
define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'forcegraph/math', 'forcegraph/draw'], function (d3Selection, d3Force, d3Zoom, d3Drag, math, draw) {
2
  'use strict';
3
4
  return function (config, linkScale, sidebar, router) {
5
    var self = this;
6
    var el;
7
    var canvas;
8
    var ctx;
9
    var force;
10
    var forceLink;
11
12
    var transform = d3Zoom.zoomIdentity;
13
    var intNodes = [];
14
    var dictNodes = {};
15
    var intLinks = [];
16
17
    const NODE_RADIUS_DRAG = 10;
18
    const NODE_RADIUS_SELECT = 15;
19
    const LINK_RADIUS_SELECT = 12;
20
21
    draw.setTransform(transform);
22
23
    function resizeCanvas() {
24
      canvas.width = el.offsetWidth;
25
      canvas.height = el.offsetHeight;
26
      canvas.style.width = el.offsetWidth + 'px';
27
      canvas.style.height = el.offsetHeight + 'px';
28
    }
29
30
    function onClick() {
31
      if (d3Selection.event.defaultPrevented) {
32
        return;
33
      }
34
35
      var e = transform.invert([d3Selection.event.clientX, d3Selection.event.clientY]);
36
      var n = force.find(e[0], e[1], NODE_RADIUS_SELECT);
37
38
      if (n !== undefined) {
39
        router.node(n.o.node)();
40
        return;
41
      }
42
43
      e = {x: e[0], y: e[1]};
44
45
46
      var closedLink;
47
      var radius = LINK_RADIUS_SELECT;
48
      intLinks
49
        /* Disable Clickable VPN
50
        .filter(function (d) {
51
          return d.o.type !== 'fastd' && d.o.type !== 'L2TP';
52
        })
53
        */
54
        .forEach(function (d) {
55
          var distance = math.distanceLink(e, d.source, d.target);
56
          if (distance < radius) {
57
            closedLink = d;
58
            radius = distance;
59
          }
60
        });
61
62
      if (closedLink !== undefined) {
63
        router.link(closedLink.o)();
64
      }
65
    }
66
67
    function redraw() {
68
      ctx.save();
69
      ctx.clearRect(0, 0, canvas.width, canvas.height);
70
      ctx.translate(transform.x, transform.y);
71
      ctx.scale(transform.k, transform.k);
72
73
      intLinks.forEach(draw.drawLink);
74
      intNodes.forEach(draw.drawNode);
75
76
      ctx.restore();
77
    }
78
79
    el = document.createElement('div');
80
    el.classList.add('graph');
81
82
    forceLink = d3Force.forceLink()
83
     .distance(function (d) {
84
       if (d.o.type === 'fastd' || d.o.type === 'L2TP') {
85
         return 0;
86
       }
87
       return 75;
88
     })
89
     .strength(function (d) {
90
       if (d.o.type === 'fastd' || d.o.type === 'L2TP') {
91
         return 0.02;
92
       }
93
       return Math.max(0.5, 1 / d.o.tq);
94
     });
95
96
    var zoom = d3Zoom.zoom()
97
         .scaleExtent([1 / 3, 3])
98
         .on('zoom', function () {
99
           transform = d3Selection.event.transform;
100
           draw.setTransform(transform);
101
           redraw();
102
         });
103
104
105
    force = d3Force.forceSimulation()
106
      .force('link', forceLink)
107
      .force('charge', d3Force.forceManyBody())
108
      .on('tick', redraw);
109
110
    var drag = d3Drag.drag()
111
      .subject(function () {
112
        if (!d3Selection.event.active) {
113
          force.alphaTarget(0.1).restart();
114
        }
115
        var e = transform.invert([d3Selection.event.x, d3Selection.event.y]);
116
        var n = force.find(e[0], e[1], NODE_RADIUS_DRAG);
117
118
        if (n !== undefined) {
119
          n.fx = transform.applyX(n.x);
120
          n.fy = transform.applyY(n.y);
121
          return n;
122
        }
123
        return undefined;
124
      })
125
      .on('drag', function () {
126
        var e = transform.invert([d3Selection.event.x, d3Selection.event.y]);
127
        d3Selection.event.subject.fx = e[0];
128
        d3Selection.event.subject.fy = e[1];
129
      })
130
      .on('end', function () {
131
        if (!d3Selection.event.active) {
132
          d3Selection.event.subject.fx = null;
133
          d3Selection.event.subject.fy = null;
134
          force.alphaTarget(0);
135
        }
136
      });
137
138
    canvas = d3Selection.select(el)
139
      .append('canvas')
140
      .on('click', onClick)
141
      .call(drag)
142
      .call(zoom)
143
      .node();
144
145
    ctx = canvas.getContext('2d');
146
    draw.setCTX(ctx);
147
148
    window.addEventListener('resize', function () {
149
      resizeCanvas();
150
      redraw();
151
    });
152
153
    self.setData = function setData(data) {
154
      intNodes = data.graph.nodes.map(function (d) {
155
        var e;
156
        if (d.id in dictNodes) {
157
          e = dictNodes[d.id];
158
        } else {
159
          e = {};
160
          dictNodes[d.id] = e;
161
        }
162
163
        e.o = d;
164
165
        return e;
166
      });
167
168
      intLinks = data.graph.links.map(function (d) {
169
        var e = {};
170
        e.o = d;
171
        e.source = dictNodes[d.source.id];
172
        e.target = dictNodes[d.target.id];
173
        e.color = linkScale(d.tq).hex();
174
175
        return e;
176
      });
177
178
      force.nodes(intNodes);
179
      forceLink.links(intLinks);
180
181
      force.restart();
182
      resizeCanvas();
183
    };
184
185
    self.resetView = function resetView() {
186
      draw.setHighlight(null);
187
      redraw();
188
    };
189
190
    self.gotoNode = function gotoNode(d) {
191
      draw.setHighlight({ type: 'node', o: d });
192
      redraw();
193
    };
194
195
    self.gotoLink = function gotoLink(d) {
196
      draw.setHighlight({ type: 'link', o: d });
197
      redraw();
198
    };
199
200
    self.destroy = function destroy() {
201
      force.stop();
202
      canvas.remove();
203
      force = null;
204
205
      if (el.parentNode) {
206
        el.parentNode.removeChild(el);
207
      }
208
    };
209
210
    self.render = function render(d) {
211
      d.appendChild(el);
212
      resizeCanvas();
213
    };
214
215
    return self;
216
  };
217
});
218