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

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

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

百度地图API

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

基于PetShop的数据可视化网站(三):可视化插件_第1张图片

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

BaiduMapClick.aspx

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



<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 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会有非常熟悉的感觉。其主要的入门操作可以看这里

其实际效果如下所示:

基于PetShop的数据可视化网站(三):可视化插件_第2张图片

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

Default.aspx

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



<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 +  '
'
+ '参数值: ' + 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 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 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 orilist = new List();
        OriginalData ori = new OriginalData();

        IList 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中;最后提取该设备的数据,绘制曲线图。

你可能感兴趣的:(asp-net)