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>
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;'>\
<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>");
});
}
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";
createChartLegend(mainDiv, ["Planned Production","Actual Production"]);
var plannedData = [{
'date': '2017-06-30T18:30:00.000Z',
'Ram': 500,
'Laptops':505,
'Processor': 350,
'Harddisk':270
}, {
'date': '2017-07-31T18:30:00.000Z',
'Monitor': 800,
'Keyboard': 560,
'Mouse': 630
},
{
'date': '2017-08-31T18:30:00.000Z',
'Ram': 788,
'Monitor': 810,
'Harddisk': 705
}, {
'date': '2017-09-30T18:30:00.000Z',
'Keyboard': 503,
'Mouse': 532,
'Monitor': 428
}, {
'date': '2017-10-31T18:30:00.000Z',
'Harddisk': 844,
'Ram': 287,
'Processor': 506
}, {
'date': '2017-11-30T18:30:00.000Z',
'Monitor': 1725,
'Keyboard': 114,
'Ram': 131
}, {
'date': '2017-12-31T18:30:00.000Z',
'Ram': 2761,
'Laptops': 83,
'Processor': 324
},
{
'date': '2018-01-31T18:30:00.000Z',
'Mouse': 2120,
'Monitor': 242,
'Processor': 361
}, {
'date': '2018-02-28T18:30:00.000Z',
'Keyboard': 1205,
'Ram': 320,
'Processor': 172
}, {
'date': '2018-03-31T18:30:00.000Z',
'Monitor': 477,
'Laptops': 480,
'Processor': 507
}, {
'date': '2018-04-30T18:30:00.000Z',
'Keyboard': 508,
'Harddisk': 490,
'Processor': 370
}
];
var actualData = [{
'date': '2017-06-30T18:30:00.000Z',
'Keyboard': 1200,
'Harddisk': 300,
'Processor': 200
}, {
'date': '2017-07-31T18:30:00.000Z',
'Ram': 400,
'Laptops':500,
'Processor': 350,
'Harddisk':700
},
{
'date': '2017-08-31T18:30:00.000Z',
'Monitor': 828,
'Keyboard': 501,
'Mouse': 300
}, {
'date': '2017-09-30T18:30:00.000Z',
'Ram': 520,
'Laptops': 320,
'Processor': 258
}, {
'date': '2017-10-31T18:30:00.000Z',
'Keyboard': 1103,
'Mouse': 832,
'Monitor': 728
}, {
'date': '2017-11-30T18:30:00.000Z',
'Ram': 555,
'Laptops': 425,
'Processor': 831
}, {
'date': '2017-12-31T18:30:00.000Z',
'Monitor': 1725,
'Keyboard': 214,
'Ram': 331
},
{
'date': '2018-01-31T18:30:00.000Z',
'Ram': 1761,
'Laptops': 830,
'Processor': 324
}, {
'date': '2018-02-28T18:30:00.000Z',
'Mouse': 1120,
'Monitor': 420,
'Processor': 661
}, {
'date': '2018-03-31T18:30:00.000Z',
'Keyboard': 1205,
'Ram': 320,
'Processor': 872
}, {
'date': '2018-04-30T18:30:00.000Z',
'Monitor': 477,
'Laptops': 480,
'Processor': 570
}
];
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/2)]);
var yActual = d3.scaleLinear()
.rangeRound([(height/2)-10,margin.top]);
y.domain([d3.min(layers, stackMin), d3.max(layers, stackMax)]);
yActual.domain([d3.min(layersActual, stackMinActual), d3.max(layersActual, stackMaxActual)])
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;
})
.attr("opacity", 0.6)
.attr("fill", function(d) {
return z(d.key);
})
.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;
})
.attr("opacity", 0.6)
.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("mouseover", function() {
var currentEl = d3.select(this);
var fadeInSpeed = 120;
d3.select("#recttooltip_" + mainDivName)
.transition()
.duration(fadeInSpeed)
.style("opacity", function() {
return 1;
});
currentEl.attr("opacity","1");
var currentRectClass = currentEl.attr("class");
if(currentRectClass.split("_")[0]=="planned"){
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).attr("opacity","1");
}else{
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);
currentEl.attr("r", 7);
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);
currentEl.attr("opacity","0.6");
var currentRectClass = currentEl.attr("class");
if(currentRectClass.split("_")[0]=="planned"){
d3.selectAll(".actual_"+currentRectClass.split("_")[1]).attr("opacity","0.6");
}else{
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))
// .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("text-anchor", "middle")
// .text("Sales");
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