postgis:更新车辆实时位置、使用聚合函数检测拥挤程度

一 内容和设计思想

1,获取车辆实时位置,将位置信息通过node实时更新到数据库中

2,构造数据库触发器,监测数据库数据变化,当实时位置更新到数据库时,通过postgis聚类函数查找离车辆指定距离车辆数目,数目越大、密度越大,道路越拥堵。

3,根据聚类分析后的密度判断道路拥挤程度

二 代码实现(leaflet+node+postgis)

1,构造触发器

js 复制代码
CREATE OR REPLACE FUNCTION changes()
RETURNS TRIGGER AS
$$
BEGIN
-- 发送 JSON 格式的变化数据到名为 'spatial_table_changes' 的通道
PERFORM pg_notify('car_changes', row_to_json(NEW)::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER after_change
AFTER INSERT OR UPDATE OR DELETE
ON car
FOR EACH ROW
EXECUTE FUNCTION changes();

2,node接受请求进行查询

js 复制代码
const express = require('express');
const router = express.Router();
const pool = require('../db'); // 引入数据库连接配置
//更新小车实时位置
router.post('/data', async (req, res) => {
  const { param1, param2 } = req.body;
  try {
    // 将 param1 和 param2 合并为一个点
    const pointText = `POINT(${param2} ${param1})`;
    // 在这里执行数据库更新,假设你的数据库表使用 geometry 类型的字段
    const result = await pool.query('UPDATE car SET geom = ST_GeomFromText($1, 4326) where id=5834 RETURNING *', [pointText]);
    res.json(result.rows[0]);
  } catch (error) {
    console.error('更新数据时出错:', error);
    res.status(500).json({ error: '更新数据时出错' });
  }
});
// 设置要监听的通道名称
const channelName = 'car_changes';
// 在应用程序启动时设置监听器
const setupNotificationListener = async () => {
  const client = await pool.connect();
  // 在通道上添加监听器
  await client.query(`LISTEN ${channelName}`);
  // 处理接收到的通知
  client.on('notification', async () => {
    router.get('/clusterResult', async (req, res) => {
      try {
        // 在通知事件处理程序中执行 SQL 查询
        const queryResult = await pool.query(`
        WITH ClusteredData AS (
          SELECT
            id,
            ST_ClusterDBSCAN(st_transform(geom, 3857), eps := 100, minpoints := 2) OVER () AS cid
          FROM
            car
        )
        SELECT
          COUNT(*) AS num_points_in_cluster
        FROM
          ClusteredData
        WHERE
          cid = (SELECT cid FROM ClusteredData WHERE id = 5834)
      `);
        res.json({ result: queryResult.rows });
      } catch (error) {
        console.error('Error executing SQL query:', error);
      }
    });
  });
  // 在应用程序关闭时释放连接
  process.on('exit', () => {
    client.release();
  });
  // 在捕获到未处理的 Promise 拒绝时退出
  process.on('unhandledRejection', (reason, promise) => {
    console.error('Unhandled Rejection at:', promise, 'reason:', reason);
    process.exit(1);
  });
};
// 调用设置监听器的函数
setupNotificationListener();

3,前端可视化展示

js 复制代码
   //获取所有车辆位置
        axios.get('http://localhost:3000/allMarker')
            .then((response) => {
                const data = response.data;
                const icon = L.icon({
                    iconUrl: 'https://openlayers.org/en/v8.2.0/examples/data/icon.png',
                    iconSize: [20, 25], 
                })
                for (var i = 0; i < data.length; i++) {
                    L.marker([data[i].y, data[i].x],{icon:icon}).addTo(geoMap);
                }
            })
            .catch((error) => {
                console.error("Error fetching data:", error);
            });
        //加载路线网络
        axios.get('http://localhost:3000/route')
            .then((response) => {
                // 请求成功时的处理
                const geojsonMarkerOptions = {
                    radius: 4,
                    weight: 3,
                };
                const data = response.data;
                const vectorLayer = L.geoJSON(data, {
                    pointToLayer: function (feature, latlng) {
                        return L.circleMarker(latlng, geojsonMarkerOptions);
                    },
                });
                vectorLayer.addTo(geoMap)
            })
            .catch((error) => {
                // 请求失败时的处理
                console.error('请求失败:', error);
            });
        //将小车实时坐标更新到数据库并设置触发器,通过聚合函数检测离车100m内的车数,得出车辆密度判断道路拥挤程度。
        async function sendData(data1, data2) {
            try {
                const data = {
                    param1: data1,
                    param2: data2
                };
                const response = await axios.post('http://localhost:3000/data', data);
                axios.get('http://localhost:3000/clusterResult')
                    .then((response) => {
                        // 请求成功时的处理
                        var value;
                        const data = response.data;
                        if (data.result[0].num_points_in_cluster <= 3) {
                           value='畅通'
                        } else if (data.result[0].num_points_in_cluster <= 6) {
                            value='一般'
                        } else {
                            value='拥堵'
                        }
                        document.getElementById('trafficValue').textContent=value;
                    })
            } catch (error) {
                console.error('发送到后端时出错:', error);
            }
        }

三 实际效果

相关推荐
娃哈哈哈哈呀36 分钟前
Vue 3 动态 ref 的使用方式(表格)
前端·javascript·vue.js
2401_896008193 小时前
GCC 使用说明
前端·javascript·算法
守城小轩6 小时前
JavaScript vs Python 用于 Web Scraping(2025):终极对比指南
前端·chrome·chrome devtools·指纹浏览器·浏览器开发·超级浏览器
风逸hhh9 小时前
python打卡day29@浙大疏锦行
开发语言·前端·python
LuckyLay9 小时前
Vue百日学习计划Day33-35天详细计划-Gemini版
前端·vue.js·学习
ᖰ・◡・ᖳ9 小时前
JavaScript:PC端特效--缓动动画
开发语言·前端·javascript·css·学习·html5
会飞的鱼先生10 小时前
vue2、vue3项目打包生成txt文件-自动记录打包日期:git版本、当前分支、提交人姓名、提交日期、提交描述等信息 和 前端项目的版本号json文件
前端·vue.js·git·json
!win !10 小时前
uni-app项目从0-1基础架构搭建全流程
前端·uni-app
c_zyer11 小时前
使用 nvm 管理 Node.js 和 npm 版本
前端·npm·node.js
布Coder11 小时前
前端 vue + element-ui 框架从 0 - 1 搭建
前端·javascript·vue.js