共享单车之数据可视化

文章目录

  • 第1关:绘制地图
  • 第2关:绘制流量最高的五条线路的路程图


第1关:绘制地图

任务描述
本关任务:使用JSP在百度地图上绘制一条共享单车起始路程。

相关知识
为了完成本关任务,你需要掌握:

如何创建地图实例;
如何在地图上绘制路程线。
创建地图实例
我们需要先在jsp中引入百度地图api。

myMap
引入之后我们便可使用api中BMap对象来创建地图实例:

经过上述设置我们访问jsp则为如下效果:

在地图上绘制路径线
首先我们需要绘制路径必须知道起始点的经纬度及终点的经纬度才能够绘制成线,现提供起始点经纬度为(116.44516,39.925338),终点经纬度为(116.403838,39.919141),通过这两个点来绘制路径线:

var start_longitude=116.44516;//开始经度
var start_latitude=39.925338;//开始纬度
var stop_longitude=116.403838;//结束经度
var stop_latitude=39.919141;//结束纬度
var polyline = new BMap.Polyline([
new BMap.Point(start_longitude, start_latitude),
new BMap.Point(stop_longitude, stop_latitude)
],{strokeColor:“red”,strokeWeight:3,strokeOpacity:0.5});//创建一条宽度为3外边框透明度为0.5的红色线
map.addOverlay(polyline);//将线添加到地图上
效果如下:

给路程线设置标注和添加箭头
上图可以看到路程,但只有一条线并无法详细的向我们展示信息,因此我们可以通过给路程线添加标注位置和方向箭头。

添加标注
var address=“北京市朝阳区朝外街道三丰里社区”;
var marker = new BMap.Marker(new BMap.Point(start_longitude,start_latitude)); //创建开始位置标注
var label = new BMap.Label(address, {offset: new BMap.Size(20, 0)});//给标注设置文字描述
marker.setLabel(label);//将文字描述设置到标注上
map.addOverlay(marker);//将标注添加到地图中
通过鼠标滚轮将地图放大,可得到如下效果:

绘制箭头

上图中,线段AB是路程线,只要绘制出CBD就可以实现箭头效果,为了灵活绘制箭头,需要用户自定义箭头的长度(r)和角度(angle)。
实现步骤如下:
变量定义:pixelStart(路程线起点坐标)、pixelEnd(路程线终点坐标)、r:(单位像素,并不是CB对应的箭头的长度,而是橘色线段对应的距离)、angle:箭头线((CB或者DB)与AB的夹角),函数定义为addArrow(polyline,r,angel):

首先要将AB两点的经纬度坐标转化成屏幕坐标
然后根据AB两点屏幕坐标以及r长度,计算绿色小绿点的屏幕坐标pixelTem。
再根据B点、小绿点的屏幕坐标及angle角度,计算出C,D两点的屏幕坐标
利用map的坐标转换方法,将C,D两点的屏幕坐标转成经纬度表示的坐标。
利用画线方法,绘制CBD折线。
代码我们已为你提供,在右侧任务代码中addArrow函数中体现。

编程要求
在右侧编辑器补充代码,绘制出一条河北省保定市雄县(经纬度为116.10,38.98)一共享单车使用的路程线,具体信息如下:

起点经纬度为(39.04607,116.233093);
终点经纬度为(39.041691,116.235352);
要求设置路程线为红色,宽度为3,透明度为0.5;
给起点和终点都创建标注,描述起点为乡里乡情铁锅炖南228米,终点为擎天矿用材料有限公司北609米,要求设置的字体大小为20
调用提供绘制箭头函数addArrow函数添加r=10,angle=Math.PI/7的箭头。
注意:直接使用已定义的变量,且已定义的变量名不要私自修改。

最终实现效果如下:

测试说明
平台会对你编写的代码进行测试:

测试输入:无
预期输出:测试通过

开始你的任务吧,祝你成功!

示例代码如下:

<%@ page language="java" contentType="text/html; charset=utf-8"
         pageEncoding="utf-8"%>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css">
        body, html,#allmap {
            width: 100%;
            height: 100%;
            overflow: hidden;
            margin:0;
        }
    </style>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.4"></script>
    <title>step1</title>
