leaflet 使用kriging-contour.js 与 turf.js生成等值面
效果如下:
leaflet生成等值面网上搜索了好多资料但测试感觉都有点瑕疵,kriging.js 生成的canvas图片每个都是小方格影响美感,turf.js会有非法Polygon且有白色缝隙。就想着可不可以使用kriging.js生成等值面,turf,js进行裁剪。
但kriging.js返回的是栅格图片,偶然间查看到kriging-contour.js 可以返回矢量数据。(https://github.com/FreeGIS/kriging-contour)
具体代码如下:
kriging-contour.js 生成等值面的边界是根据传入的点坐标最大值最小值计算的,但按照我的点位数据,最后生成的等值面不能填充满geojson边界数据,我又在源码修改下,传个边界参数,如果有需要的可以自己加一下。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>leaflet克里金空间加插值turf.js</title> <style> html, body, #map { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; cursor: default; } </style> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin="" /> <!-- Make sure you put this AFTER Leaflet's CSS --> <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script> <script src="./js/truf.js"></script> <script src="./js/kriging-contour.js"></script> <script src="./json/clip.js"></script> <script src="./json/clippoint.js"></script> </head> <body> <div id="map"></div> <script> var map = L.map('map', { center: [38.65953686, 120.8696333], zoom: 9 }); let name = L.tileLayer( "http://wprd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7", ).addTo(map); // 计算边界范围 let dd1 = turf.bbox(boundaries); let points1 = { type: "FeatureCollection", features: [] } pointvalue.map(item => { points1.features.push({ geometry: { coordinates: [item.lng, item.lat], type: 'Point' }, properties: { value: item.value }, type: 'Feature' }) }) //计算克里金等值面 let levelV = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 250, 260, 270, 280, 290, 300, 400]; let colors = [{ fill: "#ffdc84" }, { fill: "#ffd782" }, { fill: "#ffd281" }, { fill: "#ffcd7f" }, { fill: "#ffc87e" }, { fill: "#ffc37c" }, { fill: "#ffbe7a" }, { fill: "#ffb979" }, { fill: "#feb477" }, { fill: "#feaf76" }, { fill: "#feaa74" }, { fill: "#fea573" }, { fill: "#fea071" }, { fill: "#fe9b6f" }, { fill: "#fe966e" }, { fill: "#fe906c" }, { fill: "#fe8b6b" }, { fill: "#fe8669" }, { fill: "#fe8167" }, { fill: "#fe7c66" }, { fill: "#fe7764" }, { fill: "#fe7263" }, { fill: "#fd6d61" }, { fill: "#fd6860" }, { fill: "#fd635e" }, { fill: "#fd5e5c" }, { fill: "#fd595b" }, { fill: "#fd5459" }, { fill: "#fd4f58" }, { fill: "#fd4a56" }] let kriging_contours = kriging.getVectorContour(points1, 'value', { model: 'exponential', sigma2: 0, alpha: 100 }, levelV, dd1); function hotColor(d) { let index = levelV.findIndex((item) => item >= d); if (index > -1) { return colors[index].fill } else { return colors[colors.length - 1].fill } } function sortArea(a, b) { return turf.area(b) - turf.area(a); } //按照面积对图层进行排序,规避turf的一个bug kriging_contours.features.sort(sortArea) //后面使用要求输入的参数为Feature<Polygon> ,而turf.isobands的是 MultiPolygon,需要先 flatten() 处理一下,同时去掉图形为空的记录 boundaries = turf.flatten(boundaries); //行政边界 kriging_contours = turf.flatten(kriging_contours); //等值面边界 //console.log('kriging_contours:'+JSON.stringify(kriging_contours)); //根据行政边界裁剪图形, //现在放大一些区域边界还是没有充满 后面可以封装成一个插件,在源码里面进行canvas clip 剪辑只显示的geojson区域,其余的栅格部分不显示 let features = []; //裁剪后的结果集 kriging_contours.features.forEach(function(feature1) { boundaries.features.forEach(function(feature2) { let intersection = null; try { intersection = turf.intersect(feature1, feature2); } catch (e) { try { //色斑图绘制之后,可能会生成一些非法 Polygon //解决的方法通常就是做一次 turf.buffer() 操作,这样可以把一些小的碎片 Polygon 清理掉。 feature1 = turf.buffer(feature1, 0); intersection = turf.intersect(feature1, feature2); } catch (e) { intersection = feature1; //实在裁剪不了就不裁剪了,根据业务需求自行决定 } } if (intersection != null) { intersection.properties = feature1.properties; intersection.id = (Math.random() * 100000).toFixed(0); features.push(intersection); } }); }); let intersection = turf.featureCollection(features); L.geoJSON(intersection, { style: function(feature) { return { fillColor: hotColor(feature.properties.value), weight: 0, fillOpacity: 0.3, }; } }).addTo(map); </script> </body> </html>
clip.js 是geojson 边界数据,
clippoint.js是插值点数据,部分格式如下:
[{ "lat": 34.42, "lng": 115.66, "value": 299, }, { "lat": 36.53, "lng": 118.44, "value": 312, }, { "lat": 36.4, "lng": 117, "value": 321, }, ........ ]
参考文档:https://segmentfault.com/a/1190000022293641?utm_source=tag-newest