Cesium开发工具篇 | 05与第三方库的集成

集成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,
       }),
     },
   });

效果图如下:


2.png

集成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的可视化能力。


3.png

部分核心代码如下:

 // 初始化点缓冲
 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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容