</head>
<body>
<div id="allmap"></div>
</body>
</html>
<script type="text/javascript">
    var map = new BMap.Map("allmap");// 创建地图实例
    var point = new BMap.Point(116.10 ,38.98);// 创建点坐标
    map.centerAndZoom(point, 13);//设初始化地图。 如果center类型为Point时,zoom必须赋值,范围3-19级,若调用高清底图(针对移动端开发)时,zoom可赋值范围为3-18级。如果center类型为字符串时,比如“北京”,zoom可以忽略,地图将自动根据center适配最佳zoom级别
    map.addControl(new BMap.NavigationControl());//缩放平移控件
    map.enableScrollWheelZoom();//利用鼠标滚轮控制大小
    var start_longitude=116.233093;//开始经度
    var start_latitude=39.04607;//开始纬度
    var stop_longitude=116.235352;//结束经度
    var stop_latitude=39.041691;//结束纬度
    var address=["乡里乡情铁锅炖南228米","擎天矿用材料有限公司北609米"];
    /**********  Begin  **********/
    //1.初始化路程线
    var polyline = new BMap.Polyline([
        new BMap.Point(start_longitude, start_latitude),
        new BMap.Point(stop_longitude, stop_latitude)
    ], {strokeColor:"red", strokeWeight:3, strokeOpacity:0.5});
    //2.将线添加到地图上
    map.addOverlay(polyline);
    //3.调用绘制箭头线函数
    addArrow(polyline,10,Math.PI/7);
    //4.设置起始点标注
    var marker = new BMap.Marker(new BMap.Point(start_longitude,start_latitude));
    var label = new BMap.Label(address[0],{offset: new BMap.Size(20, 0)});
    marker.setLabel(label);
    map.addOverlay(marker);
    var marker = new BMap.Marker(new BMap.Point(stop_longitude,stop_latitude));
    var label = new BMap.Label(address[1], {offset: new BMap.Size(20, 0)});
    marker.setLabel(label);
    map.addOverlay(marker);
    /**********  End  **********/
    //绘制箭头的函数
    function addArrow(polyline,r,angle){
        var linePoint=polyline.getPath();//线的坐标串(里面存的就是起始点的坐标点)
        var arrowCount=linePoint.length;
        for(var i =1;i<arrowCount;i++){ //在拐点处绘制箭头
            var pixelStart=map.pointToPixel(linePoint[i-1]);
            var pixelEnd=map.pointToPixel(linePoint[i]);
            var pixelTemX,pixelTemY;//临时点坐标
            var pixelX,pixelY,pixelX1,pixelY1;//定义箭头两个点坐标
            var delta=(pixelEnd.y-pixelStart.y)/(pixelEnd.x-pixelStart.x);//主线斜率,垂直时无斜率
            var param=Math.sqrt(delta*delta+1);//代码简洁考虑
            if((pixelEnd.x-pixelStart.x)<0){ //第二、三象限
                pixelTemX=pixelEnd.x+ r/param;
                pixelTemY=pixelEnd.y+delta*r/param;
            }else{ //第一、四象限
                pixelTemX=pixelEnd.x- r/param;
                pixelTemY=pixelEnd.y-delta*r/param;
            }
            //已知直角三角形两个点坐标及其中一个角,求另外一个点坐标算法
            pixelX=pixelTemX+ Math.tan(angle)*r*delta/param;
            pixelY=pixelTemY-Math.tan(angle)*r/param;
            pixelX1=pixelTemX- Math.tan(angle)*r*delta/param;
            pixelY1=pixelTemY+Math.tan(angle)*r/param;
            var pointArrow=map.pixelToPoint(new BMap.Pixel(pixelX,pixelY));
            var pointArrow1=map.pixelToPoint(new BMap.Pixel(pixelX1,pixelY1));
            var Arrow = new BMap.Polyline([
                pointArrow,linePoint[i],pointArrow1
            ], {strokeColor:"blue", strokeWeight:3, strokeOpacity:0.5});
            map.addOverlay(Arrow);
            return Arrow;
        }
    }
