基于PetShop的数据可视化网站(三):可视化插件

在之前的系列中,我们可以较为轻松的将数据提取出来,但是仅仅使用表格等形式十分不直观。本文将通过百度地图API和ECharts对数据进行绘图。

具体的项目文件可以参考我的github仓库

百度地图API

地图的作用是展现一块儿区域内容或寻径,项目为了展现设备所处地点,引用百度地图API进行展示。大体效果如下:

地图

在之前的系列中,我们将设备信息提取到了表现层,那么我们可以在aspx.cs后台中将得到的值包装成固定格式传输给aspx页面,这时得到了如图的效果,具体代码如下所示

BaiduMapClick.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="BaiduMapClick.aspx.cs" Inherits="BaiduMapClick" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
        body, html,#allmap {width: 800px;height: 600px;overflow: hidden;margin:0;font-family:"微软雅黑";}
    </style>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的ak码"></script>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div id="allmap"></div>
    </form>
</body>
</html>

<script type="text/javascript">
    // 百度地图API功能
    // 创建Map实例
    var map = new BMap.Map("allmap");
    // 初始化地图,设置中心点坐标和地图级别
    var point = new BMap.Point(120.277515, 31.490646);
    map.centerAndZoom(point, 18);
    //开启鼠标滚轮缩放
    map.enableScrollWheelZoom(true);     
    //mapdata是后台传送过来的内容,结构大概这样:
    //[[116.417854,39.921988,1,"Arduino Uno"],
    //[116.406605,39.921585,2,"Virtual Device"]]
    var json_data = <%= mapdata %>;
    var pointArray = new Array();
    for (var i = 0; i < json_data.length; i++) 
    {
        // 创建点
        var marker = new BMap.Marker(new BMap.Point(json_data[i][0], json_data[i][1])); 
        //增加点
        map.addOverlay(marker);    
        //这个是给点加标签,但是单击事件还是在点上面
        var strdesc = "设备" + json_data[i][2] + ":" + json_data[i][3]
        var label = new BMap.Label(strdesc, { offset: new BMap.Size(20, -10) });
        //这里Title存储的是DeviceID
        marker.setTitle(json_data[i][2]);
        marker.setLabel(label);
        pointArray[i] = new BMap.Point(json_data[i][0], json_data[i][1]);
        //为每一个点增加一个单击事件
        marker.addEventListener("click", function(e){ChangeLabel(e)});
    }
    //让所有点在视野范围内
    map.setViewport(pointArray);

    //点击marker之后调用的函数,初步理解为改变隐藏的label里面的值,然后在刷新本页的方法
    function ChangeLabel(e) 
    {
        //这里获得了DeviceID
        var p = e.target;
        var devicenum = p.getTitle();

        // 这里设置了转向页面,来提交我们点击的DeviceID
        window.location.href = 'BaiduMapClick.aspx?devicenum='+devicenum;
    }
</script>

当时曾经尝试打开地图的时候开启所有信息窗口,但是根据实际使用,发现每次只能出现一个信息窗口气泡,遂放弃。

BaiduMapClick.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using FWSync.BLL;
using FWSync.Model;
using FWSync.Web;

public partial class BaiduMapClick : System.Web.UI.Page
{
    //设置一个全局变量,存储DeviceID
    public int devicenum = 1;
    //设置一个string记录需要返回到前台的值
    public string mapdata = "";

    protected void Page_Load(object sender, EventArgs e)
    {
        //使用缓存依赖调取所有设备信息
        IList<DeviceInfo> devicedata = DeviceDataProxy.GetDevices();
        //这里往下都是在拼凑前台需要的mapdata串
        mapdata = "[";
        if (devicedata.Count > 0)
        {
            for(int i = 0 ; i < devicedata.Count ; i++)
            {
                mapdata += "[" + devicedata[i].DeviceX + "," + devicedata[i].DeviceY + "," + devicedata[i].DeviceID + "," + "\"" + devicedata[i].DeviceDesc + "\"],";
            }
        }
        //去掉逗号
        mapdata = mapdata.TrimEnd(',');
        mapdata += "]";
        //这里是每次进入页面后查看URL中是否将DeviceID传递过来
        if (this.Request["devicenum"] != null)
        {
            int devicenum = int.Parse(HttpUtility.HtmlEncode(this.Request["devicenum"]));
        }
    }
}

ECharts

ECharts是百度团队开发的一个数据可视化插件,其功能较为强大,能够实现各种刁钻图形的绘制。如果使用过Highcharts会有非常熟悉的感觉。其主要的入门操作可以看这里

其实际效果如下所示:

