d3-v5 力引導佈局進階,新增圖例篩選功能

環境,數據,函數部分請參考 上一篇博客d3-V5 力引導佈局實例圖,這裏僅繪圖部分代碼

  // 新建一個力導向圖
          this.forceSimulation = d3.forceSimulation()
            .force('link', d3.forceLink().id(d => d.id))
            .force('charge', d3.forceManyBody().strength(() => -50))
            .force('center', d3.forceCenter());
          const marge = { top: 80, bottom: 60, left: 50, right: 60 };
          const svg = d3.select('#containerKG').append('svg').attr('width', this.width - 20)
            .attr('height', this.height - 20);
          d3.forceX([100]);
          const width = svg.attr('width');
          const height = svg.attr('height');
          let g = svg.append('g')
            .attr('transform', `translate(${marge.top},${marge.left})`);
          svg.call(
            d3.zoom()
              .scaleExtent([0.1, 4])
              .on('zoom', () => { g.attr('transform', d3.event.transform); }),
          );
          let j = 0;
          let k = 0;
          const legendGropp = [];
          for (let i = 0; i < legend.length; i++) {
            const obj = {
              group: legend[i].group,
              states: true,
            };
            legendGropp.push(obj);
          }
          const nodeOri = node;
          const linkOri = fliterlink;
          const sv = svg.selectAll('rect')
            .data(legendGropp)
            .enter()
            .append('rect')
            .attr('x', (d, i) => {
              if (d.group.length > 2) {
                j = j + d.group.length - 2;
                k++;
                return width / 3 + (k - 1) * 12 * j + i * 70;
              }
              return width / 3 + i * 70 + k * 12 * j;
            })
            .attr('rx', 4)
            .attr('ry', 4)
            .attr('y', 40)
            .attr('class', 'legend')
            .attr('width', 25)
            .attr('height', 15)
            .on('click', (dlegend) => {
              for (let i = 0; i < legendGropp.length; i++) {
                if (legendGropp[i].group === dlegend.group) {
                  legendGropp[i].states = !legendGropp[i].states;
                }
              }
              sv.attr('fill', (dd) => {
                if (dd.states === false) {
                  return '#ccc';
                }
                return colorScale(dd.group);
              });
              const nodeClick = [];
              const checkSetFalse = new Set();
              for (let i = 0; i < legendGropp.length; i++) {
                if (legendGropp[i].states === true) {
                  for (let m = 0; m < nodeOri.length; m++) {
                    if (nodeOri[m].group === legendGropp[i].group) {
                      nodeClick.push(nodeOri[m]);
                    }
                  }
                } else {
                  checkSetFalse.add(legendGropp[i].group);
                }
              }
              const LinksObj = [];
              for (let p = 0; p < linkOri.length; p++) {
                if (checkSetFalse.has(linkOri[p].source.group)
                  || checkSetFalse.has(linkOri[p].target.group)) {
                  continue;
                }
                LinksObj.push(linkOri[p]);
              }
              node = nodeClick;
              fliterlink = LinksObj;
              d3.selectAll('svg > g').remove();
              d3.forceX([100]);
              this.forceSimulation = d3.forceSimulation()
                .force('link', d3.forceLink().id(d => d.id))
                .force('charge', d3.forceManyBody().strength(() => -50))
                .force('center', d3.forceCenter());
              g = svg.append('g')
                .attr('transform', `translate(${marge.top},${marge.left})`);
              svg.call(
                d3.zoom()
                  .scaleExtent([0.1, 4])
                  .on('zoom', () => { g.attr('transform', d3.event.transform); }),
              );
              this.forceSimulation.nodes(node)
                .on('tick', this.ticked);// 這個函數很重要,後面給出具體實現和說明
              // 生成邊數據
              this.forceSimulation.force('link')
                .links(fliterlink)
                .distance(() => 200);
              // 設置圖形的中心位置
              this.forceSimulation.force('center')
                .x(width / 2)
                .y(height / 2);
              // 在瀏覽器的控制檯輸出

              // 有了節點和邊的數據後,我們開始繪製
              // 繪製邊
              this.links = g.append('g')
                .selectAll('line')
                .data(fliterlink)
                .enter()
                .append('line')
                .attr('stroke', '#ccc')
                .attr('stroke-width', 1);
              // 繪製節點
              // 老規矩,先爲節點和節點上的文字分組
              this.gs = g.selectAll('.circleText')
                .data(node)
                .enter()
                .append('g')
                .attr('transform', (d) => {
                  const cirX = d.x;
                  const cirY = d.y;
                  return `translate(${cirX},${cirY})`;
                })
                .call(d3.drag()
                  .on('start', this.started)
                  .on('drag', this.dragged)
                  .on('end', this.ended));

              // 繪製節點
              this.gs.append('circle')
                .attr('r', 15)
                .attr('class', 'circleR')
                .attr('fill', d => colorScale(d.group))
                .on('mouseover', function () {
                  d3.select(this)
                    .attr('r', 18)
                    .attr('fill', d => colorScale(d.group))
                    .attr('stroke', '#D3D3D3')
                    .attr('stroke-width', 1)
                    .attr('opacity', '0.8');
                })
                .on('mouseout', function () {
                  d3.select(this)
                    .transition()
                    .duration(300)
                    .attr('fill', d => colorScale(d.group))
                    .attr('r', 15)
                    .attr('stroke', 'none')
                    .attr('opacity', '1');
                });
              // this.gs.append('title')
              //   .text('my color is')
              //   .style('fill', 'red');

              // 文字
              this.gs.append('text')
                .attr('x', -15)
                .attr('y', -28)
                .attr('dy', 10)
                .attr('fill', d => colorScale(d.group))
                .text(d => d.id);
            })
            .attr('fill', d => colorScale(d.group));
          let h = 0;
          let l = 0;
          svg.selectAll('.text')
            .data(legend)
            .enter()
            .append('text')
            .attr('class', 'Text')
            .attr('x', (d, i) => {
              if (d.group.length > 2) {
                l++;
                h += d.group.length - 2;
                return width / 3 + 25 + i * 70 + (l - 1) * 12 * h;
              }
              return width / 3 + 25 + i * 70 + l * 12 * h;
            })
            .attr('y', 52)
            .attr('transform', 'translate(5)')
            .text(d => d.group);


          this.forceSimulation.nodes(node)
            .on('tick', this.ticked);// 這個函數很重要,後面給出具體實現和說明
          // 生成邊數據
          this.forceSimulation.force('link')
            .links(fliterlink)
            .distance(() => 200);
          // 設置圖形的中心位置
          this.forceSimulation.force('center')
            .x(width / 2)
            .y(height / 2);
          // 在瀏覽器的控制檯輸出

          // 有了節點和邊的數據後,我們開始繪製
          // 繪製邊
          this.links = g.append('g')
            .selectAll('line')
            .data(fliterlink)
            .enter()
            .append('line')
            .attr('stroke', '#ccc')
            .attr('stroke-width', 1);
          // 繪製節點
          // 老規矩,先爲節點和節點上的文字分組
          this.gs = g.selectAll('.circleText')
            .data(node)
            .enter()
            .append('g')
            .attr('transform', (d) => {
              const cirX = d.x;
              const cirY = d.y;
              return `translate(${cirX},${cirY})`;
            })
            .call(d3.drag()
              .on('start', this.started)
              .on('drag', this.dragged)
              .on('end', this.ended));

          // 繪製節點
          this.gs.append('circle')
            .attr('r', 15)
            .attr('class', 'circleR')
            .attr('fill', d => colorScale(d.group))
            .on('mouseover', function () {
              d3.select(this)
                .attr('r', 18)
                .attr('fill', d => colorScale(d.group))
                .attr('stroke', '#D3D3D3')
                .attr('stroke-width', 1)
                .attr('opacity', '0.8');
            })
            .on('mouseout', function () {
              d3.select(this)
                .transition()
                .duration(300)
                .attr('fill', d => colorScale(d.group))
                .attr('r', 15)
                .attr('stroke', 'none')
                .attr('opacity', '1');
            });
          // this.gs.append('title')
          //   .text('my color is')
          //   .style('fill', 'red');

          // 文字
          this.gs.append('text')
            .attr('x', -15)
            .attr('y', -28)
            .attr('dy', 10)
            .attr('fill', d => colorScale(d.group))
            .text(d => d.id);
        }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章