一、项目需求
1、数据:
https://data.cityofnewyork.us/api/views/h9gi-nx95/rows.csv?accessType=DOWNLOAD
2、功能:
-
在地图上显示出事故发生的地点
-
显示当前展示数据的统计图表
-
可以按时间、区域过滤
-
可以在地图指定任意点按地理半径过滤数据。例如:10公里内、50公里内
-
-
展示出事故发生因素之间的关系,给出出行建议
二、项目分析
题目要求将交通事故数据在地图上展示出来。首先,交通事故的数据格式是csv文件,需要在后端把csv格式的数据读取出来放在数据库中,然后根据前端发送的请求进行过滤处理后响应给前端,前端再调用地图接口将接收到的数据显示在地图上。所以,该项目涉及前后端全栈开发。
三、技术选型
首先,地图我想到的是选用百度地图,因为百度地图是国内的,申请开发者密钥比较方便,而google地图则需要FQ;前端框架我选用的是react,使用其他框架也可以,看个人喜好;后端框架我选用的是express,因为不会其他的,哈哈;数据库选用mongodb,因为mongodb入门非常简单,很容易上手使用。
四、项目搭建
1、前端部分
前端用的是react框架,直接使用react脚手架create-react-app快速构建前端文件目录,也就是在终端执行create-react-app react-baidumap,react-baidumap就是我的前端部分的项目文件名,然后cd react-baidumap 进入项目文件,接着执行npm run eject(为了查看配置)和npm start就可以看到项目文件下自动创建的目录,打开localhost:3000可以看到react的官方图标。这部分的内容可以参考react官方教程:https://react.docschina.org/docs/create-a-new-react-app.html#create-react-app我也是照着官方教程来的。至此,前端的项目框架就搭建好了,如下图所示:
接着我们打开public文件夹,找到index.html文件,我们要使用百度地图接口,就需要在这里使用script标签引入资源,以下为index.html文件的内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=2NZa1O1V3BHmsDlX9fdomGaO3S5b1AEo"></script> <title>Vehicle Collisions</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html>
然后就是在src文件夹下面的index.js文件里写代码了,这里注意要将BMap设置为全局变量来使用,不然会报错。具体如何使用百度地图可以参考百度地图官方文档上的Demohttp://lbsyun.baidu.com/jsdemo.htm#canvaslayer。如下所示,index.js文件的代码我写的注释已经很清楚了,这里不做过多解释了。
import React from 'react'; import ReactDOM from 'react-dom'; import axios from 'axios'; import './index.css'; class BaiduMap extends React.Component { componentDidMount() { var BMap = window.BMap; //将BMap设置为全局变量 var map = new BMap.Map("container"); //创建map实例 var point = new BMap.Point(-73.8648270000,40.8447820000); //初始化地图,设置纽约为地图中心 map.centerAndZoom(point, 15); //设置地图显示级别为15 map.addControl(new BMap.MapTypeControl()); //添加地图类型控件 map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放 // 编写自定义函数,创建标注,展示事故发生的地点和原因 function addMarker(point,string1,string2){ //给事故发生点添加标记 var marker = new BMap.Marker(point); map.addOverlay(marker); //展示事故发生原因 var label = new BMap.Label(string1,{offset:new BMap.Size(20,-10)}); marker.setLabel(label); //点击展示展示事故发生因素之间的关系 marker.addEventListener("click",getAttr); function getAttr(){ alert(string2); } } //获取后端数据 axios.get('/getUserInfo').then(res => { // var lng = res.data.result[0].LONGITUDE; // var lat = res.data.result[0].LATITUDE; // console.log(res.data.result[0].LONGITUDE); // console.log(res.data.result[0].LATITUDE); // var point1 = new BMap.Point(lng, lat); // addMarker(point1); res = res.data.result; // console.log(res); for( var i = 0, len = res.length; i < len; i++){ // console.log(res[i].LONGITUDE+'-----'+res[i].LATITUDE); var point1 = new BMap.Point(res[i].LONGITUDE, res[i].LATITUDE); addMarker(point1, res[i]['CONTRIBUTING FACTOR VEHICLE 1'], res[i]['CONTRIBUTING FACTOR VEHICLE 2']); } }); } render() { return ( <div id='container' style={{ '100vw', height: '100vh' }}> </div> ) } } ReactDOM.render( <BaiduMap />, document.getElementById('root') )
2、后端部分
后端使用nodejs的express框架,需要在项目中安装express和mongodb,项目目录的构建其实很简单,这里还不需要路由和构建数据模型,因为不需要请求多个路径,而且数据是现成的,所以只要有个app.js入口文件,在这里面创建一个express应用,读取csv文件导入数据库,再连接数据库查找数据、响应请求就可以了。最开始我本来是打算前端和后端写在一个项目目录下,但是中途遇到了一些问题,当时自己对前后端的概念也是模糊不清,还尝试过在前端读取csv文件,最后也是以失败告终,后来请教他人之后,才把前后端的文件分开了,以下是我的后端项目目录:
其实这里主要就是app.js这个文件的编写,内容如下:
var express = require('express'); const router = express.Router(); var app = express(); var MongoClient = require('mongodb').MongoClient; var url = 'mongodb://localhost:27017/mydata'; // 获取用户信息 router.get('/getUserInfo', function(req, res) { MongoClient.connect(url, { useNewUrlParser: true },function(err,client){ if(err){ throw err; // eslint-disable-next-line no-unreachable console.log("数据库连接失败"); return; } console.log("数据库连接成功"); var db = client.db("mydata") db.collection("userdata").find({},{"LOCATION": 1, "_id": 0}).limit(10).toArray(function(err,result){ if(err) throw err; // console.log(result); res.status(200).json({ result }); client.close(); }) }) }); app.use('/', router); app.all('/', function(req, res, next){ res.send("node启动成功"); next(); }); app.listen(3003, () => { console.log('node服务器监听3003端口成功'); })
需要注意的是,mydata数据库是我事先已经建立好的,并且已经把交通事故的csv文件数据导入之后的。关于csv文件如何导入mongodb数据库就是一两行数据库指令,可以自行百度。另外,前后端交互的方式我用的是axios,node服务器运行在3003端口,前端运行在3000端口,所以记得在前端项目文件夹下的package.json文件中,添加这一行代码:"proxy": "http://localhost:3003",注意!这行代码必须添加到最后,至于为什么,我也不太清楚,哈哈。这样,前端就可以通过axios发送请求,后端收到请求后返回响应数据,前端拿到响应数据就可以展示给用户看了。
3、运行结果
五、项目总结