我正在使用带角度4的d3 V4来开发分组条形图。这是我的代码。
imports;
let d3: any = D3;
@Component({
selector: 'grouped-bar-chart',
template: '<ng-content></ng-content>'
})
export class GroupedBarChartComponent {
@Input('chartConfig') config: GroupedBarChartConfigModel;
htmlElement: HTMLElement;
host;
width;
height;
innerWidth;
innerHeight;
margin;
x0Scale;
x1Scale;
yScale;
zScale; // color scale
svg;
tooltip;
breakPoint; // used to check if we are on small screens or not
keys;
dataset;
disabledSeries;
constructor(private element: ElementRef) {
if (this.config == null) {
this.config = new GroupedBarChartConfigModel();
}
this.htmlElement = this.element.nativeElement;
this.host = d3.select(this.element.nativeElement);
this.innerWidth = window.innerWidth;
this.innerHeight = window.innerHeight;
this.breakPoint = 768;
this.keys = []; // this holds bars contains in one cluster
this.disabledSeries = [];
this.margin = this.config.margin;
this.ngOnChanges();
}
@HostListener('window:resize', ['$event'])
onResize(event) {
this.ngOnChanges();
}
/**
* Every time the @Input is updated, rebuild the chart
**/
ngOnChanges(): void {
if (!this.config || !this.host || this.config.dataset.length === 0) return;
this.init();
this.setup();
this.buildSVG();
this.scaleAxises();
this.drawXAxis();
this.drawYAxis();
this.populate();
this.drawLegend();
}
/**
* Initialize chart dataset
*/
init(): void {
let data;
this.dataset = data;
}
/**
* Basically we get the window size and build the container configs
* also we create the xScale, yScale & zScale(color scale) ranges depending on calculations
**/
setup(): void {
this.keys = [];
this.width = this.config.width - this.margin.left - this.margin.right;
this.height = this.config.height - this.margin.top - this.margin.bottom;
// determine the geometry of the bars and spaces the individual bars within a cluster
this.x0Scale = d3.scaleBand().rangeRound([0, this.width]).paddingInner(0.01);
// spaces the different clusters of bars across the page
this.x1Scale = d3.scaleBand().padding(0.05);
this.yScale = d3.scaleLinear().rangeRound([this.height, 0]);
this.zScale = d3.scaleOrdinal()
.range(GraphColorPalette.PALETTE);
this.dataset[0].values.map((d: any) => {
if (this.keys.indexOf(d.key) === -1) {
this.keys.push(d.key);
}
});
}
/**
* build SVG element using configurations
**/
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('x', 0)
.attr('y', 0)
.attr('width', this.width)
.attr('height', this.height)
.style('fill', '#eee')
.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
}
/**
**/
scaleAxises(): void {
this.x0Scale.domain(this.dataset.map((d: any) => {
return d.key;
}));
this.x1Scale.domain(this.keys).rangeRound([0, this.x0Scale.bandwidth()]);
let maxDomain = d3.max(this.dataset, (d: any) => {
return d3.max(this.keys, (key: any, i: number) => {
return d.values[i].value;
})
});
this.yScale.domain([0, maxDomain + 1]).nice();
}
/**
* Populate the chart using
**/
populate(): void {
this.drawColumns(this.x1Scale, this.keys, this.dataset);
this.createToolTips();
// add a title to the graph
this.svg.append("text")
.attr("x", (this.width / 2))
.attr("y", 0 - (this.margin.top / 2))
.attr("text-anchor", this.config.titlePosition)
.attr("class", "title")
.style("font-size", "18px")
.style("text-decoration", "underline")
.text(this.config.title);
}
drawColumns(x1Scale: any, keys: Array<string>, data: any): void {
this.svg.append("g")
.attr("class", "chart-layer")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", (d: any) => {
return "translate(" + this.x0Scale(d.key) + ",0)";
})
.selectAll("rect")
.data((d: any) => {
return keys.map((key, i) => {
return {id: d.key, key: key, name: d.name, value: d.values[i].value};
});
})
.enter().append("rect")
.attr("fill", (d) => {
return this.zScale(d.key);
})
.attr("class", "bar")
.style('cursor', 'pointer')
.on("mousemove", (d: any) => {
this.showTooltip(d);
})
.on("mouseout", () => {
this.hideTooltip();
})
.attr("x", (d: any) => {
return x1Scale(d.key);
})
.attr("y", this.height)
.attr("width", x1Scale.bandwidth())
.transition()
.ease(d3.easeLinear)
.duration(1000)
.delay((d, i) => {
return i * 50;
})
.attr("y", (d) => {
return this.yScale(d.value);
})
.attr("height", (d) => {
return Math.abs(this.height - this.yScale(d.value));
})
}
createToolTips(): void {
// Define the div for the tooltip
this.tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip");
}
showTooltip(d: any) {
// Show tooltip
this.tooltip.transition()
.duration(200)
.style("display", "inline");
this.tooltip
.html(d.id + "<br>" + d.name + "<br>" + d.key + ": " + d.value)
.style("left", d3.event.pageX + 10 + "px")
.style("top", d3.event.pageY - 25 + "px")
.style("position", "absolute")
.style("width", "auto")
.style("height", "auto")
.style("border", "0 none")
.style("border-radius", "8px")
.style("border-shadow", "-3px 3px 15px #888888")
.style("padding", "5px")
.style("text-align", "center")
.style("font", "12px sans-serif")
.style("background", "none repeat scroll 0 0 #fff")
.style('color', '#000');
}
hideTooltip() {
this.tooltip.transition()
.duration(500)
.style("display", "none");
}
/**
* Create X-axis
**/
drawXAxis(): void {
this.svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + this.height + ")")
.call(d3.axisBottom(this.x0Scale)
.tickSize(0)
.tickPadding(6));
// Add title to x axis
this.svg.append("text")
.attr("class", "axis-x--label")
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", this.config.xLabelPosition)
.attr("transform", () => {
switch (this.config.xLabelPosition) {
case ChartLabelPositions.START:
return "translate(" + (0) + "," + (this.height - (this.margin.bottom / 10) + 40) + ")";
case ChartLabelPositions.MIDDLE:
return "translate(" + (this.width / 2) + "," + (this.height - (this.margin.bottom / 10) + 40) + ")";
case ChartLabelPositions.END:
return "translate(" + (this.width) + "," + (this.height - (this.margin.bottom / 10) + 40) + ")";
default:
//do nothing
break;
}
}
)
.text(this.config.xLabel);
}
/**
* Create Y-axis
**/
drawYAxis(): void {
this.svg.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(this.yScale).tickSize(-this.width).ticks(null, "s"))
.append("text")
.attr("x", 2)
.attr("y", this.yScale(this.yScale.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", this.config.yLabelPosition)
.text(this.config.yLabel);
}
}
我在图表中显示的数据超过500个。问题是如果有更多的数据,那么条形图没有显示。但如果我隐藏了一些关于传奇的系列,那么就会显示条形图。如何在此图表中显示更多数据。
任何建议都表示赞赏。
谢谢!