拖动时,在释放鼠标单击之前将力施加到节点

时间:2019-01-13 21:10:26

标签: d3.js

我一直在d3js中实现强制布局,并且可以缩放和拖动布局/节点。

当我拖动节点时,该行为很好,除了当我停止移动时,该节点会立即开始移回到其原始位置,即使我没有释放鼠标单击,因此该事件仍应被视为进行中。

我试图通过将d.fx和d.fy设置为当前值来解决此问题,但这并不能解决任何问题。

代码如下:

const WIDTH = 1600;
const HEIGHT = 900;

const V_MARGIN = 20;
const H_MARGIN = 50;

const ALPHA_DECAY = 0.03;
const VELOCITY_DECAY = 0.6;
const LINK_DISTANCE = Math.min(WIDTH, HEIGHT) / 10;
const CHARGE_FORCE = -Math.min(WIDTH, HEIGHT) / 3;
const ITERATIONS = 16;

const CIRCLE_WIDTH = 3;

const ON_HOVER_OPACITY = 0.1;

const c10 = d3.scaleOrdinal(d3.schemeCategory10);

const SVG = d3.select('body')
    .append('svg')
    .attr('width', WIDTH)
    .attr('height', HEIGHT)
;

const g = SVG.append('g')
    .attr('class', 'everything')
;

d3.json('got_social_graph.json')
    .then(data => {
      const nodes = data.nodes;
      const links = data.links;

      //Create force layout
      const force = d3.forceSimulation()
          .nodes(nodes)
          .alphaDecay(ALPHA_DECAY)
          .velocityDecay(VELOCITY_DECAY)
          .force('links', d3.forceLink(links).distance(LINK_DISTANCE))
          .force("collide",d3.forceCollide(d => d.influence > 15 ? d.influence : 15).iterations(ITERATIONS))
          .force('charge_force', d3.forceManyBody().strength(CHARGE_FORCE))
          .force('center_force', d3.forceCenter((WIDTH - H_MARGIN) / 2, (HEIGHT - V_MARGIN) / 2))
          .force("y", d3.forceY(0))
          .force("x", d3.forceX(0))
      ;

      //Create links
      const link = g.append('g')
          .attr('class', 'link')
          .selectAll('line')
          .data(links)
          .enter()
          .append('line')
          .attr('stroke-width', d => d.weight / 10)
      ;

      //Create nodes elements
      const node = g.append('g')
          .attr('class', 'node')
          .selectAll('circle')
          .data(nodes)
          .enter()
          .append('g')
      ;

      //Append circles to nodes
      const circle = node.append('circle')
          .attr('r', d => d.influence > 10 ? d.influence : 10)
          .attr('stroke-width', CIRCLE_WIDTH)
          .attr('stroke', d => c10(d.zone * 10))
          .attr('fill', 'black')
      ;

      /*const label = node.append('text')
          .attr('x', 12)
          .attr('y', '0.25em')
          .attr('font-size', d => d.influence * 1.5 > 9 ? d.influence * 1.5 : 9)
          .text(d => d.character)
      ;*/

      //Refresh force layout data
      force.on('tick', () => {
        node.attr('cx', d => d.x = Math.max(H_MARGIN, Math.min(WIDTH - H_MARGIN, d.x - H_MARGIN)))
            .attr('cy', d => d.y = Math.max(V_MARGIN, Math.min(HEIGHT - V_MARGIN, d.y - V_MARGIN)))
            .attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');

        link.attr('x1', d => d.source.x)
            .attr('y1', d => d.source.y)
            .attr('x2', d => d.target.x)
            .attr('y2', d => d.target.y)
        ;
      });

      //Handle mouse events
      circle
          .on('click', (d, k, n) => {
            d3.select(n[k])
          })
          .on('mouseover', (d, k, n) => {


          })
          .on('mouseout', (d, k, n) => {
            circle
                .attr('opacity', 1)
          })
      ;

      //Handle translation events
      node.call(d3.drag()
          .on('start', (d, n, k) => {
            if (!d3.event.active) force.alphaTarget(0.3).restart();
          })
          .on('drag', (d, n, k) => {
            d3.select(n[k])
                .attr('cx', d.x = d3.event.x)
                .attr('cy', d.y = d3.event.y)
          })
          .on('end', (d, n, k) => {
            if (!d3.event.active) force.alphaTarget(0);
          }))
      ;

      //Handle zoom events
      g.call(d3.zoom()
          .scaleExtent([0.8, 2.5])
          .on('start', () => {
            if (!d3.event.active) force.alphaTarget(0.3).restart();
            d3.event.sourceEvent.stopPropagation();
          })
          .on('zoom', () => {
            if (!d3.event.active) force.alphaTarget(0.3).restart();
            g.attr('transform', d3.event.transform)
          })
          .on('end', () => {
            if (!d3.event.active) force.alphaTarget(0);
          })
      );
    });

我希望该节点停留在鼠标光标上方,直到释放单击为止。该节点不必是粘性的。

0 个答案:

没有答案