集成Three.js
Three.js是基于原生WebGL封装运行的三维引擎库,在所有WebGL引擎中,Three.js是国内文资料最多、使用最广泛的三维引擎。Three.js可应用于Web 3D的可视化(如产品在线浏览、在线三维可视化等),H5/微信小程序游戏(如跳一跳),科教领域,机械领域,WebVR(VR看房、VR看车等)以及家装室内设计等方面,是一个比较轻量级的跨浏览器JavaScript库 ,适合在浏览器中创建和显示动画3D计算机图形。将Cesium的行星级渲染和GIS功能与Three.js广泛而易用的通用3D API相结合,为新的WebGL体验开启了许多可能性。两者的集成总体思路如下:
(1)创建两个容器,分别用于显示cesium和three的场景
(2)初始化cesium、three渲染器
(3)调整three和cesium的渲染频率保持一致
(4)调整three和cesium的相机位置角度保持一致
(5)加入要展示的图形
以下展示了部分核心代码。
<div id="cesiumContainer"></div>
<div id="ThreeContainer"></div>
// 2-1.初始化cesium
// cesium初始化时,要将它的自动渲染关掉(即useDefaultRenderLoop属性调整为false)
cesium.viewer = new Cesium.Viewer("cesiumContainer", {
useDefaultRenderLoop: false, // 关闭自动渲染
...
});
// 2-2.初始化three
function initThree() {
let fov = 45;
let width = window.innerWidth;
let height = window.innerHeight;
let aspect = width / height;
let near = 1;
let far = 10 * 1000 * 1000; // needs to be far to support Cesium's world-scale rendering
three.scene = new THREE.Scene();
three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
three.renderer = new THREE.WebGLRenderer({ alpha: true }); ThreeContainer.appendChild(three.renderer.domElement);
}
// 3.调整three和cesium的渲染频率
// 手动开启cesium和three的渲染,并放进一个渲染频率里。
function loop() {
requestAnimationFrame(loop);
renderCesium();
renderThreeObj();
// 4.调整相机一致
// 这里使用的cesium的相机为主相机,使three的相机与cesium保持一致即可。
renderCamera();
}
// 5.加入要展示的图形
// 这里加入一个cesium的图形polygon,再加入一个three的球体,以及一个three的12面体。
function init3DObject() {
let entity = {
name: "Polygon",
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([
minWGS84[0],
minWGS84[1],
maxWGS84[0],
minWGS84[1],
maxWGS84[0],
maxWGS84[1],
minWGS84[0],
maxWGS84[1],
]),
material: Cesium.Color.RED.withAlpha(0.1),
},
};
let Polypon = cesium.viewer.entities.add(entity);
let doubleSideMaterial = new THREE.MeshNormalMaterial({
side: THREE.DoubleSide,
});
geometry = new THREE.SphereGeometry(1, 32, 32);
let sphere = new THREE.Mesh(
geometry,
new THREE.MeshPhongMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
})
); //12面体
...
}
}
效果图如下:
集成Echarts
Echarts 是一个基于 JavaScript 的开源可视化图表库,具有丰富的图表类型,可用于地理数据可视化的地图、热力图、线图等。Cesium通过与Echarts的地理数据可视化能力相结合,大大增强Cesium整体的可视化效果。本文通过封装EchartsLayer来实现迁徙图的效果。需要注意的是,在图表的option配置项中不需要写geo,同时每个series数组中元素都必须加coordinateSystem:'GLMap'。部分核心代码如下:
var EchartsLayer = function (map, options) {
this._map = map;
this._overlay = this._createChartOverlay();
if (options) {
this._registerMap();
}
this._overlay.setOption(options || {});
};
let _echartLayer = new EchartsLayer(viewer, option);
简单效果图如下所示:
集成heatmap
heatmap.js是一个轻量级的、最先进的用于表达热力图的可视化前端库,比如人群分布情况、污染物浓度变化情况、信号强度等。感兴趣的同学可以进入官网https://www.patrick-wied.at/static/heatmapjs/ 查看详情。
下面说一下cesium和heatmap集成的原理,其实也很简单,就是把使用heatmap.js生成的热力图,以贴图材质的方式赋给某个几何图形贴图属性。部分核心代码如下:
// 根据热力图图片范围,生成随机热力点和强度值
var dataRaw = [];
for (var i = 0; i < len; i++) {
var point = {
lat: latMin + Math.random() * (latMax - latMin),
lon: lonMin + Math.random() * (lonMax - lonMin),
value: Math.floor(Math.random() * 100),
};
dataRaw.push(point);
}
// 生成数据
for (var i = 0; i < len; i++) {
var dataItem = dataRaw[i];
var point = {
x: Math.floor(((dataItem.lat - latMin) / (latMax - latMin)) * width),
y: Math.floor(((dataItem.lon - lonMin) / (lonMax - lonMin)) * height),
value: Math.floor(dataItem.value),
};
max = Math.max(max, dataItem.value);
points.push(point);
}
// 创建热力图
var heatmapInstance = h337.create({
container: document.querySelector(".heatmap"),
});
var data = {
max: max,
data: points,
};
heatmapInstance.setData(data);
// 将热力图添加到球体上(生成的热力图canvas元素类名为heatmap-canvas)
var canvas = document.getElementsByClassName("heatmap-canvas");
// console.log(canvas);
viewer.entities.add({
name: "heatmap",
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(
lonMin,
latMin,
lonMax,
latMax
),
material: new Cesium.ImageMaterialProperty({
image: canvas[0],
transparent: true,
}),
},
});
效果图如下:
集成Turf
Cesium本身更侧重于三维可视化,在空间分析方面会显得薄弱些,当然空间分析能力可以借助开源postGIS中的函数去实现,然后将结果通过Cesium去呈现。这里我们不对postGIS进行介绍,而是给大家介绍一个轻量级的用于空间分析的前端库,即Turf。Turf的定位是地理空间分析库,处理各种地图算法;特点是离线计算、模块化、快速。下面是一个简单的示例:计算两点之间的距离。
var point1 = turf.point([144.834823, -37.771257]);
var point2 = turf.point([145.14244, -37.830937]);
var midpoint = turf.midpoint(point1, point2);
而下面的截图是通过Turf、Cesium实现的点、线、面缓冲区分析结果,即借助了Turf的空间分析能力和Cesium的可视化能力。
部分核心代码如下:
// 初始化点缓冲
function initPointBuffer() {
let point = [106.422638966289, 29.5698367125623];
addPoint(point);
let pointF = turf.point(point);
let buffered = turf.buffer(pointF, 60, { units: "meters" });
let coordinates = buffered.geometry.coordinates;
let points = coordinates[0];
let degreesArray = pointsToDegreesArray(points);
addBufferPolyogn(Cesium.Cartesian3.fromDegreesArray(degreesArray));
}
// 添加点
function addPoint(point) {
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(point[0], point[1], 0),
point: {
pixelSize: 10,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
color: Cesium.Color.YELLOW,
outlineWidth: 3,
outlineColor: Cesium.Color.YELLOW.withAlpha(0.4),
},
});
}
// 添加缓冲面
function addBufferPolyogn(positions) {
viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(positions),
material: Cesium.Color.RED.withAlpha(0.6),
classificationType: Cesium.ClassificationType.BOTH,
},
});
}
如果你觉得比较麻烦的话,网上也有大神基于cesium、turf、shpjs、proj4js等这些库文件封装好了CesiumVectorTile,GitHub地址为https://github.com/engineerhe/CesiumVectorTile,支持小数据量的geojson、shape文件矢量动态切片,并且还能实现贴地效果。
获取上述全部源代码可访问本人GitHub地址:https://github.com/ls870061011。