Java后端进行经纬度点抽稀聚合,HTML呈现及前端聚合实现点聚合~

  • 1. 效果图~
    • 1.1 前端实现聚合及呈现
    • 1.2 后端实现点聚合,前端渲染呈现效果图
  • 2. 原理
  • 3. 源码
    • 3.1 前端JS实现点聚合及呈现源码
    • 3.2 后端点聚合(返回geojson)及前端自实现渲染源码
  • 参考

1. 效果图~

1.1 前端实现聚合及呈现

1.2 后端实现点聚合,前端渲染呈现效果图

2. 原理

  1. 构建测试数据
  2. 依赖前端传递的参数:bounds、mPXInMeters、zoom;分别是窗口的可视经纬度范围、单位像素距离、地图级别;

单位像素距离也可以根据地图级别进行计算;

{“level”: 0, “resolution”: 156543.033928},
{“level”: 1, “resolution”: 78271.5169639999},
{“level”: 2, “resolution”: 39135.7584820001},
{“level”: 3, “resolution”: 19567.8792409999},
{“level”: 4, “resolution”: 9783.93962049996},
{“level”: 5, “resolution”: 4891.96981024998},
{“level”: 6, “resolution”: 2445.98490512499},
{“level”: 7, “resolution”: 1222.99245256249},
{“level”: 8, “resolution”: 611.49622628138},
{“level”: 9, “resolution”: 305.748113140558},
{“level”: 10, “resolution”: 152.874056570411},
{“level”: 11, “resolution”: 76.4370282850732},
{“level”: 12, “resolution”: 38.2185141425366},
{“level”: 13, “resolution”: 19.1092570712683},
{“level”: 14, “resolution”: 9.55462853563415},
{“level”: 15, “resolution”: 4.77731426794937},
{“level”: 16, “resolution”: 2.38865713397468},
{“level”: 17, “resolution”: 1.19432856685505},
{“level”: 18, “resolution”: 0.597164283559817}

  1. 后端可以设置多少个像素聚合;

3. 源码

3.1 前端JS实现点聚合及呈现源码

<!DOCTYPE html>
<html>
<head><meta charset='utf-8' /><title>创建样式聚类</title><meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /><script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.js'></script><link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.css' rel='stylesheet' /><style>body { margin:0; padding:0; }#map { position:absolute; top:0; bottom:0; width:100%; }</style>
</head>
<body><div id='map'></div><script>
mapboxgl.accessToken = 'pk.eyJ1IjoiemhhbmcyMDIxIiwiYSI6ImNrbGthdmFvbDM0cTMyb3M2eXFiODR5d3QifQ.ow97I1ikb9zlP3p9qmFuBQ';
var map = new mapboxgl.Map({container: 'map',style: 'mapbox://styles/mapbox/dark-v10',center: [-103.59179687498357, 40.66995747013945],zoom: 3
});map.on('load', function() {// Add a new source from our GeoJSON data and set the// 'cluster' option to true. GL-JS will add the point_count property to your source data.map.addSource("earthquakes", {type: "geojson",// Point to GeoJSON data. This example visualizes all M1.0+ earthquakes// from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.data: "https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson",cluster: true,clusterMaxZoom: 14, // Max zoom to cluster points onclusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)});map.addLayer({id: "clusters",type: "circle",source: "earthquakes",filter: ["has", "point_count"],paint: {// Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)// with three steps to implement three types of circles://   * Blue, 20px circles when point count is less than 100//   * Yellow, 30px circles when point count is between 100 and 750//   * Pink, 40px circles when point count is greater than or equal to 750"circle-color": ["step",["get", "point_count"],"#51bbd6",100,"#f1f075",750,"#f28cb1"],"circle-radius": ["step",["get", "point_count"],20,100,30,750,40]}});map.addLayer({id: "cluster-count",type: "symbol",source: "earthquakes",filter: ["has", "point_count"],layout: {"text-field": "{point_count_abbreviated}","text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],"text-size": 12}});map.addLayer({id: "unclustered-point",type: "circle",source: "earthquakes",filter: ["!", ["has", "point_count"]],paint: {"circle-color": "#11b4da","circle-radius": 4,"circle-stroke-width": 1,"circle-stroke-color": "#fff"}});// inspect a cluster on clickmap.on('click', 'clusters', function (e) {var features = map.queryRenderedFeatures(e.point, { layers: ['clusters'] });var clusterId = features[0].properties.cluster_id;map.getSource('earthquakes').getClusterExpansionZoom(clusterId, function (err, zoom) {if (err)return;map.easeTo({center: features[0].geometry.coordinates,zoom: zoom});});});map.on('mouseenter', 'clusters', function () {map.getCanvas().style.cursor = 'pointer';});map.on('mouseleave', 'clusters', function () {map.getCanvas().style.cursor = '';});
});
</script></body>
</html>