</script>

共享单车之数据可视化_第1张图片

第2关:绘制流量最高的五条线路的路程图

任务描述
本关任务:在地图上绘制共享单车中流量最高的五条路线的路程。

相关知识
本实训数据基于共享单车之数据分析最后一关的数据(流量最高的五条数据)。

为了完成本关任务,你需要掌握:

如何在后台传数据给JSP页面;
JSP页面中如何获取后台传的数据;
如何在地图上绘制多条路程线。
如何在后台传数据给JSP页面
我们可以通过直接访问servlet在其doGet或doPost方法中将值传递到jsp中,示例如下:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute(“key”,“value”);//以键值对的形势存值
request.getRequestDispatcher(“index.jsp”).forward(request,response);//使用转发将数据带到页面中
}
JSP获取后台传过来的数据

但若传的数据类型为集合,则直接获取会被当成字符串,因此需要做一些数据处理,如:

List list=new ArrayList<>();
list.add(“abc”);
list.add(“ABC”);
request.setAttribute(“key”,list);

如何在地图上绘制多条路程线
上一章节我们学习了如何绘制一条路程线,现在我们要绘制多条,本质上是一样的操作,只需将后端获取的数据进行循环遍历即可:

为了方便存取数据,我们将之前章节中HbaseUtil类中用来扫描表显示结果的scanTable方法做了修改,改为将流量最高的五条路程线数据存到了自定义的BickMap对象中,(上诉的相关类和方法都可在右侧文件夹中进行查看)具体操作如下:

servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BickMap bickMap = HBaseUtil.scanTable();//获取存进去的五条数据
for (String key : bickMap.getKeys()) {
request.setAttribute(key,bickMap.get(key));//遍历将最高五条流量的数据以“字段名-结果集合”形式传到后台
}
request.getRequestDispatcher(“step2.jsp”).forward(request,response);
}
jsp

编程要求
在右侧编辑器补充代码,绘制流量最高的五条数据的路程线,具体要求如下:

在servlet中将字段名为key,bickMap.get(key)为value作为键值对方式传值给jsp;
绘制路程线样式为红色,宽度为3,透明度为0.5;
调用提供绘制箭头函数addArrow,绘制以r=10,angle=Math.PI/7的箭头;
绘制起始地点的标注信息,文字大小仍为20。
最终实现效果如下:

注意:为了方便测试,右侧编辑器中已有的变量名请勿私自改动。

测试说明
平台会对你编写的代码进行测试:

测试输入:无
预期输出:测试通过

开始你的任务吧,祝你成功!

说点什么
示例代码如下:
在该位置选择代码文件
共享单车之数据可视化_第2张图片
BickMapServlet:

package com.educoder.servlet;
import com.educoder.util.HBaseUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class BickMapServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        /**********   Begin   **********/
        //1.通过HbaseUtil类获取数据
        BickMap bickMap =HBaseUtil.scanTable();
        //2.遍历将数据以键值对的方式传给jsp
        for (String key : bickMap.getKeys()) {
            request.setAttribute(key, bickMap.get(key));
        }
        /**********   End    **********/
        
        request.getRequestDispatcher("step2.jsp").forward(request,response);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

step2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css">
        body, html,#allmap {
            width: 100%;
            height: 100%;
            overflow: hidden;
            margin:0;
        }
    </style>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.4"></script>
    <title>step2</title>
