在之前的系列中,我们可以较为轻松的将数据提取出来,但是仅仅使用表格等形式十分不直观。本文将通过百度地图API和ECharts对数据进行绘图。
具体的项目文件可以参考我的github仓库
地图的作用是展现一块儿区域内容或寻径,项目为了展现设备所处地点,引用百度地图API进行展示。大体效果如下:
在之前的系列中,我们将设备信息提取到了表现层,那么我们可以在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是百度团队开发的一个数据可视化插件,其功能较为强大,能够实现各种刁钻图形的绘制。如果使用过Highcharts会有非常熟悉的感觉。其主要的入门操作可以看这里
其实际效果如下所示:
在这里,我仅仅是使用其绘制了两条简单的曲线,来反映设备读取到的数据,这是我将百度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中;最后提取该设备的数据,绘制曲线图。