本章主要讲解利用Flot图表插件来显示具体的采集数据内容,我们先看成品图片:
上图中的两个图表,一个代表电压,一个代表电流。鼠标放到图表上的某个点上可以弹出悬浮窗显示当前时间的具体采集信息。
准备工作
首先,我们需要用到Flot插件,通过百度,我们就可以找到该项目的具体地址,然后引入到我们项目中:
1 2 3 4 5 6 | <!--Flot Chart Part--> < script src="~/Content/front/flot/excanvas.js"></ script > < script src="~/Content/front/flot/jquery.flot.js"></ script > < script src="~/Content/front/flot/jquery.flot.time.js"></ script > < script src="~/Content/front/flot/jquery.flot.resize.js"></ script > < script src="~/Content/front/flot/jquery.flot.selection.min.js"></ script > |
其次,我们的html模板设计如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!--图表数据--> < div class="paramcontainer"> < div class="panel panel-default"> < div class="panel-heading">{{selectedMachine.machine_name}}图表数据</ div > < div class="panel-body" style="padding:5px!important;"> < div class="chartcontainer"> < div class="row"> < history-data ng-repeat="item in HistoryData" options="item"></ history-data > </ div > </ div > </ div > </ div > </ div > |
图表数据绑定及显示
首先,我们需要设计我们的history-data directive,设计代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | app.directive( 'historyData' , [ function () { return { restrict: 'AE' , replace: true , scope: { options: "=" }, link: function (scope, elem, attrs) { //数据 var d = eval( "[" + scope.options.Param_data + "]" ); //随机线条颜色生成 var colors = [ "#FF0000" , "#0062E3" , "#FF00CC" , "#00CCCC" ]; var index = Math.floor((Math.random() * 4) + 1); //添加图标鼠标悬浮事件 var previousPoint = null , previousLabel = null ; elem.on( "plothover" , function (event, pos, item) { if (item) { debugger; if ((previousLabel != item.series.label) || (previousPoint != item.dataIndex)) { previousPoint = item.dataIndex; previousLabel = item.series.label; $( "#tooltip" ).remove(); var x = item.datapoint[0]; var y = item.datapoint[1]; var date = new Date(x); var color = item.series.color; showTooltip(item.pageX, item.pageY, color, "<strong>" + item.series.label + "</strong><br>" + (date.getUTCMonth()) + "月" + date.getUTCDate() + "日" + date.getUTCHours() + "时" + date.getMinutes() + "分" + " " + item.series.label + ": <strong>" + y + "</strong> (" + scope.options.Param_unit + ")" ); } } else { $( "#tooltip" ).remove(); previousPoint = null ; } }); function showTooltip(x, y, color, contents) { $( '<div id="tooltip">' + contents + '</div>' ).css({ position: 'absolute' , display: 'none' , top: y - 40, left: x - 120, border: '2px solid ' + color, padding: '3px' , 'font-size' : '12px' , 'color' : 'white' , 'border-radius' : '5px' , 'background-color' : '' +color+ '' , 'font-family' : '宋体,Verdana, Arial, Helvetica, Tahoma, sans-serif' , opacity: 0.9 }).appendTo( "body" ).fadeIn(200); } //绑定到chart图标 $.plot(elem, [{ label: scope.options.Param_name, data: d, color: colors[index] }], { xaxis: { mode: "time" }, legend: { position: "ne" }, series: { lines: { show: true }, points: { show: true , fill: false , radius: 2 } }, grid: { hoverable: true , //想用tooltip 这里一定要设置hoverable backgroundColor: { colors: [ "#fff" , "#eee" ] }, borderWidth: { top: 1, right: 1, bottom: 2, left: 2 } } }); }, template: '<div class="dae-placeholder" style="width:950px;height:200px;margin-left:20px;"></div>' }; }]); |
从这个模板中,我们可以看到,数据部分来源于<history-data ng-repeat="item in HistoryData" options="item"></history-data>中的options选项,然后通过ng-repeat来绑定多个图表(如果有多个图表数据传来的话)。
最后是我们的HistoryData数据来源:
1 2 3 4 5 6 | var historyDataList = function (machineId,starttime,endtime) { return $http({ method: 'POST' , url: '/Machine/GetHistoryCollectorDataByMachine?machineId=' + machineId + "¶mId=&starttime=" + starttime + "&endtime=" + endtime }); } |
后台拼接如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | [HttpPost] public JsonResult GetHistoryCollectorDataByMachine( string machineId, string paramId, string starttime, string endtime) { DateTime start,end; if (DateTime.TryParse(starttime, out start)) starttime= start.ToString( "yyyy-MM-dd" )+ " 00:00:00" ; if (DateTime.TryParse(endtime, out end)) endtime = end.ToString( "yyyy-MM-dd" ) + " 23:59:59" ; //首先获取采集设备的参数列表 var whereSQL = " where data.machine_id='" + machineId + "' " ; if (! string .IsNullOrEmpty(paramId)) whereSQL += " and param_id = '" + paramId.ToString() + "' " ; var groupSQL = " group by data.route_id,data.param_id,data.machine_id,setting.settingname,setting.settingvalue4 " ; var mainSQL = @"select machine_id ,route_id ,param_id ,setting.settingname ,setting.settingvalue4 from ds_collector_data data join edu_base_setting setting on data.param_id = setting.settingvalue1 " ; var allSQL = mainSQL + whereSQL + groupSQL; var groupResultList = fuNongContext.SqlQuery<CollectorGroup>(allSQL).Cast<CollectorGroup>().ToList(); var chartDataList = new List<CollectorChartFmt>(); var plainDataList = new List<CollectorChartFmt>(); //遍历参数列表取数据 if (groupResultList != null ) { //遍历采集器 groupResultList.ForEach(item => { var historySelectSQL = @" select data.data_value,data.data_time from ds_collector_data data " ; var historyWheresSQL = @" where data.machine_id='" + item.machine_id + "' and data.route_id=" + item.route_id + " and data.param_id='" + item.param_id + "' " ; var historyOrdersSQL = @" order by data.data_time desc " ; var historyFilterSQL = string .Empty; if (! string .IsNullOrEmpty(starttime) && ! string .IsNullOrEmpty(endtime)) { historyFilterSQL = @" and (data.data_time >= '" + starttime + "' and data.data_time <='" + endtime + "') " ; } if ( string .IsNullOrEmpty(starttime) && string .IsNullOrEmpty(endtime)) { historySelectSQL = @" select top 100 data.data_value,data.data_time from ds_collector_data data " ; } var historyMainSQL = historySelectSQL + historyWheresSQL + historyFilterSQL + historyOrdersSQL; var historyDataList = fuNongContext.SqlQuery<CollectorChart>(historyMainSQL).Cast<CollectorChart>().ToList(); if (historyDataList == null ) { chartDataList.Add( new CollectorChartFmt() { Param_name = "无" , Param_unit = "无" , Param_data = "[]" }); } else { var container = new List< string >(); historyDataList.ForEach(x => { var time = "Date.UTC(" + x.data_time.ToString( "yyyy,MM,dd,HH,mm,ss" ) + ")" ; var data = x.data_value; var val = "[" + time + "," + float .Parse(data) + "]" ; container.Add(val); plainDataList.Add( new CollectorChartFmt() { Param_name = item.settingname, Param_unit = item.settingvalue4, Param_data = data, Param_time = x.data_time.ToString( "yyyy-MM-dd HH:mm:ss" ) }); }); chartDataList.Add( new CollectorChartFmt() { Param_name = item.settingname, Param_unit = item.settingvalue4, Param_data = string .Join( "," , container) }); } }); } return Json( new { success = true , data = chartDataList, list = plainDataList }, JsonRequestBehavior.AllowGet); } |
也就是说,后台传过来的数据只要保持类似如下图的数据结构即可:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!