我目前正在尝试将javascript中的Mike Bostocks多条形图的代码重写为angular(4)中的打字稿 这是原始块:
http://bl.ocks.org/mbostock/3943967
我从控制台收到以下错误: https://i.imgur.com/G4dWu6q.png
EXCEPTION: Error in :0:0 caused by: Cannot read property 'length' of undefined
ORIGINAL EXCEPTION: Cannot read property 'length' of undefined
Unhandled Promise rejection: Error in :0:0 caused by: Cannot read property 'length' of undefined ; Zone: <root> ; Task: Promise.then ; Value:
我刚刚完成了一个角度cli项目的全新安装,然后使用以下命令安装了d3:
ng new d3test
npm install --save d3
npm install --save-dev @types/d3
这是我的代码:
app.component.html:
<form>
<label><input type="radio" name="mode" value="grouped"> Grouped</label>
<label><input type="radio" name="mode" value="stacked" checked> Stacked</label>
</form>
<svg width="960" height="500"></svg>
app.component.ts:
import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3/index';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
private n; // The number of series.
private m; // The number of values per series.
// The xz array has m elements, representing the x-values shared by all series.
// The yz array has n elements, representing the y-values of each of the n series.
// Each yz[i] is an array of m non-negative numbers representing a y-value for xz[i].
// The y01z array has the same structure as yz, but with stacked [y0, y1] instead of y.
private xz;
private yz;
private y01z;
private yMax;
private y1Max;
private svg;
private margin;
private width;
private height;
private g;
private x;
private y;
private color;
private series;
private rect;
ngOnInit() {
this.n = 4; // The number of series.
this.m = 58; // The number of values per series.
// The xz array has m elements, representing the x-values shared by all series.
// The yz array has n elements, representing the y-values of each of the n series.
// Each yz[i] is an array of m non-negative numbers representing a y-value for xz[i].
// The y01z array has the same structure as yz, but with stacked [y0, y1] instead of y.
this.xz = d3.range(this.m);
this.yz = d3.range(this.n).map(() => {
return this.bumps(this.m);
});
this.y01z = d3.stack().keys(<any>d3.range(this.n))(<any>d3.transpose(this.yz));
this.yMax = d3.max(this.yz, (y) => {
return d3.max(this.y);
});
this.y1Max = d3.max(this.y01z, (y) => {
return d3.max(this.y, (d) => {
return d[1];
});
});
this.svg = d3.select("svg");
this.margin = {
top: 40,
right: 10,
bottom: 20,
left: 10
};
this.width = +this.svg.attr("width") - this.margin.left - this.margin.right;
this.height = +this.svg.attr("height") - this.margin.top - this.margin.bottom;
this.g = this.svg.append("g").attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
this.init();
}
init() {
this.x = d3.scaleBand()
.domain(this.xz)
.rangeRound([0, this.width])
.padding(0.08);
this.y = d3.scaleLinear()
.domain([0, this.y1Max])
.range([this.height, 0]);
this.color = d3.scaleOrdinal()
.domain(<any>d3.range(this.n))
.range(d3.schemeCategory20c);
this.series = this.g.selectAll(".series")
.data(this.y01z)
.enter().append("g")
.attr("fill", (d, i) => {
return this.color(i);
});
this.rect = this.series.selectAll("rect")
.data((d) => {
return d;
})
.enter().append("rect")
.attr("x", (d, i) => {
return this.x(i);
})
.attr("y", this.height)
.attr("width", this.x.bandwidth())
.attr("height", 0);
this.rect.transition()
.delay((d, i) => {
return i * 10;
})
.attr("y", (d) => {
return this.y(d[1]);
})
.attr("height", (d) => {
return this.y(d[0]) - this.y(d[1]);
});
this.g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + this.height + ")")
.call(d3.axisBottom(this.x)
.tickSize(0)
.tickPadding(6));
d3.selectAll("input")
.on("change", this.changed);
}
private timeout = d3.timeout(() => {
d3.select("input[value=\"grouped\"]")
.property("checked", true)
.dispatch("change");
}, 2000);
changed() {
this.timeout.stop();
//used to be this.value
if (d3.event.currentTarget.value === "grouped") {
this.transitionGrouped();
} else {
this.transitionStacked();
}
}
transitionGrouped() {
this.y.domain([0, this.yMax]);
this.rect.transition()
.duration(500)
.delay((d, i) => {
return i * 10;
})
.attr("x", (d, i) => {
return this.x(i) + this.x.bandwidth() / this.n * d3.event.currentTarget.parentNode.__data__.key;
})
.attr("width", this.x.bandwidth() / this.n)
.transition()
.attr("y", (d) => {
return this.y(d[1] - d[0]);
})
.attr("height", (d) => {
return this.y(0) - this.y(d[1] - d[0]);
});
}
transitionStacked() {
this.y.domain([0, this.y1Max]);
this.rect.transition()
.duration(500)
.delay((d, i) => {
return i * 10;
})
.attr("y", (d) => {
return this.y(d[1]);
})
.attr("height", (d) => {
return this.y(d[0]) - this.y(d[1]);
})
.transition()
.attr("x", (d, i) => {
return this.x(i);
})
.attr("width", this.x.bandwidth());
}
// Returns an array of m psuedorandom, smoothly-varying non-negative numbers.
// Inspired by Lee Byron’s test data generator.
// http://leebyron.com/streamgraph/
bumps(m) {
var values = [],
i, j, w, x, y, z;
// Initialize with uniform random values in [0.1, 0.2).
for (i = 0; i < m; ++i) {
values[i] = 0.1 + 0.1 * Math.random();
}
// Add five random bumps.
for (j = 0; j < 5; ++j) {
x = 1 / (0.1 + Math.random());
y = 2 * Math.random() - 0.5;
z = 10 / (0.1 + Math.random());
for (i = 0; i < m; i++) {
w = (i / m - y) * z;
values[i] += x * Math.exp(-w * w);
}
}
// Ensure all values are positive.
for (i = 0; i < m; ++i) {
values[i] = Math.max(0, values[i]);
}
return values;
}
}
我知道这是很多代码,但我真的不明白问题出在哪里。如果我必须要求它可能是使用函数d3.max的地方,但我不确定。