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