/// <summary> /// 通过实体list生成报表 /// </summary> /// <typeparam name="T">泛型</typeparam> /// <param name="entityList">实体list</param> /// <param name="highchartsType">图表类型</param> /// <param name="xCategoryColumnName">X轴标记列名</param> /// <param name="stackColumnName">分组列名,如果没有分组,则使用null</param> /// <param name="dataColumnName">数据列名</param> /// <param name="sortBy">按哪列排序</param> /// <param name="title">标题</param> /// <param name="subTitle">子标题</param> /// <param name="unit">单位</param> /// <param name="showStackTotal">是否显示堆数据的总和</param> /// <param name="stackFor">哪种类型的分组累计?对应图表类型就会出现分组累计效果,不对应则没有分组累计效果,比如像要3月上海北京的总数,则X轴是月份,分组列是大区,我们使用bar图表,分组累计类型也要用bar</param> /// <param name="needAbs">是否使用绝对值样式,可以让条形图左右(柱状图上下)分开显示不同组别的数据</param> /// <param name="showLabel">是否显示数据标签</param> /// <param name="drawTable">是否在图表下面画table</param> /// <returns>highcharts的html代码</returns> public string FillHighchartsByEntityList <T>(IList <T> entityList, HighchartsType highchartsType, string xCategoryColumnName , string stackColumnName, string dataColumnName, string sortBy, string title, string subTitle, string unit, string showStackTotal, string stackFor, bool needAbs, bool showLabel, bool drawTable) { var dataTable = new System.Data.DataTable(); if (entityList.Count == 0) { return(""); } #region 获取类型的属性 PropertyInfo[] propertyInfos = typeof(T).GetProperties(); foreach (PropertyInfo propertyInfo in propertyInfos) { if (propertyInfo.PropertyType.FullName == "System.Data.EntityState" || propertyInfo.PropertyType.FullName == "System.Data.EntityKey") { continue; } //去掉系统自带的属性 dataTable.Columns.Add(propertyInfo.Name); } #endregion #region 把对象转换成datatable foreach (T entity in entityList) { DataRow data = dataTable.NewRow(); foreach (PropertyInfo propertyInfo in propertyInfos) { if (propertyInfo.PropertyType.FullName == "System.Data.EntityState" || propertyInfo.PropertyType.FullName == "System.Data.EntityKey") { continue; } //去掉系统自带的属性 data[propertyInfo.Name] = propertyInfo.GetValue(entity, null); } dataTable.Rows.Add(data); } #endregion return(FillHighchartsByDataTable(dataTable, "container", highchartsType, xCategoryColumnName, stackColumnName, dataColumnName, sortBy, title, subTitle, unit, showStackTotal, stackFor, needAbs, showLabel, drawTable, "400px", "400px")); }
/// <summary> /// 根据datatable画highcharts图表 /// </summary> /// <param name="dataTable">数据源</param> /// <param name="containerId">图表DIV的ID</param> /// <param name="highchartsType">图表类型</param> /// <param name="xCategoryColumnName">X轴标记列名</param> /// <param name="stackColumnName">分组列名,如果没有分组,则使用null</param> /// <param name="dataColumnName">数据列名</param> /// <param name="sortBy">按哪列排序</param> /// <param name="title">标题</param> /// <param name="subTitle">子标题</param> /// <param name="unit">单位</param> /// <param name="showStackTotal">是否显示堆数据的总和</param> /// <param name="stackFor">哪种类型的分组累计?对应图表类型就会出现分组累计效果,不对应则没有分组累计效果,比如像要3月上海北京的总数,则X轴是月份,分组列是大区,我们使用bar图表,分组累计类型也要用bar</param> /// <param name="needAbs">是否使用绝对值样式,可以让条形图左右(柱状图上下)分开显示不同组别的数据</param> /// <param name="showLabel">是否显示数据标签</param> /// <param name="drawTable">是否在图表下面画table</param> /// <param name="width">宽 例400px</param> /// <param name="height">高 例400px</param> /// <returns>highcharts的html代码</returns> public string FillHighchartsByDataTable(System.Data.DataTable dataTable, string containerId, HighchartsType highchartsType, string xCategoryColumnName, string stackColumnName, string dataColumnName, string sortBy , string title, string subTitle, string unit, string showStackTotal, string stackFor, bool needAbs, bool showLabel, bool drawTable, string width, string height) { #region 准备数据 var hsCategory = new HashSet <string>(); var hsStack = new HashSet <string>(); dataTable.DefaultView.Sort = sortBy;// xCategoryColumnName;//排序,让图表和table表按序排列 for (int i = 0; i < dataTable.DefaultView.Count; i++) { string xName = dataTable.DefaultView[i][xCategoryColumnName].ToString(); xName = xName == "" ? " " : xName;//如果分组数据为空字符串,则用空格代替,因为后面创建datatable的列的时候,空字符串会被自动改成Colum1,为了防止这种问题,这里暂时用空格代替 if (!hsCategory.Contains(xName)) { hsCategory.Add(xName); //获取X轴数据列表 } if (stackColumnName == null) //如果只有一行数据的,我们就传null进来,这里就会知道只保存一行数据 { if (!hsStack.Contains(null)) { hsStack.Add(null); } } else { if (!hsStack.Contains(dataTable.DefaultView[i][stackColumnName].ToString())) { hsStack.Add(dataTable.DefaultView[i][stackColumnName].ToString());//如果X轴数据要堆分组的话,这里获取堆分组的数据列表 } } } string xcategory = "";//传给highcharts的X轴数据 foreach (string hscate in hsCategory) { xcategory += "'" + hscate + "',"; } xcategory = xcategory.Substring(0, xcategory.Length - 1); string series = ""; string tooltip; if (highchartsType == HighchartsType.pie)//暂时这样处理,因为pie与其他类型的相关性不大,所以分开做series数据与tootip鼠标掩盖提示 { #region pie类型 series += "["; const string dataTemplate = "['{0}',{1}],"; series += "{type: 'pie',name: 'Browser share',data: ["; foreach (DataRow dataRow in dataTable.Rows) { series += string.Format(dataTemplate, dataRow[xCategoryColumnName], dataRow[dataColumnName]); } series = series.Substring(0, series.Length - 1) + "]}]"; tooltip = "'<b>'+ this.point.name +'</b>: '+this.y+' , '+ Math.round(this.percentage*100)/100 +' %'";//这里鼠标提示类别名称,值,百分比 #endregion } else { #region 非pie类型 series += "["; foreach (string stack in hsStack) { series += "{type:'" + highchartsType + "',name:'" + (stack ?? unit) + "',data:[";//如果没有分组数据,分组列名就用单位名称吧 foreach (string cate in hsCategory) { DataRow[] rows; if (stack == null) { rows = dataTable.Select(xCategoryColumnName + "='" + cate + "'"); } //没有堆分组的时候,只有一列数据 else { rows = dataTable.Select(stackColumnName + "='" + stack + "' and " + xCategoryColumnName + "='" + cate + "'"); } if (rows.Length == 0) { series += "0,"; } else { series += rows[0][dataColumnName] + ","; } } series = series.Substring(0, series.Length - 1); series += "],stack:0},"; } series = series.Substring(0, series.Length - 1) + "]"; if (needAbs) { tooltip = "'<b>'+ this.series.name +'</b><br/>'+this.x +': '+ (Math.abs(this.y)) +'" + unit + "'"; } //使用绝对值 else { tooltip = "'<b>'+ this.series.name +'</b><br/>'+this.x +': '+ this.y +'" + unit + "'"; } #endregion } string abs = ""; string mirror = "";//目前做法是,如果选择使用了绝对值,则默认制造镜像效果,比如数轴左边是男,右边是女 string dataLabel = showLabel ? "true" : "false"; if (needAbs) { abs = @"labels: { formatter: function(){ return (Math.abs(this.value)); } }," ; mirror = @", { // mirror axis on right side opposite: true, reversed: false, categories: categories, linkedTo: 0 }" ; } #endregion string highcharts = FormatSimpleHighcharts(containerId, title, subTitle, xcategory, unit, showStackTotal, tooltip, stackFor, series, abs, mirror, dataLabel, width, height); StringBuilder sbTable = new StringBuilder(); #region 画table if (drawTable) { #region 画表头,并重新做一个用来显示table用的临时数据表,给临时数据表添加列 sbTable.AppendLine("<table id='tableContainer' class='list-table'>");//id固定是这个,为了将来导出excel做准备 sbTable.AppendLine("<thead><tr><th>表头</th>"); DataTable showTable = new DataTable(); showTable.Columns.Add("stack");//默认添加一列分组数据 foreach (string cate in hsCategory) { showTable.Columns.Add(cate);//给新表添加列 sbTable.Append("<th>"); sbTable.Append(cate); sbTable.Append("</th>"); } sbTable.AppendLine("</tr></thead>"); #endregion #region 给临时表添加数据 foreach (string stack in hsStack) { DataRow showRow = showTable.NewRow(); showRow["stack"] = stack; foreach (string cate in hsCategory) { DataRow[] drs = dataTable.Select(xCategoryColumnName + "='" + cate + (stack == null ? "" : ("' and " + stackColumnName + "='" + stack)) + "'"); string tableData = ""; //如果没数据,则添空字符串 if (drs.Length > 0) { tableData = drs[0][dataColumnName].ToString(); if (needAbs) //如果会用绝对值了,则表格也要使用绝对值 { tableData = Math.Abs(Convert.ToDouble(tableData)).ToString(); } } showRow[cate] = tableData; } showTable.Rows.Add(showRow); } #endregion #region 把新表数据填充到字符串中 int columnNumber = showTable.Columns.Count; foreach (DataRow dataRow in showTable.Rows) { for (int i = 0; i < columnNumber; i++) { sbTable.Append("<td>"); sbTable.Append(dataRow[i].ToString()); sbTable.Append("</td>"); } sbTable.AppendLine("</tr>"); } sbTable.Append("</table>"); #endregion } #endregion #region 原始表 ////表格暂时没想到好办法 //sbTable.AppendLine("<table border=1>"); //int columnNumber = dataTable.Columns.Count; //foreach (DataRow dataRow in dataTable.Rows) //{ // sbTable.Append("<tr>"); // for (int i = 0; i < columnNumber; i++) // { // sbTable.Append("<td>"); // sbTable.Append(dataRow[i].ToString()); // sbTable.Append("</td>"); // } // sbTable.AppendLine("</tr>"); //} //sbTable.Append("</table>"); #endregion return(highcharts + sbTable); }