曲线

在这里,我仅仅是使用其绘制了两条简单的曲线,来反映设备读取到的数据,这是我将百度API和repeater插件以及ECharts集合起来使用的代码:

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>首页</title>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的ak码"></script>

    <script type="text/javascript" src="./JS/echarts.common.min.js"></script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            //登录控件
            <asp:LoginName ID="LoginName1" runat="server" />
            <asp:LoginStatus ID="LoginStatus1" runat="server" 
            LogoutAction="RedirectToLoginPage" />
        </div>
        <div id="allmap" style="width: 600px;height:400px;"></div>
        <br />
        <br />
        <br />
        这里需要根据列表选择哪个参数,通过repeater点击某一行然后刷新并绑定数据来实现

        <br />
        <asp:Repeater ID="rpt" runat="server" >
            <HeaderTemplate>
                <table>
                    <tr>
                        <td>
                            设备名称
                        </td>
                        <td>
                            设备值
                        </td>
                        <td>
                            采集时间
                        </td>
                    </tr>
            </HeaderTemplate>

            <ItemTemplate>
                <tr>
                    <td >
                        <asp:Label ID = "lblName" runat ="server" Text='<%# DataBinder.Eval(Container.DataItem, "ParamDesc") %>'></asp:Label>
                    </td>
                    <td >
                        <asp:Label ID = "lblValue" runat ="server" Text='<%# DataBinder.Eval(Container.DataItem, "ParamValue") %>'></asp:Label>

                    </td>
                     <td >
                        <asp:Label ID = "lblTime" runat ="server" Text='<%# DataBinder.Eval(Container.DataItem, "InsertTime") %>'></asp:Label>
                    </td>
                </tr>
            </ItemTemplate>

            <FooterTemplate>
                </table>
            </FooterTemplate>
        </asp:Repeater>
        <br />
        <br />
        这里需要有图像,折线图什么的
        <div id="container" style="width: 600px;height:400px;">
        </div>

        <script type="text/javascript">
            // 基于准备好的dom,初始化echarts实例
            var myChart = echarts.init(document.getElementById('container'));

            // 指定图表的配置项和数据
            option = 
            {
               tooltip: {
                    trigger: 'item',
                    formatter: function (params) {

                            var date = new Date(params.value[0]);
                            date = date.getFullYear() + '-'
                                   + (date.getMonth() + 1) + '-'
                                   + date.getDate() + ' '
                                   + date.getHours() + ':'
                                   + date.getMinutes();

                            return   '时间:'
                                   + date +  '<br/>'+ '参数值: '
                                   + params.value[1] ;
                    }
                },
                legend: {
                    data: ['温度','一氧化碳']
                },
                grid: {

                    containLabel: true
                },
                xAxis: 
                [
                    {
                        type: 'time'
                    }
                ],
                    yAxis: 
                [
                    {
                        type: 'value',
                        scale:true
                    }
                ],
                    series: 
                [
                    {
                        name:'温度',
                        type:'line',
                        smooth: true,
                        data:(function (){
                            var res = [];
                            //这里得到了后台数据,但是推送数据是倒着推送的,是因为获得的数据是反过来的
                            var jsonData = <%= jsonstr %>;
                            var i;
                            var now = new Date();
                            for (i = 0; i <  jsonData.j; i++) 
                           {
                               res.push([
                                        now.setTime(jsonData.rows[ jsonData.j - i-1].time1),
                                        jsonData.rows[ jsonData.j - i-1].price
                                        ]);

                           }
                            return res;
                        })()
                    },
                    {
                        name:'一氧化碳',
                        type:'line',
                        smooth: true,
                        data:(function (){
                            var res = [];
                            var jsonData = <%= jsonstr2 %>;
                            var i;
                            var now = new Date();
                            for (i = 0; i <  jsonData.j; i++) 
                           {
                               res.push([
                                        now.setTime(jsonData.rows[ jsonData.j - i-1].time1),
                                        jsonData.rows[ jsonData.j - i-1].price
                                        ]);
                           }
                            return res;
                        })()
                    }
                ]
            };//end option

            // 使用刚指定的配置项和数据显示图表。
            myChart.setOption(option);
    </script>

    </form>
