xxxxxxxxxx
<html>
<head>
<link href="./index.css" type="text/css" rel="stylesheet" />
</head>
<body>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="chart" width="800" height="500" style="width: 800;height: 500">
<svg width="800" height="450" class="chartSvg"></svg>
</div>
<script>
var groupChartData = [
{ "Team A": 0, "Team B": 0, over: 0 },
{ "Team A": 8, "Team B": 15, over: 1 },
{ "Team A": 15, "Team B": 17, over: 2 },
{ "Team A": 19, "Team B": 22, over: 3 },
{ "Team A": 38, "Team B": 30, over: 4 },
{ "Team A": 41, "Team B": 37, over: 5 },
{ "Team A": 47, "Team B": 38, over: 6 },
{ "Team A": 54, "Team B": 44, over: 7 },
{ "Team A": 67, "Team B": 46, over: 8 },
{ "Team A": 68, "Team B": 54, over: 9 },
{ "Team A": 76, "Team B": 63, over: 10 },
{ "Team A": 80, "Team B": 71, over: 11 },
{ "Team A": 80, "Team B": 91, over: 12 },
{ "Team A": 88, "Team B": 94, over: 13 },
{ "Team A": 93, "Team B": 103, over: 14 },
{ "Team A": 100, "Team B": 108, over: 15 },
{ "Team A": 109, "Team B": 122, over: 16 },
{ "Team A": 126, "Team B": 137, over: 17 },
{ "Team A": 147, "Team B": 147, over: 18 },
{ "Team A": 157, "Team B": 150, over: 19 },
{ "Team A": null, "Team B": 155, over: 20 }
];
var columnsInfo = { "Team A": "Team A", "Team B": "Team B" };
const width = 800;
const height = 450;
const margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
};
const xAxisField = "over";
const group1Field = "Team A";
const group2Field = "Team B";
const wordWrap = true;
const group1MinMax = d3.extent(groupChartData.map(d => d[group1Field]));
const group2MinMax = d3.extent(groupChartData.map(d => d[group2Field]));
const xAxisScale = d3
.scaleLinear()
.domain([0, d3.max(groupChartData.map(d => d[xAxisField]))])
.range([0, width - (margin.left + margin.right)]);
const yAxisScale = d3
.scaleLinear()
.domain([0, d3.max([...group1MinMax, ...group2MinMax])])
.range([height - (margin.top + margin.bottom), 0]);
const mainG = d3
.select(".chartSvg")
.append("g")
.attr("transform", `translate(0,0)`);
const xAxisG = mainG
.append("g")
.attr(
"transform",
`translate(${margin.left},${height - margin.bottom})`
)
.append("g")
.classed("xAxisG", true)
.attr("transform", `translate(0,0)`);
const yAxisG = mainG
.append("g")
.classed("yAxisG", true)
.attr("transform", `translate(${margin.left},${margin.top})`);
//CBT:draw x Axis start
let fontHeight;
groupChartData.forEach((data, index) => {
const values = data[xAxisField].toString();
const ticksG = xAxisG
.append("g")
.attr("class", "ticks")
.attr("transform", `translate(${xAxisScale(values)},0)`);
let wrappedTexts = [];
if (wordWrap == true && values.split(" ").length > 1) {
const textData = values.split(" ");
wrappedTexts = textData.map(textD => {
return ticksG
.append("text")
.style("text-anchor", "middle")
.style("font-size", "10px")
.style("fill", "#808080")
.text(textD);
});
} else {
ticksG
.append("text")
.style("text-anchor", "middle")
.style("font-size", "10px")
.style("fill", "#808080")
.text(values);
}
fontHeight = xAxisG
.select(".ticks text")
.node()
.getBBox().height;
if (wrappedTexts.length > 0) {
let yPosition = 0;
wrappedTexts.forEach(textPoint => {
textPoint.attr("y", yPosition);
yPosition = yPosition + fontHeight;
});
}
//CBT:tick line start
ticksG
.append("line")
.attr("x1", 0)
.attr("y1", -fontHeight)
.attr("x2", 0)
.attr("y2", -fontHeight + 4)
.style("stroke", "#C4C4C4");
if (index == groupChartData.length - 1) {
ticksG
.append("line")
.attr("x1", 0)
.attr("y1", -fontHeight)
.attr("x2", 0)
.attr("y2", -fontHeight + 4)
.style("stroke", "#C4C4C4");
}
//CBT:tick line end
});
//CBT:put axis down as font size
xAxisG.attr("transform", `translate(0,${fontHeight})`);
//CBT:add ticks line
xAxisG
.append("line")
.attr("x1", xAxisScale(groupChartData[0][xAxisField]))
.attr("y1", -fontHeight)
.attr(
"x2",
xAxisScale(groupChartData[groupChartData.length - 1][xAxisField])
)
.attr("y2", -fontHeight)
.style("stroke", "#C4C4C4");
//CBT:draw x axis label
xAxisG
.append("text")
.attr("x", (width - (margin.left + margin.right)) / 2)
.attr("y", margin.bottom * 0.5)
.attr("dx", "0.32em")
.style("fill", "#C4C4C4")
.style("font-weight", "bold")
.style("text-anchor", "start")
.text("Over");
//CBT:draw x Axis end
//CBT:draw y Axis start
yAxisG
.call(d3.axisLeft(yAxisScale))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -margin.left * 0.5)
.attr("x", -(height - (margin.top + margin.bottom)) / 2)
.style("fill", "#C4C4C4")
.style("font-weight", "bold")
.style("font-size", "14px")
.text("Runs");
//CBT:draw y Axis end
var line = d3
.line()
.x(function(d) {
return xAxisScale(d.x);
})
.y(function(d) {
return yAxisScale(d.y);
});
//CBT:Draw first line start
const group1Line = mainG
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
.append("g")
.classed("group1-line", true);
group1Line
.append("path")
.data([
groupChartData
.filter(function(d, i) {
//CBT:remove last blank or value is 0 data to show only that much of line
if (
(d[group1Field] != null && d[group1Field] != undefined) ||
i == 0
)
return d;
})
.map(d => {
return { x: d[xAxisField], y: d[group1Field] };
})
])
.attr("d", function(data) {
return line(data);
})
.style("stroke", function(d) {
return "#2a98cd";
})
.style("fill", "none")
.style("stroke-width", "3px");
//CBT:Draw first line end
//CBT:Draw second line start
const group2Line = mainG
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
.append("g")
.classed("group2-line", true);
group2Line
.append("path")
.data([
groupChartData
.filter(function(d, i) {
//CBT:remove last blank or value is 0 data to show only that much of line
if ((d[group2Field] != null && d[group2Field] != undefined) || i == 0)
return d;
})
.map(d => {
return { x: d[xAxisField], y: d[group2Field] };
})
])
.attr("d", function(data) {
return line(data);
})
.style("stroke", function(d) {
return "#df7247";
})
.style("fill", "none")
.style("stroke-width", "3px");
//CBT:Draw second line end
const circleRadius = 4;
const tooltip = mainG
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
var mouseOverG = mainG
.append("g")
.attr("class", "mouseOverEffect")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
const moveOnMouseOverG = mouseOverG
.append("g")
.attr("transform", "translate(0,0)");
const groupLine = moveOnMouseOverG
.append("path")
.attr("d", `M0 0 L0 ${height - (margin.bottom + margin.top)} Z`)
.attr("class", "mouse-line")
.style("stroke", "black")
.style("stroke-opacity", "0")
.style("stroke-width", "2px");
const group1Circle = moveOnMouseOverG
.append("circle")
.attr("r", circleRadius)
.style("fill", "transparent")
.style("stroke", "green")
.style("stroke-width", "2px")
.style("stroke-opacity", "0");
const group2Circle = moveOnMouseOverG
.append("circle")
.attr("r", circleRadius)
.style("fill", "transparent")
.style("stroke", "green")
.style("stroke-width", "2px")
.style("stroke-opacity", "0");
//CBT:tooltip start
var tooltipG = tooltip
.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("style", "opacity:0")
.attr("transform", `translate(0,0)`);
const rectTooltip = tooltipG.append("rect").style("fill", "#ccc");
const textTooltip = tooltipG.append("text").text("");
//CBT:tooltip end
mouseOverG
.append("svg:rect")
.data([groupChartData])
.attr("width", width - (margin.left + margin.right))
.attr("height", height - (margin.top + margin.bottom))
.attr("fill", "none")
.attr("pointer-events", "all")
.on("mouseenter", function(data) {
group1Circle.style("stroke-opacity", 1);
group2Circle.style("stroke-opacity", 1);
groupLine.style("stroke-opacity", 1);
tooltipG.style("opacity", 1);
})
.on("mouseout", function(data) {
group1Circle.style("stroke-opacity", 0);
group2Circle.style("stroke-opacity", 0);
groupLine.style("stroke-opacity", 0);
tooltipG.style("opacity", 0);
})
.on("mousemove", function(data) {
var mouse = d3.mouse(this);
console.log(
"X",
mouse[0],
"xValue:",
Math.round(xAxisScale.invert(mouse[0]))
);
moveOnMouseOverG.attr(
"transform",
`translate(${xAxisScale(
Math.round(xAxisScale.invert(mouse[0]))
)},0)`
);
let tooltipXPosition =
xAxisScale(Math.round(xAxisScale.invert(mouse[0]))) + 10;
const filteredData = data.filter(
d => d[xAxisField] == Math.round(xAxisScale.invert(mouse[0]))
);
textTooltip.text("Over:" + filteredData[0][xAxisField]);
const heightOfText = textTooltip.node().getBBox().height;
const widthOfText = textTooltip.node().getBBox().width;
textTooltip.text("");
textTooltip
.append("tspan")
.attr("y", heightOfText + 10)
.attr("x", 10)
.text("Over: " + filteredData[0][xAxisField]);
textTooltip
.append("tspan")
.attr("y", heightOfText * 2 + 15)
.attr("x", 10)
.text(group1Field + ": " + filteredData[0][group1Field]);
textTooltip
.append("tspan")
.attr("y", heightOfText * 3 + 20)
.attr("x", 10)
.text(group2Field + ": " + filteredData[0][group2Field]);
rectTooltip.attr("height", textTooltip.node().getBBox().height + 20);
rectTooltip.attr("width", textTooltip.node().getBBox().width + 20);
if (
textTooltip.node().getBBox().width + 20 + tooltipXPosition >
width - (margin.left + margin.right)
) {
tooltipXPosition =
tooltipXPosition - 20 - (textTooltip.node().getBBox().width + 20);
}
tooltipG.attr("transform", `translate(${tooltipXPosition},10)`);
if (filteredData.length > 0 && filteredData[0][group1Field] != null) {
group1Circle.style("stroke-opacity", 1);
group1Circle.style("cy", yAxisScale(filteredData[0][group1Field]));
} else {
group1Circle.style("stroke-opacity", 0);
}
if (filteredData.length > 0 && filteredData[0][group2Field] != null) {
group2Circle.style("stroke-opacity", 1);
group2Circle.style("cy", yAxisScale(filteredData[0][group2Field]));
} else {
group2Circle.style("stroke-opacity", 0);
}
});
//CBT:Legend Start
$("#chart").before(
"<div id='Legend_chart' class='pmd-card-body' style='margin-top:0; margin-bottom:0;'></div>"
);
var keys = [
{
color: "#2a98cd",
label: group1Field
},
{
color: "#df7247",
label: group2Field
}
];
keys.forEach(function(d) {
var cloloCode = d.color;
$("#Legend_chart").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.label +
" </span>\
</span>"
);
});
//CBT:Legend End
</script>
</body>
</html>
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