javascript - 为什么在 d3.js 的循环包装中 d3.hierarchy 的 r 值为负?
问题描述
我以https://observablehq.com/@d3/zoomable-circle-packing为例来尝试d3
使用circle packing
角度。我有似乎是分层的数据,我正在遵循所提供的代码。但是,我d3.hierarchy()
给了我奇怪的结果。出于某种原因, alld.x
和d.y
都是r
负数。我不知道为什么。我仍在阅读一些指南和书籍,试图了解我是否可以弄清楚d3.hierarchy
为什么这些值是负面的。但我有点挣扎。代码中发生了什么,如何为数组中的每个对象显示带有 3 个圆圈的圆圈包装?
我在下面的 stackblitz 中有代码。
StackBlitz
代码在stackblitz中
代码
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' });
}
}
}
解决方案
你有2个问题:
您的数据结构不正确,您将对象作为
children
属性的值。它们应该是数组。您正在设置 SVG
viewBox
,而不是它的宽度。因此,这...this.diameter = +this.svg.attr("width")
...只是
+null
,就是0
。因此,size()
方法中的数组将具有负值,这解释了您的主要问题。使用你的width
andheight
代替。
这是分叉代码:https ://stackblitz.com/edit/angular-circle-packing-uyigxs?file=src/app/app.component.ts
推荐阅读
- async-await - Alpine JS:X-data async 未启动 x-model
- r - 如何在 R 中为不包含标头的 .dat 文件创建 hist()?
- node.js - 查找一个并使用随机文档更新?
- python - Pandas 数据类型到 Python 原生数据类型
- vue.js - Nuxt:如何在文件中而不是在样式标签中拥有 css 全局样式
- php - 我必须遍历查询 1 中的 9600 个 DISTINCT 域并更新查询 2 中第二个表中的 id
- laravel - Laravel S3 存储桶权限
- react-native - 反应导航标签栏颜色不起作用
- flutter - 分组 FCM 通知颤振
- node.js - NodeJS TLS客户端连接在第一次收到请求后关闭