xxxxxxxxxx
<meta charset="utf-8">
<head>
<title>Chandrakant Bharatkumar Thakkar</title>
</head>
<body>
<div id="charts">
<svg width="800" height="500"></svg>
</div>
<a href="https://stackoverflow.com/users/7430694/chandrakant-thakkar" style="position: absolute;top: 87%;left: 77%;" target="_blank">
<img src="https://stackoverflow.com/users/flair/7430694.png" width="208" height="58" alt="profile for Chandrakant Thakkar at Stack Overflow, Q&A for professional and enthusiast programmers" title="profile for Chandrakant Thakkar at Stack Overflow, Q&A for professional and enthusiast programmers">
</a>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="./data.js"></script>
<script>
var groupPlan = ["Laptops", "Processor", "Ram","Harddisk","Monitor","Keyboard","Mouse"];
var groupActual = ["Laptops", "Processor", "Ram","Harddisk","Monitor","Keyboard","Mouse"];
var parseDate = d3.timeFormat("%b-%Y");
var mainDiv = "#charts";
var mainDivName = "charts";
var actualMaxHeight=0;
var plannedMaxHeight=0;
drawStackChart();
function createChartLegend(mainDiv, groupPlan) {
// var z = d3.scaleOrdinal(d3.schemeCategory10);
var z =d3.scaleOrdinal(["#0ef2a6","#0661f1"]);
var mainDivName = mainDiv.substr(1, mainDiv.length);
$(mainDiv).before("<div id='Legend_" + mainDivName + "' class='pmd-card-body' style='margin-left: 65px;margin-top:0; margin-bottom:0;'></div>");
var keys = groupPlan;
keys.forEach(function(d) {
var cloloCode = z(d);
$("#Legend_" + mainDivName).append("<span class='team-graph team1' style='display: inline-block; margin-right:10px;float: left;'>\
<span style='background:" + cloloCode +
";width: 10px;height: 10px;display: inline-block;vertical-align: middle;'> </span>\
<span style='padding-top: 0;font-family:Source Sans Pro, sans-serif;font-size: 13px;display: inline;'>" + d +
" </span>\
</span>");
});
$("#Legend_" + mainDivName).append("<div style='width:50%;text-align:right'><input type='button' style='margin-right:30px;opacity:0;' value='Reset' id='resetAllData'/></div>");
d3.select("#resetAllData").on("click",function(){
d3.select("#resetAllData").style("opacity","0");
$("#Legend_" + mainDivName).remove();
d3.select("#charts").html("<svg width='800' height='500'></svg>");
drawStackChart();
});
}
function drawStackChart(){
createChartLegend(mainDiv, ["Planned Production","Actual Production"]);
plannedData.forEach(function(d) {
d = type(d);
});
actualData.forEach(function(d) {
d = type(d);
});
var layers = d3.stack()
.keys(groupPlan)
.offset(d3.stackOffsetDiverging)
(plannedData);
var layersActual = d3.stack()
.keys(groupActual)
.offset(d3.stackOffsetDiverging)
(actualData);
var svg = d3.select("svg"),
margin = {
top: 20,
right: 30,
bottom: 80,
left: 60
},
width = +svg.attr("width"),
height = +svg.attr("height");
var x = d3.scaleBand()
.rangeRound([margin.left, width - margin.right])
.padding(0.1);
x.domain(plannedData.map(function(d) {
return d.date;
}));
var y = d3.scaleLinear()
.rangeRound([height - margin.bottom, height*0.45]);
plannedMaxHeight=height - margin.bottom;
actualMaxHeight=(height*0.45)-10;
var yActual = d3.scaleLinear()
.rangeRound([(height*0.45)-10,margin.top]);
var maxY=d3.max(layers, stackMax) > d3.max(layersActual, stackMaxActual)?d3.max(layers, stackMax): d3.max(layersActual, stackMaxActual);
y.domain([d3.min(layers, stackMin), maxY]);
yActual.domain([d3.min(layersActual, stackMinActual), maxY])
function stackMin(layers) {
return d3.min(layers, function(d) {
return d[0];
});
}
function stackMinActual(layersActual) {
return d3.min(layersActual, function(d) {
return d[0];
});
}
function stackMax(layers) {
return d3.max(layers, function(d) {
return d[1];
});
}
function stackMaxActual(layersActual) {
return d3.max(layersActual, function(d) {
return d[1];
});
}
// var z = d3.scaleOrdinal(d3.schemeCategory10);
var z =d3.scaleOrdinal(["#0ef2a6"]);
var zActual =d3.scaleOrdinal(["#0661f1"]);
var maing = svg.append("g")
.selectAll("g")
.data(layers);
var g = maing.enter().append("g");
var rect = g.selectAll("rect")
.data(function(d) {
d.forEach(function(d1) {
d1.key = d.key;
return d1;
});
return d;
})
.enter().append("rect")
.attr("class",function(d){
return "planned_"+d.key+" planned";
})
.attr("opacity", 0.6)
.attr("fill", function(d) {
return z(d.key);
})
.attr("cursor","pointer")
.attr("data", function(d) {
var data = {};
data["key"] = d.key;
data["value"] = d.data[d.key];
var total = 0;
groupPlan.map(function(d1) {
if(d.data.hasOwnProperty(d1)){
total = total + d.data[d1]
}
});
data["total"] = total;
return JSON.stringify(data);
})
.attr("stroke-opacity", 0.5)
.attr("stroke-width","1px")
.attr("stroke","black")
.attr("width", x.bandwidth)
.attr("x", function(d) {
return x(d.data.date);
})
.attr("y", function(d) {
if(d.data.hasOwnProperty(d.key)){
return y(d[1]);
}else{
return 0;
}
})
.attr("height", function(d) {
if(d.data.hasOwnProperty(d.key)){
return y(d[0]) - y(d[1]);
}else{
return 0;
}
});
var maingActual = svg.append("g")
.selectAll("g")
.data(layersActual);
var gActual = maingActual.enter().append("g");
var rectActual = gActual.selectAll("rect")
.data(function(d) {
d.forEach(function(d1) {
d1.key = d.key;
return d1;
});
return d;
})
.enter().append("rect")
.attr("class",function(d){
return "actual_"+d.key+" actual";
})
.attr("opacity", 0.6)
.attr("cursor","pointer")
.attr("fill", function(d) {
return zActual(d.key);
})
.attr("data", function(d) {
var data = {};
data["key"] = d.key;
data["value"] = d.data[d.key];
var total = 0;
groupActual.map(function(d1) {
if(d.data.hasOwnProperty(d1)){
total = total + d.data[d1]
}
});
data["total"] = total;
return JSON.stringify(data);
})
.attr("stroke-opacity", 0.5)
.attr("stroke-width","1px")
.attr("stroke","black")
.attr("width", x.bandwidth)
.attr("x", function(d) {
return x(d.data.date);
})
.attr("y", function(d) {
if(d.data.hasOwnProperty(d.key)){
return yActual(d[1]);
}else{
return 0;
}
})
.attr("height", function(d) {
if(d.data.hasOwnProperty(d.key)){
return yActual(d[0]) - yActual(d[1]);
}else{
return 0;
}
});
([rect,rectActual]).map(function(d){
d.on("click",function(d){
var currentEl = d3.select(this);
var tooltipData = JSON.parse(currentEl.attr("data"));
d3.select("#resetAllData").style("opacity","1");
var currentRectClass = currentEl.attr("class").split(" ")[0];
if(currentRectClass.split("_")[0]=="planned"){
d3.selectAll(".actual").transition().duration(1000).attr("opacity","0");
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).transition().duration(1001).attr("opacity","1");
d3.selectAll(".planned").transition().duration(1002).attr("opacity","0");
d3.selectAll(".planned_"+currentRectClass.split("_")[1]).transition().duration(1003).attr("opacity","0.6");
}else{
d3.selectAll(".planned").transition().duration(1000).attr("opacity","0");
d3.selectAll(".planned_"+currentRectClass.split("_")[1]).transition().duration(1001).attr("opacity","1");
d3.selectAll(".actual").transition().duration(1002).attr("opacity","0");
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).transition().duration(1003).attr("opacity","0.6");
}
d3.selectAll(".planned_"+currentRectClass.split("_")[1]).transition().duration(2000)
.attr("y",function(d){
return (plannedMaxHeight-d3.select(this).attr("height"));
});
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).transition().duration(2000)
.attr("y",function(d){
return (actualMaxHeight-d3.select(this).attr("height"));
});
currentEl.attr("opacity","1");
});
d.on("mouseover", function() {
var currentEl = d3.select(this);
var fadeInSpeed = 120;
if(currentEl.style("opacity")!=0){
d3.select("#recttooltip_" + mainDivName)
.transition()
.duration(fadeInSpeed)
.style("opacity", function() {
return 1;
});
currentEl.attr("opacity","1");
var currentRectClass = currentEl.attr("class").split(" ")[0];
if(currentRectClass.split("_")[0]=="planned"){
// d3.selectAll(".actual").attr("opacity","0");
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).attr("opacity","1");
}else{
// d3.selectAll(".planned").attr("opacity","0");
d3.selectAll(".planned_"+currentRectClass.split("_")[1]).attr("opacity","1");
}
//CBT:calculate tooltips text
var tooltipData = JSON.parse(currentEl.attr("data"));
var tooltipsText = "";
d3.selectAll("#recttooltipText_" + mainDivName).text("");
var yPos = 0;
d3.selectAll("#recttooltipText_" + mainDivName).append("tspan").attr("x", 0).attr("y", yPos * 10).attr("dy", "1.9em").text(tooltipData.key + ": " + tooltipData.value);
yPos = yPos + 1;
d3.selectAll("#recttooltipText_" + mainDivName).append("tspan").attr("x", 0).attr("y", yPos * 10).attr("dy", "1.9em").text("Total" + ": " + tooltipData.total);
//CBT:calculate width of the text based on characters
var dims = helpers.getDimensions("recttooltipText_" + mainDivName);
d3.selectAll("#recttooltipText_" + mainDivName + " tspan")
.attr("x", dims.w + 4);
d3.selectAll("#recttooltipRect_" + mainDivName)
.attr("width", dims.w + 10)
.attr("height", dims.h + 20);
}
});
d.on("mousemove", function() {
var currentEl = d3.select(this);
if(currentEl.style("opacity")!=0){
d3.selectAll("#recttooltip_" + mainDivName)
.attr("transform", function(d) {
var mouseCoords = d3.mouse(this.parentNode);
var xCo = 0;
if (mouseCoords[0] + 10 >= width * 0.80) {
xCo = mouseCoords[0] - parseFloat(d3.selectAll("#recttooltipRect_" + mainDivName)
.attr("width"));
} else {
xCo = mouseCoords[0] + 10;
}
var x = xCo;
var yCo = 0;
if (mouseCoords[0] + 10 >= width * 0.80) {
yCo = mouseCoords[1] + 10;
} else {
yCo = mouseCoords[1];
}
var x = xCo;
var y = yCo;
return "translate(" + x + "," + y + ")";
});
}
});
d.on("mouseout", function() {
var currentEl = d3.select(this);
if(currentEl.style("opacity")!=0){
currentEl.attr("opacity","0.6");
var currentRectClass = currentEl.attr("class").split(" ")[0];
if(currentRectClass.split("_")[0]=="planned"){
// d3.selectAll(".actual").attr("opacity","0.6");
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).attr("opacity","0.6");
}else{
// d3.selectAll(".planned").attr("opacity","0.6");
d3.selectAll(".planned_"+currentRectClass.split("_")[1]).attr("opacity","0.6");
}
d3.select("#recttooltip_" + mainDivName)
.style("opacity", function() {
return 0;
})
.attr("transform", function(d, i) {
// klutzy, but it accounts for tooltip padding which could push it onscreen
var x = -500;
var y = -500;
return "translate(" + x + "," + y + ")";
});
}
});
});
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("x", width / 2)
.attr("y", margin.bottom * 0.5)
.attr("dx", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("font-size", "15px")
.attr("text-anchor", "start")
.text("Month");
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", 0 - (height / 2))
.attr("y", 15 - (margin.left))
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("font-size", "15px")
.attr("text-anchor", "middle")
.text("Production Quantity(PCs)");
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(yActual))
var rectTooltipg = svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.attr("id", "recttooltip_" + mainDivName)
.attr("style", "opacity:0")
.attr("transform", "translate(-500,-500)");
rectTooltipg.append("rect")
.attr("id", "recttooltipRect_" + mainDivName)
.attr("x", 0)
.attr("width", 120)
.attr("height", 80)
.attr("opacity", 0.71)
.style("fill", "#000000");
rectTooltipg
.append("text")
.attr("id", "recttooltipText_" + mainDivName)
.attr("x", 30)
.attr("y", 15)
.attr("fill", function() {
return "#fff"
})
.style("font-size", function(d) {
return 10;
})
.style("font-family", function(d) {
return "arial";
})
.text(function(d, i) {
return "";
});
}
function type(d) {
d.date = parseDate(new Date(d.date));
groupPlan.forEach(function(c) {
if(d.hasOwnProperty(c)){
d[c] = +d[c];
}
});
return d;
}
var helpers = {
getDimensions: function(id) {
var el = document.getElementById(id);
var w = 0,
h = 0;
if (el) {
var dimensions = el.getBBox();
w = dimensions.width;
h = dimensions.height;
} else {
console.log("error: getDimensions() " + id + " not found.");
}
return {
w: w,
h: h
};
}
};
</script>
Modified http://code.jquery.com/jquery-latest.min.js to a secure url
https://code.jquery.com/jquery-latest.min.js
https://d3js.org/d3.v4.min.js