function multiSeriesLineChart(config) { function setReSizeEvent(data) { var resizeTimer; window.removeEventListener('resize', function() {}); window.addEventListener('resize', function(event) { if (resizeTimer !== false) { clearTimeout(resizeTimer); } resizeTimer = setTimeout(function() { $(data.mainDiv).empty(); drawmultiSeriesLineChartCharts(data); clearTimeout(resizeTimer); }, 500); }); } drawmultiSeriesLineChartCharts(config); setReSizeEvent(config); } function createmultiSeriesLineChartLegend(mainDiv, columnsInfo, colorRange) { var z = d3.scaleOrdinal() .range(colorRange); var mainDivName = mainDiv.substr(1, mainDiv.length); $(mainDiv).before("
"); var keys = Object.keys(columnsInfo); keys.forEach(function(d) { var cloloCode = z(d); $("#Legend_" + mainDivName).append("\  \ " + columnsInfo[d] + " \ "); }); } function drawmultiSeriesLineChartCharts(config) { var keys = Object.keys(config.data[0]); var tempObj = {}; keys.forEach(function(d) { tempObj[d] = 0; }); config.data.splice(0, 0, tempObj); var data = config.data; var columnsInfo = config.columnsInfo; var xAxis = config.xAxis; var yAxis = config.yAxis; var colorRange = config.colorRange; var mainDiv = config.mainDiv; var mainDivName = mainDiv.substr(1, mainDiv.length); var label = config.label; var requireCircle = config.requireCircle || false; var requireLegend = config.requireLegend; var imageData = config.imageData; d3.select(mainDiv).append("svg").attr("width", $(mainDiv).width()).attr("height", $(mainDiv).height() * 0.9); var svg = d3.select(mainDiv + " svg"), margin = { top: 20, right: 20, bottom: 30, left: 50 }, width = svg.attr("width") - margin.left - margin.right, height = svg.attr("height") - margin.top - margin.bottom; var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var mouseOverG = svg.append("g").attr("class", "mouseOverEffect") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); mouseOverG.append("path") .attr("class", "mouse-line") .style("stroke", "black") .style("opacity", "0") .style("stroke-width", "2px"); if (requireLegend != null && requireLegend != undefined && requireLegend != false) { $("#Legend_" + mainDivName).remove(); createmultiSeriesLineChartLegend(mainDiv, columnsInfo, colorRange); } var x = d3.scaleLinear().range([0, width]), y = d3.scaleLinear().range([height, 0]), z = d3.scaleOrdinal() .range(colorRange); var line = d3.line() .x(function(d) { return x(d[xAxis]); }) .y(function(d) { return y(d[yAxis]); }); var columns = Object.keys(columnsInfo); var groupData = columns.map(function(id) { return { id: id, values: data.filter(function(d, i) { //CBT:remove last blank or value is 0 data to show only that much of line if ((d[id] != 0 && d[id] != null && d[id] != undefined) || i == 0) return d; }).map(function(d, i) { var tempObj = {}; tempObj[xAxis] = d[xAxis]; tempObj[yAxis] = d[id]; return tempObj; }) }; }); x.domain(d3.extent(data, function(d) { return d[xAxis]; })); y.domain([ d3.min(groupData, function(c) { return d3.min(c.values, function(d) { return d[yAxis]; }); }), d3.max(groupData, function(c) { return d3.max(c.values, function(d) { return d[yAxis]; }); }) ]); z.domain(groupData.map(function(c) { return c.id; })); g.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)) .append("text") .attr("x", width / 2) .attr("y", margin.bottom * 0.9) .attr("dx", "0.32em") .attr("fill", "#000") .attr("font-weight", "bold") .attr("text-anchor", "start") .text(label.xAxis); g.append("g") .attr("class", "axis axis--y") .call(d3.axisLeft(y)) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", "0.71em") .attr("fill", "#000") .attr("font-weight", "bold") .text(label.yAxis); var city = g.selectAll(".city") .data(groupData) .enter().append("g") .attr("class", "city"); city.append("path") .attr("class", "line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) { return z(d.id); }).style("fill", "none").style("stroke-width", "3px"); var lines = document.getElementsByClassName("line"); var mousePerLine = mouseOverG.selectAll(".mousePerLine") .data(groupData) .enter().append("g") .attr("class", "mousePerLine"); //CBT:for wicket Circles in multiseries line chart var circleRadius = 4; var keys = Object.keys(columnsInfo); var circles = mousePerLine.append("circle") .attr("class", "mousePerLineCircle") .attr("r", circleRadius) .attr("fill", "green") .attr("fill-opacity", function(d) { return 1; }) mouseOverG.append("svg:rect") .attr("width", width) .attr("height", height) .attr("fill", "none") .attr("pointer-events", "all") .on("mouseout", function() { d3.select(".mouse-line") .style("opacity", "0"); d3.selectAll(".mousePerLineCircle") .style("opacity", "0"); d3.select("#circletooltip_" + mainDivName) .transition() .style("opacity", function() { return 0; }); d3.select("#circletooltipbottom_" + mainDivName) .transition() .style("opacity", function() { return 0; }); }) .on("mouseover", function() { d3.select(".mouse-line") .style("opacity", "1"); d3.selectAll(".mousePerLineCircle") .style("opacity", "1"); }) .on("mousemove", function() { var mouse = d3.mouse(this); d3.select(".mouse-line") .attr("d", function() { var d = "M" + mouse[0] + "," + height + " " + mouse[0] + "," + 0; return d; }); d3.selectAll(".mousePerLine") .attr("transform", function(d, i) { var xData = x.invert(mouse[0]); var bisect = d3.bisector(function(d) { return d.runs; }).right; var idx = bisect(d.values, xData); var beginning = 0; var end = lines[i].getTotalLength(); var target = null; while (true) { target = Math.floor((beginning + end) / 2); pos = lines[i].getPointAtLength(target); if ((target == end || target == beginning) && pos.x != mouse[0]) { break; } if (pos.x > mouse[0]) { end = target; } else if (pos.x < mouse[0]) { beginning = target; } else { break; } d3.select("#circletooltip_" + mainDivName).attr("transform", function(d) { var mouseCoords = mouse; var xCo = 0; if (mouseCoords[0] + 10 >= width * 0.80) { xCo = mouseCoords[0] - (parseFloat(d3.selectAll("#circletooltipRect_" + mainDivName) .attr("width")) + 10); } 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 + ")"; }); d3.select("#circletooltipbottom_" + mainDivName).attr("transform", function(d) { var mouseCoords = mouse; var xCo = 0; if (mouseCoords[0] + 10 >= width * 0.80) { xCo = mouseCoords[0] - (parseFloat(d3.selectAll("#circletooltipRectbottom_" + mainDivName) .attr("width")) + 10); } else { xCo = mouseCoords[0] + 10; } var x = xCo; var yCo = 0; if (mouseCoords[0] + 10 >= width * 0.80) { yCo = mouseCoords[1] + 70; } else { yCo = mouseCoords[1] + 60; } var x = xCo; var y = yCo; return "translate(" + x + "," + y + ")"; }); } var fadeInSpeed = 120; d3.select("#circletooltip_" + mainDivName) .transition() .duration(fadeInSpeed) .style("opacity", function() { return 1; }); d3.select("#circletooltipbottom_" + mainDivName) .transition() .duration(fadeInSpeed) .style("opacity", function() { return 1; }); var columns = Object.keys(columnsInfo); if (columns[0] == d["id"]) { var tooltipsText = y.invert(pos.y); d3.selectAll("#circletooltipText_" + mainDivName).text(""); var yPos = 0; d3.selectAll("#circletooltipText_" + mainDivName).append("tspan").attr("x", 0).attr("y", yPos * 10).attr("dy", "1.9em").text("Over" + ": " + parseInt(xData)); yPos = yPos + 1; d3.selectAll("#circletooltipText_" + mainDivName).append("tspan").attr("x", 0).attr("y", yPos * 10).attr("dy", "1.9em").text("Runs" + ": " + parseInt(tooltipsText)); //CBT:calculate width of the text based on characters var dims = helpers.getDimensions("circletooltipText_" + mainDivName); d3.selectAll("#circletooltipText_" + mainDivName + " tspan") .attr("x", dims.w + 4); d3.selectAll("#circletooltipRect_" + mainDivName) .attr("width", dims.w + 10) .attr("height", dims.h + 20); } else { var tooltipsText = y.invert(pos.y); d3.selectAll("#circletooltipTextbottom_" + mainDivName).text(""); var yPos = 0; d3.selectAll("#circletooltipTextbottom_" + mainDivName).append("tspan").attr("x", 0).attr("y", yPos * 10).attr("dy", "1.9em").text("Over" + ": " + parseInt(xData)); yPos = yPos + 1; d3.selectAll("#circletooltipTextbottom_" + mainDivName).append("tspan").attr("x", 0).attr("y", yPos * 10).attr("dy", "1.9em").text("Runs" + ": " + parseInt(tooltipsText)); //CBT:calculate width of the text based on characters var dims = helpers.getDimensions("circletooltipTextbottom_" + mainDivName); d3.selectAll("#circletooltipTextbottom_" + mainDivName + " tspan") .attr("x", dims.w + 4); d3.selectAll("#circletooltipRectbottom_" + mainDivName) .attr("width", dims.w + 10) .attr("height", dims.h + 20); } return "translate(" + mouse[0] + "," + pos.y + ")"; }); }) var circleTooltipg = g.append("g") .attr("font-family", "sans-serif") .attr("font-size", 10) .attr("text-anchor", "end") .attr("id", "circletooltip_" + mainDivName) .attr("style", "opacity:0") .attr("transform", "translate(-500,-500)"); circleTooltipg.append("rect") .attr("id", "circletooltipRect_" + mainDivName) .attr("x", 0) .attr("width", 120) .attr("height", 80) .attr("opacity", 0.71) .style("fill", "#2a98cd"); circleTooltipg .append("text") .attr("id", "circletooltipText_" + 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 ""; }); var circleTooltipgbottom = g.append("g") .attr("font-family", "sans-serif") .attr("font-size", 10) .attr("text-anchor", "end") .attr("id", "circletooltipbottom_" + mainDivName) .attr("style", "opacity:0") .attr("transform", "translate(-500,-500)"); circleTooltipgbottom.append("rect") .attr("id", "circletooltipRectbottom_" + mainDivName) .attr("x", 0) .attr("width", 120) .attr("height", 80) .attr("opacity", 0.71) .style("fill", "#df7247"); circleTooltipgbottom .append("text") .attr("id", "circletooltipTextbottom_" + 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 ""; }); } 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 }; } };