我试图为使用d3和Angular 2构建的多系列折线图添加缩放功能。
ngOnChanges(data):void {
this.setup(data);
this.initData(data);
this.buildSVG();
this.scaleAxis(data);
this.populate();
this.drawXAxis();
this.drawYAxis();
this.zoomEventHandler();
this.addVerticalLineTooltip();
}
private setup(data):void {
this.margin = {top: 50, right: 100, bottom: 100, left: 100};
this.width = 600;
this.height = 400;
this.xScale = d3.scaleTime().range([0, this.width]);
this.yScale = d3.scaleLinear().range([this.height, 0]);
this.zScale = d3.scaleOrdinal(d3.schemeCategory10);
this.zScale.domain(d3.keys(data[0]).filter(function (key) {
return key !== "date";
}));
}
private initData(data) {
// format the data
data.forEach((d)=> {
d.date = this.parseDate(d.date);
});
this.ds = this.zScale.domain().map((name)=> {
return {
name: name,
values: data.map((d) => {
return {x: d.date, y: d[name], name: name};
})
};
});
}
/**
* build SVG element using the configurations
**/
private buildSVG():void {
this.host.html('');
this.svg = this.host.append('svg')
.attr('width', this.width + this.margin.left + this.margin.right)
.attr('height', this.height + this.margin.top + this.margin.bottom)
.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
this.svg.append('rect')
.attr('class', 'view')
.attr('x', 0.5)
.attr('y', 0.5)
.attr('width', this.width)
.attr('height', this.height)
.style('fill', '#EEEEEE')
.style('stroke-width', '0px');
}
private scaleAxis(data) {
this.xScale.domain(d3.extent(data, (d) => {
return d.date;
}));
this.yScale.domain([
d3.min(this.ds, (c) => {
return d3.min(c.values, function (d) {
return d.y;
});
}),
d3.max(this.ds, (c) => {
return d3.max(c.values,
(d) => {
return d.y;
});
})
]);
this.zScale.domain(this.ds.map((c) => {
return c.name;
}));
this.make_x_axis = ()=> {
return d3.axisBottom()
.scale(this.xScale)
.tickPadding(15);
};
this.make_y_axis = ()=> {
return d3.axisLeft()
.scale(this.yScale)
.tickPadding(10);
};
}
/**
* Create x axis
**/
private drawXAxis():void {
this.xAxis = d3.axisBottom()
.scale(this.xScale)
.tickPadding(15);
this.svg.append('g')
.attr('class', 'x-axis')
.attr('transform', 'translate(0,' + this.height + ')')
.call(this.xAxis);
this.svg.append('text')
.attr('text-anchor', 'middle')
.attr('transform', 'translate(' + (this.width / 2) + "," + (this.height + this.margin.bottom / 2) + ")")
.text('Date');
}
/**
*create y axis
**/
private drawYAxis():void {
this.yAxis = d3.axisLeft()
.scale(this.yScale)
.tickPadding(10);
this.svg.append('g')
.attr('class', 'y-axis')
.call(this.yAxis)
.append('text')
.attr('transform', 'rotate(-90)');
this.svg.append('text')
.attr('text-anchor', 'middle')
.attr("transform", "translate(-" + (this.margin.left / 2) + "," + (this.height / 2) + ")rotate(-90)")
.text('Sales / Searches');
this.svg.append("g")
.attr("class", "y grid")
.call(this.make_y_axis()
.tickSize(-this.width, 0, 0)
.tickFormat(""))
.style("opacity", "0.1");
}
/**
* Populate the graphs
**/
private populate():void {
// define the line
this.line = d3.line()
.x((d) => {
return this.xScale(d.x);
})
.y((d) => {
return this.yScale(d.y);
});
let chartdata = this.svg.selectAll(".chartdata")
.data(this.ds)
.enter().append("g")
.attr("class", "chartdata");
chartdata.append("path")
.attr("class", "line")
.attr("d", (d) => {
return this.line(d.values);
})
.style("fill", "none")
.style("stroke-width", "2px")
.style("stroke", (d) => {
return this.zScale(d.name);
});
chartdata.append("text")
.datum((d)=> {
return {
name: d.name, value: d.values[d.values.length - 1]
};
})
.attr("transform", (d) => {
return "translate(" +
this.xScale(d.value.x) + "," + this.yScale(d.value.y) + ")";
})
.attr('class', 'lineLabel')
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "14px open-sans")
.text((d) => {
return d.name;
});
// add the dots
chartdata.selectAll(".circle")
.data((d) => {
return d.values;
})
.enter().append("circle")
.attr("class", "circle")
.attr("r", 4)
.attr("cx", (d) => {
return this.xScale(d.x);
})
.attr("cy", (d) => {
return this.yScale(d.y);
})
.style("fill", (d) => { // Add the colours dynamically
return this.zScale(d.name);
});
}
private zoomEventHandler() {
let zoom = d3.zoom()
.scaleExtent([1, 2])
.translateExtent([[0, -100], this.width + 90, this.height + 100]).on("zoom", () => this.zoomed());
this.svg.call(zoom);
}
private zoomed() {
d3.select('.x-axis').call(this.xAxis.scale(d3.event.transform.rescaleX(this.xScale)));
d3.selectAll('.line').attr('transform', 'translate(' + d3.event.transform.x + ',' + d3.event.transform.y + ') scale(' + d3.event.transform.k + ')');
d3.selectAll('.circle').attr('transform', 'translate(' + d3.event.transform.x + ',' + d3.event.transform.y + ') scale(' + d3.event.transform.k + ')');
}
我的图表正在响应鼠标滚动事件,如下所示。
有关我的代码错误的建议吗?
谢谢!