首页 > 解决方案 > D3 - 如何在拖动功能中访问新数据

问题描述

我在一条线上有 5 个组元素,我可以将它们拖过那条线。

在拖动结束时,我将当前元素的位置保存在我的数据对象中。之后,如果我拖动另一个元素,数据数组似乎没有更新。每次在拖动功能中,我都会看到数据的初始状态。

进入、更新、退出

const settingsData = settings.map(({ day, ...rest }) => ({ x: scale(day), y: 50, ...rest}));

const group = d3.select('svg').selectAll(".handlersGroup").data(settingsData, ({ id }) => id);

    group.exit().remove();

    const itemGroup = group.enter().append('g')
    .attr('transform', 'translate(0, 0)')
    .attr('class', 'handlersGroup');

    itemGroup.append('circle')
      .attr("r", 14)
      .attr("cy", d => d.y)
      .attr("cx", d => d.x)
      .style("fill", ({ color }) => color);

    itemGroup.append('text')
      .attr("y", d => d.y - 15)
      .attr("x", d => d.x + 10)
      .style("fill", 'black')
      .style('opacity', 0)
      .text(d => `${d.type} - ${Math.round(scale.invert(d.x))}`);

    itemGroup.merge(group);

    itemGroup
    .call(drag)
    .on('mouseover', function () {
      d3.select(this).select('text').style('opacity', 1);
    })
    .on('mouseout', function () {
      d3.select(this).select('text').style('opacity', 0);
    });

拖动功能

const drag = d3.drag()
      .on('drag', function(d) {
        const currentX = d3.event.x;

        const validatedX = currentX < 37 ?
        d.x : currentX > width - 30 ?
        d.x : currentX;

        const startingTextCorrectionPoint = 500;
        const moveAdditional = currentX > startingTextCorrectionPoint ? (currentX - startingTextCorrectionPoint) : 0;

        d3.select(this).select("text").attr("x", d.x = validatedX - moveAdditional + 10);
        d3.select(this).select('text').text((i) => `${d.type} - ${Math.round(scale.invert(validatedX))}`);
        d3.select(this).select("circle")
          .attr("cx", d.x = validatedX);
      })
      .on('start', function() {
        d3.event.sourceEvent.stopPropagation()
        d3.select(this).raise()
      })
      .on('end', function({ id, x }) {
      // Here everytime settings is the initial data array and not the updated one. 
        const newSettings = settings.map(el => {
          if (el.id === id) {
            return {...el, day: Math.round(scale.invert(x))};
          }
          return el;
        });
        updateSettings(newSettings);
      });

我可以用不同的方法更新设置数组而不使用地图,从而避免这个问题,但我想学习解决这个问题比避免它更好。

我相信我正在迭代的设置数据可以通过在初始声明期间存在的关闭来访问.call(drag),因此我无法获得新数据。

如何在函数中访问新的设置数据?

标签: javascriptd3.js

解决方案


目前,我通过更改一些代码并“避免”我最初的问题来解决我的问题。

.on('end', () => {
    const nodesData = d3.selectAll('.handlersGroup').data();
    const newSettings = nodesData.map(({ x, color, type, id }) => 
      ({ color, type, id, day: Math.round(scale.invert(x)) }));

    updateSettings(newSettings);
  });

如果有人知道如何直接访问更新的数据,请发布正确的解决方案


推荐阅读