3.2 后端点聚合(返回geojson)及前端自实现渲染源码

/*** @param visibleBounds 屏幕的范围 前端传* @param list          所有的点数据* @param mClusters     聚合后的数据集合* @param isLattice     是否是方格和距离的算法 , 是 方格和距离的算法   , 否 距离算法* @return*/
private static void calculateOrgClusters(LatLngBounds visibleBounds, List<Map<String, Object>> list, List<Cluster> mClusters, double mClusterDistance, Integer zoom, boolean isLattice) {mIsCanceled = false;mClusters.clear();ClusterItem clusterItem = new RegionItem();LatLng mLatLng;for (int i = 0; i < list.size(); i++) {Map<String, Object> data = list.get(i);mLatLng = new LatLng(Double.parseDouble(data.get("lat").toString()), Double.parseDouble(data.get("lng").toString()));clusterItem = new RegionItem(mLatLng, data);if (mIsCanceled) {return;}LatLng latlng = clusterItem.getPosition();if (visibleBounds.contains(latlng)) {Cluster cluster = null;if (isLattice) {// 方格和距离的算法cluster = getClusterFangGe(latlng, mClusters);} else {// 距离算法cluster = getCluster(latlng, mClusters, mClusterDistance, zoom);}if (cluster != null) {cluster.addCount();} else {cluster = new Cluster(latlng);mClusters.add(cluster);cluster.addClusterItem(clusterItem);cluster.addCount();cluster.setMap(data);// 设置中心点的范围if (isLattice) {LatLngBounds latLngBounds = AMapUtils.getAround(latlng, mClusterDistance);cluster.setLatLngBounds(latLngBounds);}}}}
}
<!DOCTYPE html>
<html>
<head><meta charset='utf-8'/><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no'/><!--本地加载的js及css文件--><script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.js'></script><link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.css' rel='stylesheet'/><script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><style>#m_infobar {position: absolute;bottom: 100px;left: 20px;width: 200px;height: 200px;overflow: auto;z-index: 201;background: greenyellow;padding-left: 10px;}#menu {background: #fff;position: absolute;z-index: 1;top: 70px;right: 50px;border-radius: 3px;width: 120px;border: 1px solid rgba(0, 0, 0, 0.4);font-family: 'Open Sans', sans-serif;}#menu a {font-size: 13px;color: #404040;display: block;margin: 0;padding: 0;padding: 10px;text-decoration: none;border-bottom: 1px solid rgba(0, 0, 0, 0.25);text-align: center;}#menu a:last-child {border: none;}#menu a:hover {background-color: #f8f8f8;color: #404040;}#menu a.active {background-color: #3887be;color: #ffffff;}#menu a.active:hover {background: #3074a4;}</style>
</head>
<body style="height: 100%;"><div class="panel panel-default"><div class="panel-heading"><div class="row"><div class="col-md-4"><strong>Geojson后端聚合轨迹点</strong></div><div class="col-md-8"><label id="i_click"></label></div></div></div><div class="panel-body"><nav id="menu"></nav><div id="map" style="width: 100%; height: 800px;"><div id='m_infobar'><div id="tooltip-name"></div><div id='tooltip'></div></div></div></div><div class="panel-footer" style="bottom: 0px;"><div class="row"><div class="col-xs-4"><label id="i_coordinate"></label></div><div class="col-xs-8"><label id="i_show"></label></div></div></div>
</div><script>mapboxgl.accessToken = 'pk.eyJ1IjoiemhhbmcyMDIxIiwiYSI6ImNrbGthdmFvbDM0cTMyb3M2eXFiODR5d3QifQ.ow97I1ikb9zlP3p9qmFuBQ';var map = new mapboxgl.Map({resizeEnable: true,container: 'map',style: 'mapbox://styles/mapbox/dark-v10',center: [105, 34],zoom: 4});map.on('load', function () {// Add a new source from our GeoJSON data and set the// 'cluster' option to true. GL-JS will add the mag property to your source data.map.addSource("earthquakes", {type: "geojson",// Point to GeoJSON data. This example visualizes all M1.0+ earthquakes       // from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.// data: "https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson",// 只需修改数据来源~~data: "/geo?bounds=" + map.getBounds().toString().replaceAll('LngLat', '').replace('Bounds', '').replace('),', ';').replaceAll('(', '').replaceAll(')', '') + "&zoom=" + map.getZoom(),
//            cluster: true,// clusterMaxZoom: 20, // Max zoom to cluster points on//clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)});var url = "/geo?bounds=" + map.getBounds().toString().replaceAll('LngLat', '').replace('Bounds', '').replace('),', ';').replaceAll('(', '').replaceAll(')', '') + "&zoom=" + map.getZoom();var zoomOri = map.getZoom();console.log('url------: ' + url);map.addLayer({id: "clusters",type: "circle",source: "earthquakes",filter: ["has", "mag"],paint: {// Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)// with five steps to implement three types of circles://   * 11b4da,1px circles when point mag is 1//   * 99CCCC,1px circles when point mag is less than 20//   * Blue, 20px circles when point mag is less than 100//   * Yellow, 30px circles when point mag is between 100 and 750//   * Pink, 40px circles when point mag is greater than or equal to 750"circle-color": ["step",["get", "mag"],"#11b4da",1,"#99CCCC",20,"#3366FF",100,"#f1f075",750,"#f28cb1"],"circle-radius": ["step",["get", "mag"],20,100,30,750,40]}});map.addLayer({id: "cluster-mag",type: "symbol",source: "earthquakes",filter: ["has", "mag"],layout: {"text-field": "{mag}","text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],"text-size": 12}});// inspect a cluster on clickmap.on('click', 'clusters', function (e) {var features = map.queryRenderedFeatures(e.point, {layers: ['clusters']});var deviceId = features[0].properties.deviceId;var clusterId = features[0].properties.clusterId;console.log("deviceId: ", deviceId);console.log("clusterId: ", clusterId);console.log("lng,lat: ", "[" + features[0].geometry.coordinates[0] + "," + features[0].geometry.coordinates[1] + "]");console.log("lng,lat: ", JSON.stringify(features[0].geometry.coordinates));map.easeTo({center: features[0].geometry.coordinates,zoom: map.getZoom()});});map.on("mousemove", function (e) {var features = map.queryRenderedFeatures(e.point, {layers: ["clusters"]});if (features.length) {//show name and value in sidebarvar item = features[0].properties;var arr = [];arr.push("设备id:" + item.deviceId);arr.push("在线:" + item.online);arr.push("故障:" + item.fault);arr.push("重叠点数:" + item.mag);viewMapOption();document.getElementById('tooltip').innerHTML = arr.join('<br/>');} else {//if not hovering over a feature set tooltip to emptydocument.getElementById('tooltip').innerHTML = "";}});map.on('mouseenter', 'clusters', function () {map.getCanvas().style.cursor = 'pointer';});map.on('mouseleave', 'clusters', function () {map.getCanvas().style.cursor = '';});// 获取点数据function queryData(str) {zoom = map.getZoom();zoom = zoom.toString().substr(0, zoom.toString().indexOf("."));if (zoom) {} else {console.log("queryData0---: ", zoom);zoom = zoomOri + 1;console.log("queryData1---: ", zoom);}var url = "/geo?bounds=" + map.getBounds().toString().replaceAll('LngLat', '').replace('Bounds', '').replace('),', ';').replaceAll('(', '').replaceAll(')', '') + "&zoom=" + zoom;console.log('queryData: ', str, url);$.ajax({url: url,  // ajax请求要请求的地址type: "get", // 请求的类型  get  postsuccess: function (data) {// 请求成功之后要执行的方法// data  接收请求成功之后的返回值map.getSource('earthquakes').setData(data);},error: function (error) {// 请求失败之后要执行的内容}})}// 移动结束事件map.on('moveend', queryData);// 缩放完成事件map.on('zoomend', queryData);// 拖拽完成事件map.on('dragend', queryData);// 鼠标滚动map.on("wheel", queryData);viewMapOption();map.on('move', viewMapOption);map.on('mousemove', viewCoordinate);});function locationByXY() {var px = parseFloat($("#m_x").val());var py = parseFloat($("#m_y").val());map.setCenter([px, py]);}/*** 容器改变触发*/function resizeMap() {//初始化宽度、高度$("#map").height($(window).height() - 150);//当文档窗口发生改变时 触发$(window).resize(function () {$("#map").height($(window).height() - 150);});}function viewCoordinate(evt) {if (evt != null) $("#i_coordinate").text("当前坐标:" + evt.lngLat.lng.toFixed(7) + "," + evt.lngLat.lat.toFixed(7));}/*** 显示地图状态信息*/function viewMapOption() {var bounds = map.getBounds();console.log("级别=" + map.getZoom() + ",中心(" + bounds.getCenter().lng.toFixed(7) + "," + bounds.getCenter().lat.toFixed(7) + ")");console.log("边界[" + bounds.getSouthWest().lng.toFixed(7) + "," + bounds.getSouthWest().lat.toFixed(7) + ";" + bounds.getNorthEast().lng.toFixed(7) + "," + bounds.getNorthEast().lat.toFixed(7) + "]");$("#i_click").text("级别=" + map.getZoom() + ",中心(" + bounds.getCenter().lng.toFixed(7) + "," + bounds.getCenter().lat.toFixed(7) + ")");$("#i_show").text("边界[" + bounds.getSouthWest().lng.toFixed(7) + "," + bounds.getSouthWest().lat.toFixed(7) + ";" + bounds.getNorthEast().lng.toFixed(7) + "," + bounds.getNorthEast().lat.toFixed(7) + "]");}
</script></body>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet">
</html>

参考

  • https://blog.csdn.net/qq_36120342/article/details/108752068
  • https://gitee.com/liuhaomin/publicdemo/tree/master/dianjuhe 依赖mysql库
  • https://www.cnblogs.com/haibalai/p/9049625.html

Java后端进行经纬度点抽稀聚合,HTML呈现及前端聚合实现点聚合~相关推荐

  1. java后端根据经纬度获取地址(高德地图)

    1.申请高德地图key 2.逆地理编码(坐标->地址)-地理X: https://lbs.amap.com/demo/jsapi-v2/example/geocoder/regeocoding ...

  2. JAVA后端获取经纬度

    通过天地图来对接 国家地理信息公共服务平台 天地图 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; ...

  3. java 后端与前端Date类型与String类型互相转换(使用注解)

    一:java 后端格式化输出Date类型的属性值到前端 后端返回的类型中,直接定义Date类型,加上此注解,直接将Date类型转成自定义的格式给前端 class TestDateOutput{@Jso ...

  4. 【 malcolmcrum】基于Java后端与Typescript前端的代码自动生成

    Java 后端和 Typescript 前端虽然都是类型语言,但传统上这两个域上的类型之间存在脱节.本文推荐的这个工具让我们在一个地方修改一个方法或类,并立即在其他地方直接使用它,或者在我们误用它时在 ...

  5. Java后端数据分页问题

    文章目录 前言 一.简易分页 二.使用Page工具封装分页(Mybatis) 1.定义相关方法及工具 2.后端方法 总结 前言 Java后端数据分页问题. 一.简易分页 前端传入分页起始页start, ...

  6. 【Java分享客栈】我有一个朋友,和前端工程师联调接口被狠狠鄙视了一番。

    前言 我有一个朋友,昨天和前端工程师联调一个接口,然后被狠狠鄙视了一番. 大家知道,自从前后端分离以后,像我一样一直以Java工程师为傲而自居的码圣们就砍掉了一半脊梁,从此被贴上了"Java ...

  7. 我作为Java后端,分享一下入门Spark编程的经历!

    作者:陌北有棵树,玩Java,架构师社区合伙人! 最近由于工作任务,需要掌握大数据技术栈的相关知识,于是开始了入门大数据的漫漫之路. 相比传统Java后端的技术栈来说,大数据关注的技术点可以说是另一套 ...

  8. Java后端架构开荒实战(二)——单机到集群

    Java后端架构开荒实战(二)--单机到集群 一.前言 上一篇文章做了一些准备工作,这边文章正式开始写代码. 在做好单实例架构之后,升级到集群是一件很容易的事情,所以把单机和集群放在这一篇一起说. 二 ...

  9. Java后端架构开荒实战(一)——基础设施

    Java后端架构开荒实战(一)--基础设施 一.前言 之前的文章有讲过后端架构演进系列,这个系列文章还是以一个经典的电商系统为例子,来讲讲Robben是如何在实际开发中一步一步打造出一个大型的后端架构 ...

最新文章

  1. eclipse如何导出WAR包
  2. ORACLE纯SQL实现多行合并一行
  3. Oracle的row_number函数
  4. 光流 | 由粗到精的稠密光流算法
  5. segue和delegate实现两个页面传值
  6. react-native flatlist 上拉加载onEndReached方法频繁触发的问题
  7. multism中ui和uo应该怎么表示_王者荣耀:梦泪直播时谈到体验服大改动,表示装备的改动很关键...
  8. 测试计划与测试方案的区别
  9. busybox inittab
  10. nuke软件功能有哪些?苹果Mac影视后期特效合成软件NUKE 13
  11. JNA-Java跨平台调用的利器
  12. 基于springboot+vue的二手商城(闲置物品交易)(前后端分离)
  13. 科学计算器 c语言源代码,科学计算器C语言代码
  14. cad插件苹果系统_CAD看图软件mac版|CAD迷你看图 for Mac下载 v4.0.0 官方版_最火软件站...
  15. 特征向量的归一化方法
  16. 视觉/视觉惯性SLAM最新综述:领域进展、方法分类与实验对比
  17. linux 查看go安装目录,Linux系统安装Go语言的步骤
  18. GDrive is here
  19. 学术论文等级划分(包括EI会议论文)
  20. 直播回顾 | 阿拉丁带你探秘未来文旅新生态

热门文章

  1. 快速搭建第一个Mybatis程序
  2. Dialog 带白色的边的处理方法
  3. Fragment 使用 replace 的方式实现切换 以及切换的时候Fragment 生命周期
  4. 格式化verilog/systemverilog代码插件
  5. 漫谈五种IO模型(主讲IO多路复用)
  6. centOS7 LNMP+phpmyadmin环境搭建 第三篇phpmyadmin安装
  7. Curator Cache
  8. java中名词概念的理解
  9. Java学习笔记---字符类型
  10. Windows Phone开发(39):漫谈关键帧动画上篇 转:http://blog.csdn.net/tcjiaan/article/details/7550506...