为什么在d3.js中的圆包装中,d3.hierarchy中r的值是负数? [英] Why the value for r is negative from d3.hierarchy in circle packing in d3.js?

查看:66
本文介绍了为什么在d3.js中的圆包装中,d3.hierarchy中r的值是负数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 https://observablehq.com/@d3/zoomable-circle -packing 作为示例,尝试以角度进行 d3 圆形包装。我拥有的数据似乎是分层数据,我将按照显示的代码进行操作。但是,我的 d3.hierarchy()给我奇怪的结果。由于某些原因,所有 dx dy r 都是负面的。我不知道为什么。我仍在阅读一些指南和书籍,试图了解是否可以弄清 d3.hierarchy 如何理解值为何为负。但是我对此感到有点挣扎。代码中发生了什么,如何显示数组中每个对象带有3个圆圈的圆圈堆积?


我在下面的堆栈闪电中有代码。


StackBlitz


代码为在这里

代码

  import'@ angular / core'的{Component,OnInit,ElementRef,ViewChild,VERSION,AfterViewInit}; 
进口*作为 d3中的d3;

@Component({
选择器:'my-app',
templateUrl:'./app.component.html',
styleUrls:['./ app.component.css']
})
出口类AppComponent实现OnInit,AfterViewInit {

私有直径:数字;
私人保证金= {顶部:20,右侧:20,底部:20,左侧:20};
私人宽度:数字;
私人身高:数字;
私人svg;任何;
私人g:任何;
private svg容器:ElementRef;
私人色彩:任意;
私人dac:任意;
私人包装:任何;

@ViewChild('circleContainer',{static:false})设置内容(content:ElementRef){

if(content){
this.svgContainer =内容;
}

}

ngOnInit(){


this.dac = {
name ; :: DAC,
子代:
[
{
name:
[
Direction;
],
孩子:
{
孩子:
[
{姓名:领导, ; score:3.33, _row: leader},
{ name: same_sector, score:3.64, _row: same_sector},
{名称: senior_teams,分数:3.81, _ row: senior_teams},
{名称: team,分数:3.81, _ row: team}
]
}
},
{
title:
[
对齐
],
孩子:
{
孩子:
[
{名字:领导, ; score:3, _row: leader},
{ name: same_sector, score:3.51, _row: same_sector},
{名称: senior_teams,分数:3.48, _ row: senior_teams},
{名称: team,分数:3.48, _ row:团队}
]
}
},
{
title:
[
承诺;
],
孩子:
{
孩子:
[
{名字:领导, ; score:3.67, _row: leader},
{ name: same_sector, score:4.05, _row: same_sector},
{名称: senior_teams,分数:3.57, _ row: senior_teams},
{名称: team,分数:3.57, _ row:团队}
]
}
}
]
}
this.createChart();

}

ngAfterViewInit(){

this.width = 500-this.margin.left-this.margin.right;
this.height = 400-this.margin.top-this.margin.bottom;

this.color = d3.scaleLinear< string>()
.domain([1,5])
.range([ hsl(152,80%, 80%), hsl(228,30%,40%)])
.interpolate(d3.interpolateHcl);

if(this.svgContainer&& this.dac){

this.createChart()

}

}


private createSVG(rect){

this.svg = d3.select(rect)
.append('svg')
.attr('viewBox',`0 0 $ {this.width / 2} $ {this.height / 2}`)
.attr('preserveAspectRatio','xMinYMin Meet')
.style('display','block')
.style('margin','0 auto')
.style('background',this.color(1))
.style('cursor','pointer')
.attr('class','bubble-chart')

this.diameter = + this.svg.attr( ; width)
console.log( diameter:,this.diameter);

this.pack =数据=> d3.pack()
.size([this.diameter-this.margin.left,this.diameter-this.margin.right])
.padding(2)
(d3。层次结构(数据)
.sum(d => d.score)
.sort((a,b)=> b.value-a.value))


}

私人createChart(){

让它= this;

const rect = this.svgContainer.nativeElement;

this.createSVG(rect);

const root = this.pack(this.dac);
让focus = root;
让我们看看;

console.log(root);
this.svg = this.svg
.on('click',(event)=> zoom(event,root));

常量节点= this.svg.append('g')
.selectAll('circle')
.data(root.descendants()。slice(1))
.join('circle')
.attr('fill',d => d.children?this.color(d.depth): white)
.attr ('pointer-events',d =>!d.children?'none':null)
.on('mouseover',function(){d3.select(this).attr('stroke' ,'#999');})
.on('mouseout',function(){d3.select(this).attr('stroke','null');})
.on ('click',(event,d)=> focus!== d&(zoom(event,d),event.stopPropagation()));

const label = this.svg.append('g')
.style('font','10px Roboto')
.attr('pointer-events', 'none')
.attr('text-anchor','middle')
.selectAll('text')
.data(root.descendants())
。 join('text')
.style('fill-opacity',d => d.parent === root?1:0)
.style('display',d => d.parent === root?'inline':'none')
.text(d => d.data.name);


zoomTo([root.x,root.y,root.r * 2]);

函数zoomTo(v){
const k = that.width / v [2];

视图= v;


console.log( k:,k);
console.log( v:,v);

label.attr('transform',d => {
console.log( dx:,dx)
console.log( dy: " dy);
return`translate($ {(dx-v [0])* k},$ {(dy-v [1])* k})`});
node.attr(‘transform’,d =>`translate($ {(d.x-v [0])* k},$ {(d.y-v [1])* k})));
node.attr(’r’,d => d.r * k);
}


函数zoom(event,d){
const focus0 = focus;
focus = d;

const transition = that.svg.transition()
.duration(event.altKey?7500:750)
.tween('zoom',d => {
const i = d3.interpolateZoom(view,[focus.x,focus.y,focus.r * 2]);
return t => zoomTo(i(t));
});

标签
.filter(function(d){return d.parent === focus || this.style.display ==='inline';})
。 transition(transition)
.style('fill-opacity',d => d.parent === focus?1:0)
.on('start',function(d){if (d.parent === focus)this.style.display ='inline';})
.on('end',function(d){if(d.parent!== focus)this.style .display ='none'});
}



}



}


解决方案

您有2个问题:


  1. 您的数据结构不正确,您有对象作为子代属性的值。它们应该是数组。



  2. 您要设置SVG viewBox ,而不是其宽度。因此,此...

      this.diameter = + this.svg.attr( width)

    ...只是 + null ,即 0 。因此, size()方法中的数组将具有负值,这说明了您的主要问题。请改用您的宽度高度



这是分叉的代码: https://stackblitz.com/edit/angular-circle-packing-uyigxs?file=src/app/app.component.ts


I'm using https://observablehq.com/@d3/zoomable-circle-packing as an example to try d3 and circle packing in angular. I have the data which seems to be hierarchical and I'm following along the code that's presented. However, my d3.hierarchy() is giving me strange results. For some reason, all d.x, d.y and r are all negative. I couldn't figure out why. I'm still reading some guides and books trying to understand if I can figure out how d3.hierarchy works to understand why the values are negative. But I'm bit struggling with that. What's happening in the code and how can I show the circle packing with 3 circles for each object in the array?

I have the codes in stackblitz below.

StackBlitz

The code is here in stackblitz

Code

import { Component, OnInit, ElementRef, ViewChild,  VERSION, AfterViewInit } from '@angular/core';
import * as d3 from 'd3';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit, AfterViewInit  {
 
  private diameter: number;
  private margin = { top: 20, right: 20, bottom: 20, left: 20 };
  private width: number;
  private height: number;
  private svg; any;
  private g: any;
  private svgContainer: ElementRef;
  private color: any;
  private dac: any;
  private pack: any;

  @ViewChild('circleContainer', { static: false }) set content(content: ElementRef) {

    if (content) {
      this.svgContainer = content;
    }

  }

  ngOnInit() {

  
    this.dac = {
    "name": "DAC",
    "children":
    [
        {
            "name":
            [
                "Direction"
            ],
            "children":
            {
                "children":
                [
                    {"name":"leader","score":3.33,"_row":"leader"},
                    {"name":"same_sector","score":3.64,"_row":"same_sector"},
                    {"name":"senior_teams","score":3.81,"_row":"senior_teams"},
                    {"name":"team","score":3.81,"_row":"team"}
                ]
            }
        },
        {
            "title":
            [
                "Alignment"
            ],
            "children":
            {
                "children":
                [
                    {"name":"leader","score":3,"_row":"leader"},
                    {"name":"same_sector","score":3.51,"_row":"same_sector"},
                    {"name":"senior_teams","score":3.48,"_row":"senior_teams"},
                    {"name":"team","score":3.48,"_row":"team"}
                ]
            }
        },
        {
            "title":
            [
                "Commitment"
            ],
            "children":
            {
                "children":
                [
                    {"name":"leader","score":3.67,"_row":"leader"},
                    {"name":"same_sector","score":4.05,"_row":"same_sector"},
                    {"name":"senior_teams","score":3.57,"_row":"senior_teams"},
                    {"name":"team","score":3.57,"_row":"team"}
                ]
            }
        }
    ]
}
    this.createChart();
  
  }

  ngAfterViewInit() {

    this.width = 500 - this.margin.left - this.margin.right;
    this.height = 400 - this.margin.top - this.margin.bottom;

    this.color = d3.scaleLinear<string>()
      .domain([1, 5])
      .range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
      .interpolate(d3.interpolateHcl);

    if (this.svgContainer && this.dac) {

      this.createChart()

    }

  }


    private createSVG(rect) {

    this.svg = d3.select(rect)
      .append('svg')
      .attr('viewBox', `0 0  ${this.width / 2} ${this.height / 2}`)
      .attr('preserveAspectRatio', 'xMinYMin meet')
      .style('display', 'block')
      .style('margin', "0 auto")
      .style('background', this.color(1))
      .style('cursor', 'pointer')
      .attr('class', 'bubble-chart')

    this.diameter = +this.svg.attr("width")
    console.log("diameter: ", this.diameter);

    this.pack = data => d3.pack()
      .size([this.diameter - this.margin.left, this.diameter - this.margin.right])
      .padding(2)
      (d3.hierarchy(data)
        .sum(d => d.score)
        .sort((a, b) => b.value - a.value))
      

  }

 private createChart() {

    let that = this;

    const rect = this.svgContainer.nativeElement;

    this.createSVG(rect);

    const root = this.pack(this.dac);
    let focus = root;
    let view;

    console.log(root);
    this.svg = this.svg
      .on('click', (event) => zoom(event, root));

    const node = this.svg.append('g')
      .selectAll('circle')
      .data(root.descendants().slice(1))
      .join('circle')
      .attr('fill', d => d.children ? this.color(d.depth) : "white")
      .attr('pointer-events', d => !d.children ? "none" : null)
      .on('mouseover', function () { d3.select(this).attr('stroke', '#999'); })
      .on('mouseout', function () { d3.select(this).attr('stroke', 'null'); })
      .on('click', (event, d) => focus !== d && (zoom(event, d), event.stopPropagation()));

    const label = this.svg.append('g')
      .style('font', '10px Roboto')
      .attr('pointer-events', 'none')
      .attr('text-anchor', 'middle')
      .selectAll('text')
      .data(root.descendants())
      .join('text')
      .style('fill-opacity', d => d.parent === root ? 1 : 0)
      .style('display', d => d.parent === root ? 'inline' : 'none')
      .text(d => d.data.name);


    zoomTo([root.x, root.y, root.r * 2]);

    function zoomTo(v) {
      const k = that.width / v[2];

      view = v;

      
      console.log("k: ", k);
      console.log("v:",v);

      label.attr('transform', d => {
        console.log("dx: ", d.x)
        console.log("dy: ", d.y);
        return `translate(${(d.x - v[0]) * k}, ${(d.y - v[1]) * k})`});
      node.attr('transform', d => `translate(${(d.x - v[0]) * k}, ${(d.y - v[1]) * k})`);
      node.attr('r', d => d.r * k);
    }


    function zoom(event, d) {
      const focus0 = focus;
      focus = d;

      const transition = that.svg.transition()
        .duration(event.altKey ? 7500 : 750)
        .tween('zoom', d => {
          const i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2]);
          return t => zoomTo(i(t));
        });

      label
        .filter(function (d) { return d.parent === focus || this.style.display === 'inline'; })
        .transition(transition)
        .style('fill-opacity', d => d.parent === focus ? 1 : 0)
        .on('start', function (d) { if (d.parent === focus) this.style.display = 'inline'; })
        .on('end', function (d) { if (d.parent !== focus) this.style.display = 'none' });
    }



  }

  

}

解决方案

You have 2 problems:

  1. Your data structure is incorrect, you have objects as the value of your children properties. They should be arrays.

  2. You are setting the SVG viewBox, not its width. Therefore, this...

    this.diameter = +this.svg.attr("width")
    

    ...is just +null, which is 0. Because of that, the array in the size() method will have negative values, which explains your main issue. Use your width and height instead.

Here is the forked code: https://stackblitz.com/edit/angular-circle-packing-uyigxs?file=src/app/app.component.ts

这篇关于为什么在d3.js中的圆包装中,d3.hierarchy中r的值是负数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