File indexing completed on 2024-05-19 06:00:30

0001 
0002 function makeLineChart(dataset, xName, yObjs, axisLables) {
0003     var chartObj = {};     
0004     var color = d3.scaleOrdinal().range(["#1F77B4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c"
0005         ,"#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"
0006         ,"#8c564b","#c49c94","#e377c2","#f7b6d2","#7f7f7f"
0007         ,"#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5"
0008         ,"#393b79","#5254a3","#6b6ecf","#9c9ede","#637939"
0009         ,"#b5cf6b","#cedb9c","#8c6d31","#bd9e39","#e7ba52"
0010         ,"#ad494a","#d6616b","#7b4173","#a55194","#ce6dbd"]);
0011     chartObj.xAxisLable = axisLables.xAxis;
0012     chartObj.yAxisLable = axisLables.yAxis;
0013     /*
0014      yObjsects format:
0015      {y1:{column:'',name:'name',color:'color'},y2}
0016      */
0017 
0018     chartObj.data = dataset;
0019     chartObj.margin = {top: 15, right: 60, bottom: 60, left: 50};
0020     chartObj.width = 750 - chartObj.margin.left - chartObj.margin.right;
0021     chartObj.height = 580 - chartObj.margin.top - chartObj.margin.bottom;
0022 
0023 // So we can pass the x and y as strings when creating the function
0024     chartObj.xFunct = function(d){return d[xName]};
0025  
0026 // For each yObjs argument, create a yFunction
0027     function getYFn(column) {
0028         return function (d) {
0029             return d[column];
0030         };
0031     }
0032 
0033 // Object instead of array
0034     chartObj.yFuncts = [];
0035     for (var y  in yObjs) {
0036         yObjs[y].name = y;
0037         yObjs[y].yFunct = getYFn(yObjs[y].column); //Need this  list for the ymax function
0038         chartObj.yFuncts.push(yObjs[y].yFunct);
0039     }
0040 
0041 //Formatter functions for the axes
0042     chartObj.formatAsNumber = d3.format(".0f");
0043     chartObj.formatAsDecimal = d3.format(".2f");
0044     chartObj.formatAsCurrency = d3.format("$.2f");
0045     chartObj.formatAsYYYYMM = d3.timeFormat("%Y-%m");
0046 
0047     
0048     chartObj.formatAsFloat = function (d) {
0049         if (d % 1 !== 0) {
0050             return d3.format(".2f")(d);
0051         } else {
0052             return d3.format(".0f")(d);
0053         }
0054         
0055     };
0056 
0057     chartObj.xFormatter = chartObj.formatAsYYYYMM;
0058     chartObj.yFormatter = chartObj.formatAsFloat;
0059 
0060     chartObj.bisectYear = d3.bisector(chartObj.xFunct).left; //< Can be overridden in definition
0061 
0062 //Create scale functions
0063     //chartObj.xScale = d3.scaleLinear().range([0, chartObj.width]).domain(d3.extent(chartObj.data, chartObj.xFunct)); 
0064 
0065     // console.log(">>>>>>>>>>>>>>>>>>>>>>");
0066     // console.log(d3.extent(chartObj.data, chartObj.xFunct));
0067     chartObj.xScale = d3.scaleTime().range([0, chartObj.width]).domain(d3.extent(chartObj.data, chartObj.xFunct));                                                  
0068 
0069 // Get the max of every yFunct
0070     chartObj.max = function (fn) {
0071         return d3.max(chartObj.data, fn);
0072     };
0073     chartObj.yScale = d3.scaleLinear().range([chartObj.height, 0]).domain([0, d3.max(chartObj.yFuncts.map(chartObj.max))]);
0074 
0075     
0076 
0077 //Create axis
0078 
0079     var numofticks=20;
0080     if(dataset.length<numofticks)
0081     {
0082         numofticks = dataset.length;
0083     }  
0084     chartObj.xAxis  = d3.axisBottom(chartObj.xScale).ticks(numofticks).tickFormat(chartObj.xFormatter);    
0085     chartObj.yAxis = d3.axisLeft(chartObj.yScale).tickFormat(chartObj.yFormatter);
0086 
0087 
0088 // Build line building functions
0089     function getYScaleFn(yObj) {
0090         return function (d) {
0091             return chartObj.yScale(yObjs[yObj].yFunct(d));
0092         };
0093     }
0094 
0095     for (var yObj in yObjs) {
0096         yObjs[yObj].line = d3.line().x(function (d) {
0097             return chartObj.xScale(chartObj.xFunct(d));
0098         }).y(getYScaleFn(yObj));
0099     }
0100     
0101 
0102     chartObj.svg;
0103 
0104 // Change chart size according to window size
0105     chartObj.update_svg_size = function () {
0106         chartObj.width = parseInt(chartObj.chartDiv.style("width"), 10) - (chartObj.margin.left + chartObj.margin.right);
0107 
0108         chartObj.height = parseInt(chartObj.chartDiv.style("height"), 10) - (chartObj.margin.top + chartObj.margin.bottom);
0109 
0110         /* Update the range of the scale with new width/height */
0111         chartObj.xScale.range([0, chartObj.width]);
0112         chartObj.yScale.range([chartObj.height, 0]);
0113 
0114         if (!chartObj.svg) {return false;}
0115 
0116         /* Else Update the axis with the new scale */
0117         chartObj.svg.select('.x.axis').attr("transform", "translate(0," + chartObj.height + ")").call(chartObj.xAxis);
0118 
0119         
0120         chartObj.svg.select('.x.axis .label').attr("x", chartObj.width / 2);
0121 
0122         chartObj.svg.select('.y.axis').call(chartObj.yAxis);
0123         chartObj.svg.select('.y.axis .label').attr("x", -chartObj.height / 2);
0124 
0125         /* Force D3 to recalculate and update the line */
0126         for (var y  in yObjs) {
0127             yObjs[y].path.attr("d", yObjs[y].line);
0128         }
0129         
0130 
0131         d3.selectAll(".focus.line").attr("y2", chartObj.height);
0132 
0133         chartObj.chartDiv.select('svg').attr("width", chartObj.width + (chartObj.margin.left + chartObj.margin.right)).attr("height", chartObj.height + (chartObj.margin.top + chartObj.margin.bottom));
0134 
0135         chartObj.svg.select(".overlay").attr("width", chartObj.width).attr("height", chartObj.height);
0136         return chartObj;
0137     };
0138 
0139     chartObj.bind = function (selector) {
0140         chartObj.mainDiv = d3.select(selector);
0141         // Add all the divs to make it centered and responsive
0142         chartObj.mainDiv.append("div").attr("class", "inner-wrapper").append("div").attr("class", "outer-box").append("div").attr("class", "inner-box");
0143         chartSelector = selector + " .inner-box";
0144         chartObj.chartDiv = d3.select(chartSelector);
0145         d3.select(window).on('resize.' + chartSelector, chartObj.update_svg_size);
0146         chartObj.update_svg_size();
0147         return chartObj;
0148     };
0149 
0150 // Render the chart
0151     chartObj.render = function () {
0152         //Create SVG element
0153         chartObj.svg = chartObj.chartDiv.append("svg").attr("class", "chart-area").attr("width", chartObj.width + (chartObj.margin.left + chartObj.margin.right)).attr("height", chartObj.height + (chartObj.margin.top + chartObj.margin.bottom)).append("g").attr("transform", "translate(" + chartObj.margin.left + "," + chartObj.margin.top + ")");
0154 
0155         // Draw Lines
0156         for (var y  in yObjs) {
0157             yObjs[y].path = chartObj.svg.append("path").datum(chartObj.data).attr("class", "line").attr("d", yObjs[y].line).style("stroke", color(y)).attr("data-series", y).on("mouseover", function () {
0158                 focus.style("display", null);
0159             }).on("mouseout", function () {
0160                 focus.transition().delay(700).style("display", "none");
0161             }).on("mousemove", mousemove);
0162         }
0163         
0164 
0165         // Draw Axis
0166         chartObj.svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + chartObj.height + ")").call(chartObj.xAxis).append("text").attr("class", "label").attr("x", chartObj.width / 2).attr("y", 30).style("text-anchor", "middle").text(chartObj.xAxisLable);
0167         
0168         chartObj.svg.selectAll("text")
0169             .attr("y", 0)
0170             .attr("x", 9)
0171             .attr("dy", ".35em")
0172             .attr("transform", "rotate(90)")
0173             .style("text-anchor", "start");
0174 
0175 
0176         chartObj.svg.append("g").attr("class", "y axis").call(chartObj.yAxis).append("text").attr("class", "label").attr("transform", "rotate(-90)").attr("y", -42).attr("x", -chartObj.height / 2).attr("dy", ".71em").style("text-anchor", "middle").text(chartObj.yAxisLable);
0177 
0178        
0179         
0180         var datasetNotDone = dataset.filter(d => d.cnt == 0);
0181         var datasetDone = dataset.filter(d => d.cnt == 1);
0182         
0183         
0184          for (var y  in yObjs) {
0185         // Appends a circle for each datapoint 
0186             chartObj.svg.selectAll(".dot")
0187             .data(datasetDone)
0188             .enter().append("circle") // Uses the enter().append() method
0189             .attr("class", "dot") // Assign a class for styling
0190             .attr("cx", function(d) { return chartObj.xScale(chartObj.xFunct(d)) })
0191             .attr("cy", function(d) { return chartObj.yScale(yObjs[y].yFunct(d)) })
0192             .attr("r", 5);
0193                 
0194             }
0195 
0196           for (var y  in yObjs) {
0197         // Appends a circle for each datapoint 
0198             chartObj.svg.selectAll(".dotRed")
0199             .data(datasetNotDone)
0200             .enter().append("circle") // Uses the enter().append() method
0201             .attr("class", "dotRed") // Assign a class for styling
0202             .attr("cx", function(d) { return chartObj.xScale(chartObj.xFunct(d)) })
0203             .attr("cy", function(d) { return chartObj.yScale(yObjs[y].yFunct(d)) })
0204             .attr("r", 5);
0205                 
0206             }
0207 
0208          
0209 
0210 
0211 
0212         //Draw tooltips
0213         var focus = chartObj.svg.append("g").attr("class", "focus").style("display", "none");
0214 
0215 
0216         for (var y  in yObjs) {
0217             yObjs[y].tooltip = focus.append("g");
0218             yObjs[y].tooltip.append("circle").attr("r", 5);
0219             yObjs[y].tooltip.append("rect").attr("x", 8).attr("y","-5").attr("width",22).attr("height",'0.75em');
0220             yObjs[y].tooltip.append("text").attr("x", 9).attr("dy", ".35em");
0221         }
0222 
0223         // Year label
0224         focus.append("text").attr("class", "focus year").attr("x", 9).attr("y", 7);
0225         // Focus line
0226         focus.append("line").attr("class", "focus line").attr("y1", 0).attr("y2", chartObj.height);
0227 
0228         //Draw legend
0229         var legend = chartObj.mainDiv.append('div').attr("class", "legend");
0230         for (var y  in yObjs) {
0231             series = legend.append('div');
0232             series.append('div').attr("class", "series-marker").style("background-color", color(y));
0233             series.append('p').text(y);
0234             yObjs[y].legend = series;
0235         }
0236 
0237         // Overlay to capture hover
0238         chartObj.svg.append("rect").attr("class", "overlay").attr("width", chartObj.width).attr("height", chartObj.height).on("mouseover", function () {
0239             focus.style("display", null);
0240         }).on("mouseout", function () {
0241             focus.style("display", "none");
0242         }).on("mousemove", mousemove);
0243 
0244         return chartObj;
0245         function mousemove() {
0246             
0247             var x0 = chartObj.xScale.invert(d3.mouse(this)[0]), i = chartObj.bisectYear(dataset, x0, 1), d0 = chartObj.data[i - 1], d1 = chartObj.data[i];
0248 
0249             try {
0250                 var d = x0 - chartObj.xFunct(d0) > chartObj.xFunct(d1) - x0 ? d1 : d0;
0251 
0252             } catch (e) {  console.log(e); return;}
0253             minY = chartObj.height;
0254             for (var y  in yObjs) {
0255                 yObjs[y].tooltip.attr("transform", "translate(" + chartObj.xScale(chartObj.xFunct(d)) + "," + chartObj.yScale(yObjs[y].yFunct(d)) + ")");
0256                 yObjs[y].tooltip.select("text").text(chartObj.yFormatter(yObjs[y].yFunct(d)));
0257                 minY = Math.min(minY, chartObj.yScale(yObjs[y].yFunct(d)));
0258             }
0259 
0260             focus.select(".focus.line").attr("transform", "translate(" + chartObj.xScale(chartObj.xFunct(d)) + ")").attr("y1", minY);
0261             focus.select(".focus.year").text("Yearmonth: " + chartObj.xFormatter(chartObj.xFunct(d)));
0262         }
0263 
0264     };
0265     return chartObj;
0266 }
0267 
0268