危化品运输对安全性要求极高,车辆行驶路线通常需要提前报备并严格固定。一旦运输车辆驶离审批路线,就可能进入人口密集区或水源保护区,风险陡增。电子围栏技术通过在地图上划定许可区域,结合GPS实时定位数据,可以第一时间发现越界行为并触发报警。虽然现在前端框架层出不穷,但大量存量监管平台仍基于jQuery构建,本文就详细拆解如何在jQuery体系下实现一套完整的电子围栏越界报警处理机制。

电子围栏的数据建模与地图绘制
电子围栏本质上是一组地理坐标点按顺序连线围成的封闭区域,常见的有圆形围栏和多边形围栏两种。圆形围栏只需要一个圆心坐标加一个半径,判断简单;多边形围栏更贴合实际道路和区域边界,是监管平台的主流选择。我们通常将围栏信息设计成如下JSON结构,由后端接口下发:
// 单个围栏的数据结构
var fence = {
id: 'F001',
name: '化工园区限定路线',
type: 'polygon', // polygon 或 circle
points: [ // 多边形顶点,按顺序排列
{lng: 121.5123, lat: 31.2456},
{lng: 121.5342, lat: 31.2389},
{lng: 121.5410, lat: 31.2601},
{lng: 121.5188, lat: 31.2655}
],
alarmLevel: 2 // 越界报警等级
};
拿到数据后,用jQuery的$.ajax请求围栏列表,再交给地图SDK绘制。以高德地图为例,通过AMap.Polygon对象将点串连成可视化的围栏区域,并保存图层引用以便后续高亮闪烁:
function drawFence(map, fence) {
var path = fence.points.map(function (p) {
return [p.lng, p.lat];
});
var polygon = new AMap.Polygon({
path: path,
strokeColor: '#1890ff',
strokeWeight: 2,
fillColor: '#1890ff',
fillOpacity: 0.15
});
map.add(polygon);
// 将图层挂在围栏对象上,越界时方便操作样式
fence.layer = polygon;
return fence;
}
// 页面初始化时批量加载围栏
$(function () {
$.ajax({
url: '/api/fences',
method: 'GET',
dataType: 'json',
success: function (res) {
window.fenceList = res.data.map(function (f) {
return drawFence(window.map, f);
});
}
});
});
这里有一个容易被忽视的细节:围栏顶点必须严格按顺序(顺时针或逆时针)排列,如果后端返回的点序混乱,绘制出来的多边形会出现自相交,导致后续越界判断完全失效。前端最好在绘制前做一次简单的点序校验,发现异常及时提示。
越界判断的核心算法:射线法详解
判断车辆位置是否在多边形围栏内,最经典的算法是射线法(Ray Casting)。原理是:从待判断的点向任意方向引出一条射线,统计这条射线与多边形所有边的交点数量。交点为奇数说明点在多边形内部,偶数则在外部。该算法时间复杂度为O(n),n为多边形顶点数,对于监管平台常见的几十个顶点的围栏,性能完全够用。
/**
* 判断点是否在多边形内(射线法)
* @param {Object} point {lng, lat}
* @param {Array} polygon 顶点数组 [{lng, lat}, ...]
* @return {boolean} true 表示在围栏内
*/
function isPointInPolygon(point, polygon) {
var x = point.lng, y = point.lat;
var inside = false;
var len = polygon.length;
for (var i = 0, j = len - 1; i < len; j = i++) {
var xi = polygon[i].lng, yi = polygon[i].lat;
var xj = polygon[j].lng, yj = polygon[j].lat;
// 判断射线是否与当前边相交
var intersect = ((yi > y) !== (yj > y)) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) {
inside = !inside; // 每相交一次翻转一次状态
}
}
return inside;
}
代码中(yi > y) !== (yj > y)这一步是排除与射线平行的边,避免重复计数。需要注意的是,GPS坐标存在漂移,车辆恰好行驶在围栏边界上时,判断结果可能在true和false之间频繁跳动。工程上的处理办法是引入一个容差范围:连续两到三次判断在围栏外才认定为真实越界,单次出界视为噪声,这个去抖策略在后面的报警处理中会体现。
如果使用的是圆形围栏,判断则简单得多,直接计算车辆位置到圆心的球面距离,再与半径比较即可。距离计算推荐使用Haversine公式,避免把经纬度差当平面距离处理,在纬度较高的区域误差会非常明显。
实时位置获取:轮询与WebSocket的取舍
车辆位置数据是越界判断的输入源,前端获取方式主要有两种。第一种是定时轮询,用setInterval每隔几秒请求一次最新位置,实现简单、兼容性好,缺点是实时性受轮询间隔限制,且大量车辆监控时服务端压力大。第二种是WebSocket长连接,由服务端在收到车载终端上报后立即推送,实时性可以达到秒级,是当前监管平台的主流做法。两者也可以混合使用:正常监控走WebSocket,连接断开时自动降级为轮询兜底。
function connectWebSocket() {
var ws = new WebSocket('wss://monitor.ipipp.com/ws/vehicle');
ws.onmessage = function (event) {
var data = JSON.parse(event.data);
handlePosition(data.vehicleId, {lng: data.lng, lat: data.lat});
};
ws.onclose = function () {
// 断线降级:切回轮询模式
console.warn('WebSocket断开,降级为轮询');
startPolling();
};
}
function startPolling() {
window.pollTimer = setInterval(function () {
$.getJSON('/api/vehicles/latest', function (list) {
list.forEach(function (v) {
handlePosition(v.id, {lng: v.lng, lat: v.lat});
});
});
}, 5000);
}
收到位置后调用统一的handlePosition入口,遍历该车辆绑定的围栏逐个判断,为后续报警逻辑留出清晰的处理链路。这种单一入口的设计便于在链路中插入坐标纠偏、速度校验等扩展逻辑,而不需要改动多处代码。
越界报警的触发、去重与界面反馈
报警处理最容易出问题的地方不是判断本身,而是重复报警。车辆在围栏边界附近行驶时,如果每次位置更新都弹一次报警,操作员会很快被淹没在无效信息里。因此必须做两件事:一是状态化跟踪,为每辆车维护一个当前是否越界的标记,只有从界内变为界外这一瞬间才触发报警;二是报警恢复,车辆重新回到围栏内时同样要上报一次事件,形成完整的行为闭环。
// 车辆状态表
var vehicleState = {};
function handlePosition(vehicleId, pos) {
var fence = window.fenceList[0]; // 实际应查找车辆绑定的围栏
var outCount = vehicleState[vehicleId] ? vehicleState[vehicleId].outCount : 0;
var inFence = isPointInPolygon(pos, fence.points);
// 连续2次在界外才确认越界,过滤GPS漂移
if (!inFence) {
outCount++;
} else {
outCount = 0;
}
var state = vehicleState[vehicleId] || {};
state.outCount = outCount;
state.lastPos = pos;
if (outCount >= 2 && !state.alarming) {
state.alarming = true;
triggerAlarm(vehicleId, pos, fence);
} else if (inFence && state.alarming) {
state.alarming = false;
resolveAlarm(vehicleId);
}
vehicleState[vehicleId] = state;
}
function triggerAlarm(vehicleId, pos, fence) {
// 围栏高亮闪烁
fence.layer.setOptions({strokeColor: '#f5222d', fillColor: '#f5222d'});
// 上报服务端留痕
$.post('/api/alarm', JSON.stringify({
vehicleId: vehicleId,
fenceId: fence.id,
lng: pos.lng,
lat: pos.lat,
time: Date.now()
}));
// 前端弹窗与声音提示
showAlarmDialog(vehicleId, fence);
}
function resolveAlarm(vehicleId) {
// 恢复围栏样式、关闭报警面板等
$('#alarm-' + vehicleId).remove();
}
界面反馈方面,弹窗建议做成右上角可堆叠的提示条,配合地图上的车辆图标变红并跳动,同时播放提示音。报警提示音在浏览器自动播放策略下可能被拦截,可以在用户第一次点击页面时调用AudioContext解锁,或者提前让用户开启监控确认。所有报警必须持久化到服务端,前端展示只是辅助,事后追溯要以服务端记录为准。
最后补充一点性能经验:监控车辆较多时,越界判断和DOM更新都要控制频率,地图图标的移动可以用节流函数限制在每秒一到两次;报警列表的渲染避免频繁整体重绘,用jQuery增量插入对应节点即可。把这些细节处理到位,一套基于jQuery的电子围栏越界报警体系就足够稳定可靠,足以支撑日常危化品运输的监管需求。
jQuery电子围栏越界报警危化品运输监管修改时间:2026-09-09 17:55:17