(1)主要过程:结合Kriging.js 实现 Mapboxgl 上的插值图
(2)效果:
(3)代码
HTML 、CSS:
<head><meta charset="UTF-8" /><title>Mapboxgl(canvas) + kriging.js</title><style>html,body,#map {width: 100%;height: 100%;margin: 0;padding: 0;}</style><link rel="stylesheet" href="../lib/js/geoglobe/mapbox-gl.css" type="text/css" /><script type="text/javascript" src="../lib/js/geoglobe/mapbox-gl.js"></script><script type="text/javascript" src="../lib/js/turf/turf_new.min.js"></script><script type="text/javascript" src="../lib/js/interpolation/kriging_noModule.js"></script><!-- 行政区划数据 (为了偷懒使用了js的形式) --><script src="./data/wuhanShi.js"></script><body><!-- 用于绘制插值图的canvas --><canvas id="canvasMap" style="display: none; opacity: 0.2"></canvas><div id="map"></div><script src="./js/mapboxKriging.js"></script></body>
</head>
完整 JS:
// 颜色范围 (自定义)
const colors = ['rgba(0,0,0,0)','rgb( 82 , 184 , 70 )','rgb(90,187,68)','rgb(98,189,66)','rgb(106,192,63)','rgb(114,194,61)','rgb(122,197,59)','rgb(130,199,57)','rgb(138,202,55)','rgb(146,204,52)','rgb(154,207,50)','rgb(162,209,48)','rgb(171,212,46)','rgb(179,215,44)','rgb(187,217,41)','rgb(195,220,39)','rgb(203,222,37)','rgb(211,225,35)','rgb(219,227,33)','rgb(227,230,30)','rgb(235,232,28)','rgb( 243 , 235 , 26 )','rgb(243,230,26)','rgb(243,224,27)','rgb(243,219,27)','rgb(244,213,28)','rgb(244,208,28)','rgb(244,203,29)','rgb(244,197,29)','rgb(244,192,30)','rgb(244,186,30)','rgb(244,181,30)','rgb(245,176,31)','rgb(245,170,31)','rgb(245,165,32)','rgb(245,159,32)','rgb(245,154,33)','rgb(245,149,33)','rgb(246,143,34)','rgb(246,138,34)','rgb(246,132,35)',
];let canvasImg, // 用于插值的画布map, // 地图实例points, // 插值点 通过随机数产生;range; // 插值范围// 插值范围 外边界
// 可以使用 turf.js 库,获取行政区划的bbox,即为外边界
let xlim = [113.70228083999996, 115.08257304000006];
let ylim = [29.96907695999994, 31.36125996000004];// 用于将canvas导出的图片放置在地图上合适位置
let coordinates = [[xlim[0], ylim[1]],[xlim[0], ylim[0]],[xlim[1], ylim[0]],[xlim[1], ylim[1]],
];// 地图初始化
function init() {map = new mapboxgl.Map({container: 'map',style: {version: 8,sources: {cartodb: {tiles: ['http://b.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'],tileSize: 256,type: 'raster',},},layers: [{id: 'cartodb',type: 'raster',source: 'cartodb',},],},center: [114.44515001943142, 30.649477958235423],zoom: 8.3,pitch: 0,});// 地图加载map.on('load', () => {createPoints();addStateLayer();cavasLayer();});
}
// 添加边界图层
function addStateLayer() {let wuhanFeatures = [];wuhanShi.features.forEach((element) => {wuhanFeatures.push({type: 'Feature',properties: element.attributes,geometry: {type: 'Polygon',coordinates: element.geometry.rings,},});});map.addSource('wuhan', {type: 'geojson',data: {type: 'FeatureCollection',features: wuhanFeatures,},});map.addLayer({id: 'wuhan',source: 'wuhan',type: 'line',paint: {'line-color': 'black','line-width': 2,},});// 插值范围range = wuhanFeatures[0].geometry.coordinates;
}
// 创建用于插值的随机数据点
function createPoints() {var randomPoints = turf.randomPoint(25, {bbox: [113.70228083999996, 29.96907695999994, 115.08257304000006, 31.36125996000004],});randomPoints.features.forEach((item, index) => {item.properties = {z: Math.round(Math.random() * 100),id: index,};});// console.log(randomPoints); // 打印randomPoints查看插值点数据// 插值点图层map.addSource('point', {type: 'geojson',data: randomPoints,});map.addLayer({id: 'point',source: 'point',type: 'circle',paint: {'circle-color': 'black',},});// 插值点数据points = randomPoints.features;
}
//进行克里金插值
function loadkriging() {var canvas = document.getElementById('canvasMap');canvas.width = 1000;canvas.height = 1000;var n = points.length;var t = []; // 数值var x = []; // 经度var y = []; // 纬度for (var i = 0; i < n; i++) {t.push(points[i].properties.z);x.push(points[i].geometry.coordinates[0]);y.push(points[i].geometry.coordinates[1]);}//对数据集进行训练var variogram = kriging.train(t, x, y, 'exponential', 0, 100);//使用variogram对象使polygons描述的地理位置内的格网元素具备不一样的预测值,最后一个参数,是插值格点精度大小var grid = kriging.grid(range, variogram, (ylim[1] - ylim[0]) / 250);//将得到的格网grid渲染至canvas上kriging.plot(canvas, grid, [xlim[0], xlim[1]], [ylim[0], ylim[1]], colors);// 将插值结果进行处理,转换为图片格式以便作为图层接入mapboxgl地图中return drawImage(0, 0, 0.5);
}
// canvas图片处理
function drawImage(x, y, alpha) {// 获取canvas元素对应的DOM对象var canvas = document.getElementById('canvasMap');// 获取在canvas上绘图的CanvasRenderingContext2D对象var ctx = canvas.getContext('2d');// 绘制图片// ctx.drawImage(image, x, y);// 获取从x、y开始,宽为image.width、高为image.height的图片数据// 也就是获取绘制的图片数据var imgData = ctx.getImageData(x, y, canvas.width, canvas.height);for (var i = 0, len = imgData.data.length; i < len; i += 4) {// 改变每个像素的透明度imgData.data[i + 3] = imgData.data[i + 3] * alpha;}// 将获取的图片数据放回去。ctx.putImageData(imgData, x, y);return canvas.toDataURL('image/png');
}// 添加一个raster图层到地图中,使用的数据源是canvas转换为的图片形式(插值结果)
function cavasLayer() {map.addSource('kriging', {type: 'image',url: loadkriging(),coordinates: [coordinates[0], coordinates[3], coordinates[2], coordinates[1]],});map.addLayer({id: 'kriging',type: 'raster',source: 'kriging',paint: {'raster-opacity': 1,},});
}init();
我觉得应该不能再详细了...
(4)还存在的问题:目前够用。如有问题请联系我改正!