我正在使用d3js构建瀑布图,但主要要求是在图表中具有多个小计,类似于下图所示。
但是目前我正在使用d3js的图表在图表末尾只有一个总值,下面将介绍我正在处理的代码。
D3.html
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<svg class="chart"></svg>
</body>
</html>
D3.css
.bar.total rect {
fill: blue;
}
.bar:hover rect{
fill:orange;
}
.bar.positive rect {
fill: green;
}
.bar:hover rect{
fill:orange;
}
.bar.negative rect {
fill: red;
}
.bar:hover rect{
fill:orange;
}
.bar line.connector {
stroke: grey;
stroke-dasharray: 3;
}
.axis text {
font: 12px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
div.tooltip {
color:white;
position:absolute;
text-align: center;
padding: 1.2px;
font: 11px sans-serif;
background: black;
border: 0px;
border-radius: 8px;
pointer-events: none;
width: 60px;
}
D3.js
var margin = {top: 20, right: 30, bottom: 100, left: 70},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 0.4;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], padding);
var y = d3.scale.linear()
// .range([height, 0]);
.range([height - padding, padding]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(function(d) { return dollarFormatter(d); })
// .tickFormat(formatAxis)
//tooltip
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0)
.attr("align","middle");
//whole chart
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data = [
{"name":"List Price","value":120},
{"name":"County Adj","value":-13},
{"name":"Country List Price","value":-20},
{"name":"Std Discount","value":-20},
{"name":"Promotion","value":7},
{"name":"Volume Discount","value":-10},
{"name":"Freight Surcharge","value":6},
{"name":"Sales Discount","value":5},
{"name":"Invoice Price","value":9},
{"name":"Cash Discount","value":-2},
{"name":"Customer Rebate","value":-14},
{"name":"Buying Group Rebate","value":4},
{"name":"Net Price","value":-12},
{"name":"Bonus","value":13},
{"name":"Cost to Serve","value":-9},
{"name":"Pocket Price","value":-12},
{"name":"Production Cost","value":-12},
{"name":"Net Margin","value":-18}
];
//function to find all the positive values
var positive_val = data.filter(function(d) { return d.value > 0; });
console.log(JSON.stringify(positive_val));
//function to calculate the sum of all the positive values
var maxSum = positive_val.reduce(function(sum, d) {
return sum + d.value;
}, 0);
console.log("The maximum sum is "+maxSum);
//to calculate the new Domain by adding 120
var yaxisRange=maxSum+120;
console.log("The y axis sum is "+yaxisRange);
var newDomain=dollarFormatter(yaxisRange);
console.log(newDomain);
var newDomain = newDomain.replace(/[!@#$%^&*]/g, ",");
console.log(newDomain);
// Transform data (i.e., finding cumulative values and total) for easier charting
var cumulative = 0;
for (var i = 0; i < data.length; i++) {
data[i].start = cumulative;
cumulative += data[i].value;
data[i].end = cumulative;
data[i].class = ( data[i].value >= 0 ) ? 'positive' : 'negative'
}
data.push({
name: 'Total',
end: cumulative,
start: 0,
class: 'total',
value: cumulative
});
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.end; })]);
//var y_domain = ([0, d3.max(data, function(d) { return d.end; })]);
// y.domain( y_domain);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 6)
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "rotate(50)")
.style("text-anchor", "start");
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = chart.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", function(d) { return "bar " + d.class })
.attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; });
bar.append("rect")
//.attr("y", function(d) { return y(d.value); })
.attr("y", function(d) { return y( Math.max(d.start, d.end) ); })
.attr("height", function(d) { return Math.abs( y(d.start) - y(d.end) ); })
//function to draw the tooltip
.attr("width", x.rangeBand()).on("mouseover", function(d) {
// to find the parent node,to calculate the x position
var parentG = d3.select(this.parentNode);
var barPos = parseFloat(parentG.attr('transform').split("(")[1]);
var xPosition = barPos+x.rangeBand()/2;
//to find the y position
var yPosition = parseFloat(d3.select(this).attr("y"))+ Math.abs( y(d.start) - y(d.end))/2;
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d.name + "<br/>" + (d.value))
.style("left", xPosition + "px")
.style("top", yPosition + "px");
}).on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
// bar.append("text")
// .attr("x", x.rangeBand() / 2)
// .attr("y", function(d) { return y(d.end) + 5; })
// .attr("dy", function(d) { return ((d.class=='negative') ? '-' : '') + ".75em" })
// .text(function(d) { return dollarFormatter(d.end - d.start);});
bar.filter(function(d) { return d.class != "total" }).append("line")
.attr("class", "connector")
.attr("x1", x.rangeBand() + 5 )
.attr("y1", function(d) { return y(d.end) } )
.attr("x2", x.rangeBand() / ( 1 - padding) - 5 )
.attr("y2", function(d) { return y(d.end) } )
function type(d) {
d.value = +d.value;
return d;
}
function dollarFormatter(n) {
n = Math.round(n);
var result = n;
if (Math.abs(n) > 1000) {
result = Math.round(n/1000) + 'M';
}
return '$' + result + 'M';
}
如果需要有关上述代码的更多信息,请在下面找到我目前正在使用的Codepen链接。 https://codepen.io/hari2609/pen/oMxVJZ?editors=0010