为什么在d3.js中的圆包装中,d3.hierarchy中r的值是负数? [英] Why the value for r is negative from d3.hierarchy in circle packing in d3.js?
问题描述
我正在使用 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个问题:
-
您的数据结构不正确,您有对象作为
子代
属性的值。它们应该是数组。
-
您要设置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:
Your data structure is incorrect, you have objects as the value of your
children
properties. They should be arrays.You are setting the SVG
viewBox
, not its width. Therefore, this...this.diameter = +this.svg.attr("width")
...is just
+null
, which is0
. Because of that, the array in thesize()
method will have negative values, which explains your main issue. Use yourwidth
andheight
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屋!