function multiSeriesLineChart(config) { drawmultiSeriesLineChartCharts(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 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: 40, right: 20, bottom: 80, 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 middleLineg = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); if (requireLegend != null && requireLegend != undefined && requireLegend != false) { $("#Legend_" + mainDivName).remove(); createmultiSeriesLineChartLegend(mainDiv, columnsInfo, colorRange); } var parseTime = d3.timeParse("%d-%b-%y"); data.forEach(function (d) { d.startDate = parseTime(d.startDate); }); var x = d3.scaleTime().range([0, width]), y = d3.scaleLinear().range([height, 0]), yBatch = 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 lineBatch = d3.line() .x(function (d) { return x(d[xAxis]); }) .y(function (d) { return yBatch(d["productBSales"]); }); 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["startDate"] != 0 && d["startDate"] != null && d["startDate"] != undefined)) return d; }).map(function (d, i) { var tempObj = {}; tempObj[xAxis] = d[xAxis]; tempObj[yAxis] = d[id]; tempObj["productBSales"] = d["productBSales"]; tempObj["data"] = d; 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]; }); }) ]); yBatch.domain([ d3.min(groupData, function (c) { return d3.min(c.values, function (d) { return d["productBSales"]; }); }), d3.max(groupData, function (c) { return d3.max(c.values, function (d) { return d["productBSales"]; }); }) ]); z.domain(groupData.map(function (c) { return c.id; })); var middleLine = middleLineg.append("path") .attr("class", "mouse-line") .style("stroke-width", "3px") .style("opacity", function () { return 0; }) .style("stroke", "black"); var ele = g.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%d-%b")).ticks(31)); ele.selectAll("text") .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", ".15em") .attr("transform", "rotate(-65)"); ele.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); g.append("g") .attr("class", "axis axis--y") .attr("transform", "translate(" + width + ",0)") .call(d3.axisLeft(yBatch)) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", "0.71em") .attr("fill", "#000") .attr("font-weight", "bold") .text("Product B Sales (Lacks)"); var city = g.selectAll(".city") .data(groupData) .enter().append("g") .attr("class", "city"); city.append("path") .attr("class", "line") .style("stroke", function (d) { return 'solid'; }) .attr("d", function (d) { if (d.id == "productASales") { return line(d.values); } else { return lineBatch(d.values); } }) .style("stroke", function (d) { return z(d.id); }).style("fill", "none").style("stroke-width", "3px"); var lines = document.getElementsByClassName("line"); var mousePerLine = middleLineg.selectAll(".mousePerLine") .data(groupData) .enter().append("g") .attr("class", "mousePerLine"); var circleRadius = 4; var keys = Object.keys(columnsInfo); var circles = mousePerLine.append("circle") .attr("class", "mousePerLineCircle") .attr("r", circleRadius) .attr("fill", function (d) { if (d.id == "productASales") { return "red"; } else { return "green"; } }) .attr("fill-opacity", function (d) { return 1; }); var element = g.append("g") .selectAll("g") .data(data) .enter().append("g") .attr("transform", function (d) { return "translate(" + x(d[xAxis]) + ",0)"; }); var circlesAll = element.selectAll("circle") .data(function (d) { return keys.map(function (key) { return { key: key, value: d[key] }; }); }) .enter().append("circle") .attr("cx", function (d) { return 0; }) .attr("cy", function (d) { if (d.key == "productASales") { return y(d.value); } else { return yBatch(d.value); } }) .attr("r", circleRadius) .attr("fill", function (d) { if (d.key == "productASales") { return "red"; } else { return "green"; } }) .attr("fill-opacity", function (d) { return 1; }) var prevSelectedDateMultiSeries = ""; var toolTipDate = ""; middleLineg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("fill", "none") .attr("pointer-events", "all") .on("mouseout", function () { 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"); var fadeInSpeed = 120; d3.select("#circletooltipdate_" + mainDivName) .transition() .duration(fadeInSpeed) .style("opacity", function () { return 1; }); d3.select("#circletooltip_" + mainDivName) .transition() .duration(fadeInSpeed) .style("opacity", function () { return 1; }); d3.select("#circletooltipbottom_" + mainDivName) .transition() .duration(fadeInSpeed) .style("opacity", function () { return 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]); if (i == 0) { if (prevSelectedDateMultiSeries != d3.timeFormat("%Y-%m-%d")(xData)) { prevSelectedDateMultiSeries = d3.timeFormat("%Y-%m-%d")(xData); toolTipDate = d3.timeFormat("%d-%b-%Y")(xData); //CBT:show tips } } var bisect = d3.bisector(function (d) { return d.startDate; }).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("#circletooltipdate_" + mainDivName).attr("transform", function (d) { var mouseCoords = mouse; var xCo = 0; if (mouseCoords[0] + 10 >= width * 0.80) { xCo = mouseCoords[0] - (parseFloat(d3.selectAll("#circletooltipRectdate_" + 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 + "," + -30 + ")"; }); 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; var yPos = 0; var fontSize = "12px"; d3.selectAll("#circletooltipTextdate_" + mainDivName).text(""); d3.selectAll("#circletooltipTextdate_" + mainDivName).append("tspan").attr("x", 0).attr("y", 2).attr("dy", "1.9em").text(toolTipDate) .attr("font-size", fontSize); var dims = helpers.getDimensions("circletooltipTextdate_" + mainDivName); d3.selectAll("#circletooltipTextdate_" + mainDivName + " tspan") .attr("x", dims.w + 4); d3.selectAll("#circletooltipRectdate_" + mainDivName) .attr("width", dims.w + 10) .attr("height", dims.h + 20); var columns = Object.keys(columnsInfo); var tooltipsText = yBatch.invert(pos.y); if (columns[0] != d["id"]) { var tooltipRecords = d.values.filter(function (d1) { var startDateD = new Date(d3.timeFormat("%Y-%b-%d 00:00:00")(new Date(d1.startDate))); var endDateD = new Date(d3.timeFormat("%Y-%b-%d 23:59:59")(new Date(d1.startDate))); var selectedDated = new Date(d3.timeFormat("%Y-%b-%d 00:00:00")(new Date(xData))); if (selectedDated.getTime() >= startDateD.getTime() && selectedDated.getTime() <= endDateD.getTime()) { return d1.data } }); if (tooltipRecords.length != 0) { d3.selectAll("#circletooltipText_" + mainDivName).text(""); d3.selectAll("#circletooltipText_" + mainDivName).append("tspan").attr("x", 0).attr("y", 2).attr("dy", "1.9em").text((tooltipRecords[0].data.productBSales)) .attr("font-size", fontSize); 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 tooltipRecords = d.values.filter(function (d1) { var startDateD = new Date(d3.timeFormat("%Y-%b-%d 00:00:00")(new Date(d1.startDate))); var endDateD = new Date(d3.timeFormat("%Y-%b-%d 23:59:59")(new Date(d1.startDate))); var selectedDated = new Date(d3.timeFormat("%Y-%b-%d 00:00:00")(new Date(xData))); if (selectedDated.getTime() >= startDateD.getTime() && selectedDated.getTime() <= endDateD.getTime()) { return d1.data } }); if (tooltipRecords.length != 0) { d3.selectAll("#circletooltipTextbottom_" + mainDivName).text(""); d3.selectAll("#circletooltipTextbottom_" + mainDivName).append("tspan").attr("x", 0).attr("y", 2).attr("dy", "1.9em").text((tooltipRecords[0].data.productASales)) .attr("font-size", fontSize); 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", 0) .attr("height", 0) .attr("opacity", 0.71) .style("fill", "green"); 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 circleTooltipBottomg = 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)"); circleTooltipBottomg.append("rect") .attr("id", "circletooltipRectbottom_" + mainDivName) .attr("x", 0) .attr("width", 0) .attr("height", 0) .attr("opacity", 0.71) .style("fill", "red"); circleTooltipBottomg .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 circleTooltipDateg = g.append("g") .attr("font-family", "sans-serif") .attr("font-size", 10) .attr("text-anchor", "end") .attr("id", "circletooltipdate_" + mainDivName) .attr("style", "opacity:0") .attr("transform", "translate(-500,-500)"); circleTooltipDateg.append("rect") .attr("id", "circletooltipRectdate_" + mainDivName) .attr("x", 0) .attr("width", 120) .attr("height", 80) .attr("opacity", 0.71) .style("fill", "#000000"); circleTooltipDateg .append("text") .attr("id", "circletooltipTextdate_" + 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 "Hello"; }); } 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 }; } };