</body>
</html>
<script type="text/javascript">
    // 百度地图API功能
    var map = new BMap.Map("allmap");
    var point = new BMap.Point(120.277515, 31.490646);
    map.centerAndZoom(point, 18);
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放

    var json_data = <%= mapdata %>;
    var pointArray = new Array();
    for (var i = 0; i < json_data.length; i++) 
    {
        var marker = new BMap.Marker(new BMap.Point(json_data[i][0], json_data[i][1])); // 创建点
        map.addOverlay(marker);    //增加点
        //这个是给点加标签,但是单击事件还是在点上面
        var strdesc = "设备" + json_data[i][2] + ":" + json_data[i][3]
        var label = new BMap.Label(strdesc, { offset: new BMap.Size(20, -10) });
        marker.setTitle(json_data[i][2]);
        marker.setLabel(label);
        pointArray[i] = new BMap.Point(json_data[i][0], json_data[i][1]);
        marker.addEventListener("click", function(e){ChangeLabel(e)});
    }
    //让所有点在视野范围内
    map.setViewport(pointArray);

    //点击marker之后调用的函数,初步理解为改变隐藏的label里面的值,然后在刷新本页的方法
    function ChangeLabel(e) 
    {
        var p = e.target;
        var devicenum = p.getTitle();

        // 这里设置了转向页面,使用了get请求,如果没有这个的话,那么设定一个默认值好了
        window.location.href = 'Default.aspx?devicenum='+devicenum;
    }
</script>

内容大体上和之前都是重复的,除了ECharts数据推送部分,是将后台得到的数据一个个的push到图中,由于后台提取的数据是逆序,在BLL中并没有找到List的Reverse方法,因此直接在前台逆序push。

Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using FWSync.BLL;
using FWSync.Model;
using FWSync.Web;

public partial class _Default : System.Web.UI.Page
{
    //地图要用到的内容
    public int deviceid = 1;
    public string mapdata = "";
    //js作图用这个串来传递数据
    public string jsonstr = "";
    public string jsonstr2 = "";

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            //基于票据的验证方法
            //如果登录,则显示用户名
            HttpContext context = this.Context;
System.Security.Principal.IPrincipal;

            System.Security.Principal.IPrincipal user = this.User;
        }
        //这里应该是每次进来都做得事情,即对数据进行绑定
        //首先对表格进行调整
        BindAll();
    }

    private void BindAll()
    {
        IList<DeviceInfo> devicedata = DeviceDataProxy.GetDevices();
        mapdata = "[";

        if (devicedata.Count > 0)
        {
            for (int i = 0; i < devicedata.Count; i++)
            {
                mapdata += "[" + devicedata[i].DeviceX + "," + devicedata[i].DeviceY + "," + devicedata[i].DeviceID + "," + "\"" + devicedata[i].DeviceDesc + "\"],";
            }
        }
        mapdata = mapdata.TrimEnd(',');
        mapdata += "]";

        if (this.Request["devicenum"] != null)
        {
            deviceid = int.Parse(HttpUtility.HtmlEncode(this.Request["devicenum"]));
        }
        //这里通过获得的DeviceID提取数据
        IList<ParamAndOneDataInfo> tempdata = WebUtility.GetParamAndOneData(deviceid);
        rpt.DataSource = tempdata;
        rpt.DataBind();

        //接下来对折线进行调整
        jsonstr = GetLine(deviceid, 1);
        jsonstr2 = GetLine(deviceid, 2);
    }

    //GetLine这个方法是通过DeviceID和ParamID获得数据,并返回一个拼凑的string
    private string GetLine(int deviceid,int paramid)
    {
        IList<OriginalDataInfo> orilist = new List<OriginalDataInfo>();
        OriginalData ori = new OriginalData();

        IList<ParamInfo> paramdata = ParamDataProxy.GetParams();
        //这个方法的作用是通过通过DeviceID和ParamID提取最后的20个数据
        orilist = ori.GetTopNDatasByDeviceIDAndParamID(20, deviceid, paramid);
        int j = orilist.Count;
        if (j > 0)
        {
            string json = "{\"j\":" + j + ",\"rows\":[";
            double maxitem = 1000;//最多放1000个点在图像上面
            int step = j > maxitem ? (int)(maxitem / j) : 1;

            for (int i = 0; i < orilist.Count; i += step)
            {
                json += "{\"time1\":\"" + (Convert.ToDateTime(orilist[i].InsertTime).AddHours(-8) - new DateTime(1970, 1, 1)).TotalMilliseconds + "\",\"price\":\"" + Convert.ToDecimal(orilist[i].ParamValue) + "\"},";
            }

            json = json.TrimEnd(',');
            json += "]}";
            return json;
        }
        else
        {
            throw new Exception("无数据");
        }
    }
}

大体的处理过程:进入页面后首先绘制地图;接下来判断URL中是否包含DeviceID,如果没有,默认为1,否则查询相应Device的数据并放入repeater中;最后提取该设备的数据,绘制曲线图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值