如何解决D3js无法正确呈现图表:所有内容都显示为一条线
我正在学习D3js,以下脚本仅渲染包含垂直线的SVG。我试图了解我在这里做错了什么。
我有一个名为Fight的数据项,其中包含一些数据,包括一个属性,该属性可以将游戏的日志文件中的所有损坏事件获取,并将其插入到{ time: number,damage: number }
类型的对象中。
时间以毫秒为单位。
export class GraphComponent implements OnInit {
fight: Fight;
svg: any;
g: any;
x: any;
y: any;
constructor(
private readonly graphService: GraphService,private readonly hostElement: ElementRef
) { }
ngOnInit(): void {
this.graphInit();
this
.graphService
.fight
.subscribe({
next: fight => {
this.fight = fight;
this.graph();
},error: error => {
console.error(error);
}
});
}
graphInit(): void {
this.svg =
d3
.select(this.hostElement.nativeElement)
.append('svg')
.attr('width','100%')
.attr('height','100%')
.attr('viewBox',[0,200,100].join(' '));
}
graph(): void {
const data = this.fight.damage;
const width = this.fight.timeElapsedMs;
const height = this.fight.maxDamage + (this.fight.maxDamage * 0.05);
// X and Y Axis for area charts
this.x =
d3
.scaleLinear()
.domain(d3.extent(data,d => d.time))
.range([0,width]);
this
.svg
.append('g')
.attr('transform',`translate(0,${height})`)
.call(d3.axisBottom(this.x));
this.y =
d3
.scaleLinear()
.domain(d3.extent(data,d => d.damage))
.range([height,0]);
this
.svg
.append('g')
.call(d3.axisLeft(this.y));
this
.svg
.append('path')
.datum(data)
.attr('fill','none')
.attr('stroke','#a80000')
.attr('stroke-width',1.5)
.attr('d',d3
.line()
.x((d: any) => this.x(d.time))
.y((d: any) => this.y(d.damage))
);
}
}
全栈闪电战:https://stackblitz.com/github/xoriworgv?file=src/app/shared/components/graph/graph.component.ts
这是一个电子应用程序,所以我看看是否可以放入一些虚拟数据并使之工作。
解决方法
我已经通过Stackblitz链接推断了您的问题,其中包含一些示例数据。
问题在于您处理数据的方式。 d3.line()
期望由n
个点组成的数组,每个点都有一个x
和y
坐标的对象。您只给了fight.damage
,它是一个数字数组。我为您创建了一个zip
函数,您可以轻松地将它与TypeScript一起使用,以帮助转换数据。
已经完成了,现在您看到的不仅仅是一行!
const graph = (fight) => {
const svg =
d3.select('svg')
.attr('width','400')
.attr('height','250')
.attr('viewBox',[0,200,100].join(' '));
const line =
d3
.line()
.x((d) => x(d.time))
.y((d) => y(d.damage));
const rawData = zip(fight.time,fight.damage);
const data = rawData.map(([time,damage]) => ({
time: time,damage: damage,}));
const width = fight.timeElapsedMs;
const height = fight.maxDamage + (fight.maxDamage * 0.05);
// X and Y Axis for area charts
const x =
d3.scaleLinear()
.domain(d3.extent(fight.time))
.range([0,width]);
svg
.append('g')
.attr('transform',`translate(0,${height})`)
.call(d3.axisBottom(x));
const y =
d3
.scaleLinear()
.domain(d3.extent(fight.damage))
.range([height,0]);
svg
.append('g')
.call(d3.axisLeft(y));
svg
.append('path')
.datum(data)
.attr('fill','none')
.attr('stroke','#a80000')
.attr('stroke-width',1.5)
.attr('d',line);
};
const fight = {
damage: [50,100,50,150],time: [100,300,400],timeElapsedMs: 500,maxDamage: 100,};
/**
* zip is a javascript equivalent of the python zip function
*
* Example:
* zip([1,2,3],[11,22,33]) => [[1,11],[2,22],[3,33]]
*
* @param {T[][]} rows An array of the rows to zip
* @returns {T[][]} the zipped array
*/
//function zip<T>(...rows: T[][]): T[][] {
function zip(...rows) {
return rows[0].map((_,col) => rows.map(row => row[col]));
}
graph(fight);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。