</head>
<body>
<div id="allmap"></div>
</body>
</html>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript">
    var map = new BMap.Map("allmap");// 创建地图实例
    var point = new BMap.Point(116.10 ,38.98);// 创建点坐标
    map.centerAndZoom(point, 13);//设初始化地图。 如果center类型为Point时,zoom必须赋值,范围3-19级,若调用高清底图(针对移动端开发)时,zoom可赋值范围为3-18级。如果center类型为字符串时,比如“北京”,zoom可以忽略,地图将自动根据center适配最佳zoom级别
    map.addControl(new BMap.NavigationControl());//缩放平移控件
    map.enableScrollWheelZoom();//利用鼠标滚轮控制大小
    /**********   Begin  **********/
    //1.获取后台传过来的数据 调用已写好的change函数清理数据
    var start_longitude = change('<%=request.getAttribute("start_longitude") %>');
    var start_latitude = change('<%=request.getAttribute("start_latitude") %>');
    var stop_longitude = change('<%=request.getAttribute("stop_longitude") %>');
    var stop_latitude = change('<%=request.getAttribute("stop_latitude") %>');
    var start_address = change('<%=request.getAttribute("start_address") %>');
    var stop_address = change('<%=request.getAttribute("stop_address") %>');
    //2.初始化路程线
    for (var i=0;i<start_latitude.length;i++){
        var polyline = new BMap.Polyline([
            new BMap.Point(start_longitude[i], start_latitude[i]),
            new BMap.Point(stop_longitude[i], stop_latitude[i])
        ], {strokeColor:"red", strokeWeight:3, strokeOpacity:0.5});
        //3.将线添加到地图上
        map.addOverlay(polyline);
        //4.调用绘制箭头线函数
        addArrow(polyline,10,Math.PI/7);
        //5.设置起始点标注
        var marker = new BMap.Marker(new BMap.Point(start_longitude[i],start_latitude[i]));
        var label = new BMap.Label(start_address[i],{offset: new BMap.Size(20, 0)});
        marker.setLabel(label);
        map.addOverlay(marker);
        var marker = new BMap.Marker(new BMap.Point(stop_longitude[i],stop_latitude[i]));
        var label = new BMap.Label(stop_address[i], {offset: new BMap.Size(20, 0)});
        marker.setLabel(label);
        map.addOverlay(marker);
    }
    /**********   End   **********/
    //数据转化函数
    function change(obj) {
        obj = obj.substring(1,obj.length - 1).split(",");
        return obj;
    }
    //绘制箭头的函数
    function addArrow(polyline,r,angle){
        var linePoint=polyline.getPath();//线的坐标串(里面存的就是起始点的坐标点)
        var arrowCount=linePoint.length;
        for(var i =1;i<arrowCount;i++){ //在拐点处绘制箭头
            var pixelStart=map.pointToPixel(linePoint[i-1]);
            var pixelEnd=map.pointToPixel(linePoint[i]);
            var pixelTemX,pixelTemY;//临时点坐标
            var pixelX,pixelY,pixelX1,pixelY1;//定义箭头两个点坐标
            var delta=(pixelEnd.y-pixelStart.y)/(pixelEnd.x-pixelStart.x);//主线斜率,垂直时无斜率
            var param=Math.sqrt(delta*delta+1);//代码简洁考虑
            if((pixelEnd.x-pixelStart.x)<0){ //第二、三象限
                pixelTemX=pixelEnd.x+ r/param;
                pixelTemY=pixelEnd.y+delta*r/param;
            }else{ //第一、四象限
                pixelTemX=pixelEnd.x- r/param;
                pixelTemY=pixelEnd.y-delta*r/param;
            }
            //已知直角三角形两个点坐标及其中一个角,求另外一个点坐标算法
            pixelX=pixelTemX+ Math.tan(angle)*r*delta/param;
            pixelY=pixelTemY-Math.tan(angle)*r/param;
            pixelX1=pixelTemX- Math.tan(angle)*r*delta/param;
            pixelY1=pixelTemY+Math.tan(angle)*r/param;
            var pointArrow=map.pixelToPoint(new BMap.Pixel(pixelX,pixelY));
            var pointArrow1=map.pixelToPoint(new BMap.Pixel(pixelX1,pixelY1));
            var Arrow = new BMap.Polyline([
                pointArrow,linePoint[i],pointArrow1
            ], {strokeColor:"blue", strokeWeight:3, strokeOpacity:0.5});
            map.addOverlay(Arrow);
            return Arrow;
        }
    }
</script>

共享单车之数据可视化_第3张图片


你可能感兴趣的:(信息可视化)