代码之家  ›  专栏  ›  技术社区  ›  Chris Satchell

d3中的点更改时更新多边形

  •  0
  • Chris Satchell  · 技术社区  · 6 年前

    我目前正在处理d3中的多边形,希望在用户拖动点时更新单个多边形。最初绘制它们效果很好,但我无法进行更新。下面这把小提琴包含了我的可怕尝试:

    https://jsfiddle.net/z4g5817z/9/

    相关代码:

    const areas = [{
        uid: 'ajf9v0',
        points: [{
            x: 52,
            y: 92
          },
          {
            x: 50,
            y: 151
          },
          {
            x: 123,
            y: 149
          },
          {
            x: 125,
            y: 91
          }
        ],
        foo: 'bar',
        // ...
      },
      {
        uid: 'ufnf12',
        points: [{
            x: 350,
            y: 250
          },
          {
            x: 450,
            y: 250
          },
          {
            x: 450,
            y: 275
          },
          {
            x: 350,
            y: 275
          }
        ],
        foo: 'baz',
        // ...
      }
    ];
    
    const svg = d3.select('#root');
    
    svg.attr('width', 500)
      .attr('height', 500);
    
    const areasGroup = svg.append('g')
      .attr('class', 'areas');
    
    function drawAreas(areas) {
    
      console.log('Called draw');
      const self = this;
    
      const aGroup = areasGroup.selectAll('g.area')
        .data(areas, (d) => {
          console.log('Areas', d.points.map((d) => [d.x, d.y].join('#')).join('#'));
          return d.points.map((d) => [d.x, d.y].join('#')).join('#');
        });
    
      areasGroup.exit().remove();
    
      const areaGroups = aGroup.enter()
        .append('g')
        .attr('class', 'area');
    
      //const areaPolygon = area.append('g')
      //    .attr('class', 'polygon');
    
      //const areaPoints = area.append('g')
      //    .attr('class', 'points');
    
      const polygon = areaGroups.selectAll('polygon')
        .data((d) => {
          console.log('Polygon data points', [d.points]);
          return [d.points];
        }, (d) => {
          console.log('Polygon key', d.map((d) => [d.x, d.y].join('#')).join('#'));
          return d.map((d) => [d.x, d.y].join('#')).join('#');
        });
    
      polygon.enter()
        .append('polygon')
        .merge(polygon)
        .attr('points', (d) => {
          console.log('Polygon points', d);
          return d.map((d) => [d.x, d.y].join(',')).join(' ');
        })
        .attr('stroke', '#007bff')
        .attr('stroke-width', 1)
        .attr('fill', '#007bff')
        .attr('fill-opacity', 0.25)
        .on('click', this.handlePolygonSelection)
    
      polygon.exit().remove();
    
      const circles = areaGroups.selectAll('circle')
        .data((d) => d.points, (d) => d.x + '#' + d.y);
    
      circles.enter()
        .append('circle')
        .attr('r', 4)
        .attr('cx', (d) => d.x)
        .attr('cy', (d) => d.y)
        .attr('fill', '#007bff')
        .on('click', (d, idx, j) => {
          const parentArea = d3.select(j[idx].parentNode).datum().points;
    
          const i = parentArea.findIndex((p) => p.x === d.x && p.y === d.y);
    
          if (i === parentArea.length) {
            parentArea.pop();
          } else if (i === 0) {
            parentArea.shift();
          } else {
            parentArea.splice(i, 1);
          }
    
          this.drawAreas(areas);
        })
        .call(d3.drag()
          .on('start', function(d) {
            d3.select(this).classed('active', true)
          })
          .on('drag', function(d) {
            d3.select(this)
              .attr('cx', d.x = d3.event.x)
              .attr('cy', d.y = d3.event.y);
            self.drawAreas(areas);
          })
          .on('end', function(d) {
            d3.select(this).classed('active', false)
          }));
    
      circles.exit().remove();
    
    }
    
    this.drawAreas(areas);
    

    感谢所有花时间看一看的人,感谢所有人的帮助。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Chris Satchell    6 年前

    看来我找到了问题所在: https://jsfiddle.net/z4g5817z/91/

    正在更改

    const polygon = areaGroups.selectAll('polygon')
    

    const polygon = areasGroup.selectAll('g.area').selectAll('polygon')
    

    似乎已经修好了。我想这和 areaGroups 仅处理enter事件的选择。

    另一种选择是保持现状并改变

    const areaGroups = aGroup.enter()
      .append('g')
      .attr('class', 'area');
    

    const areaGroups = aGroup.enter()
      .append('g')
      .merge(aGroup)
      .attr('class', 'area');
    

    这将产生相同的结果,因为更新事件现在也得到了适当的处理。