【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(四)

12,336 阅读2分钟

前三篇中我们已经能够实现加载地球、加载地图、加载点线面的效果。基本知识也相应介绍过,接下来的文章主要偏重的可能是某个功能的具体实现或某种样式的具体实现。欢迎大家评论区进行讨论。

前言

国家现在大力推行网格化管理,各地也基于网格化管理诞生了很多系统,现如今智慧城市或数字城市中,必不可少的功能就是网格展示及相关功能。今天我们就网格相关的样式和操作来复习一下关于面polygon的点击操作。同样的,行政区划也可以利用这样的效果和操作进行下沉。

我们先来看一下效果,实现了面的渐变填充样式,鼠标悬浮效果、点击效果。

grid.gif

思路及实现

我们想要实现面的点击、悬浮效果以及样式的修改。需要用到的基本上就是Cesium的ScreenSpaceEventHandler来监听鼠标的操作,而样式修改可能会对填充图片或者material进行处理。好了,既然想到了如何实现我们就开始动手吧!

获取数据

网格实质上也是面,所以我们需要首先有网格的面数据,我们可以去 DataV.Geoatlas地图中获取面的geojson数据。这里我们采用北京市的行政区划数据,地址我这里贴出来,想寻找其他数据的小伙伴可以自行寻找。

https://geo.datav.aliyun.com/areas_v2/bound/110000_full.json

加载geoJSON格式数据

利用Cesium的GeoJsonDataSource来加载geoJSON数据,注意:它返回的是一个promise对象,所以接收时需要使用.then(cb)

var promise=Cesium.GeoJsonDataSource.load('https://geo.datav.aliyun.com/areas_v2/bound/110000_full.json')
promise.then((datasource) => {
    viewer.dataSources.add(datasource);
    var entities = datasource.entities.values;
    for (var i = 0; i < entities.length; i++){
      var entity = entities[i];
      entity.polygon.material = Cesium.Color.RED;
      entity.polygon.extrudedHeight = 100
    }
})

在这里我们看到datasource就是我们通过url获取到的数据集,加载完毕后我们需要通过循环数据集中的实体集来对每一个实体进行样式的修改,这里我们暂时设置了它的颜色为红色,拉伸高度为100。

image.png

可以看到我们的带有高度的面已经渲染出来了,接下来我们可以思考一下如何变成我们最开始的效果图那样半透明渐变的呢?

polygon样式修改

我们知道,entity是通过matrial材质进行样式的修改。透明度我们可以通过Cesium.Color自带的withAlpha进行修改,但我们想呈现出的效果是区域渐变加透明,我当时的第一想法是既然material可以加载图片,那我们能不能用一张区域渐变的图片对它进行填充呢?结论是可以的。我们只需要 entity.polygon.material = require('./images/color.jpg');就可以利用图片填充。

image.png

这时候你可能会说,这就好办了,把图片变成半透明的不就实现了吗。这有什么难的。对,但是我们思考一下,如果这时候客户说:不行,这个颜色不好看,给我多换几个我看看效果,你该怎么办?做好几张图片挨个替换吗,这未免也太麻烦了吧。所以我们需要一个能够指定颜色并快速生成图片的方式供我们使用。canvas这时候站出来了,利用canvas,我们可以使用代码来快生成指定样式的图片,这不比制图快多了。

canvas关于渐变、角度的知识在这就不介绍了,网上比比皆是,我们直接通过代码讲解。

getColorRamp(rampColor,centerColor) {
    var ramp = document.createElement("canvas");
    ramp.width = 50;
    ramp.height = 50;
    var ctx = ramp.getContext("2d");

    var grd = ctx.createRadialGradient(25, 25, 0, 25, 25, 50);
    grd.addColorStop(0, centerColor); // "rgba(255,255,255,0)"
    grd.addColorStop(1, rampColor);

    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 50, 50);

    // return ramp;

    return new Cesium.ImageMaterialProperty({
      image: ramp,
      transparent: true
    });
}

可以看到我们封装了一个函数,入参是渐变两端的颜色(当然如果你的需求中需要改变角度、方向等可以自定义参数),生成一个50*50的canvas画布,createRadialGradient创建一个渐变对象,规定渐变颜色和位置,绘制到画布上,最后返回一个Cesium的ImageMaterialProperty图片材质类,记得配置transparenttrue

这样我们就可以自定义颜色来生成半透明渐变效果的材质了,看效果!

image.png

边缘的黄线是面的outline,我们可以将其设置为null以展示更好效果。

鼠标悬浮及点击事件

我们想实现的效果为点击高亮和鼠标移入时面外围有动效线的效果,其实很简单,也就是我们点击这个面的时候获取到这个面,改变这个面的材质,利用这个面的外围坐标集生成一个polyline,添加动态线的材质。现在我们来看看代码吧。

handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((e) => {
  var pick = viewer.scene.pick(e.position);
  if (Cesium.defined(pick) && pick.id) {
    var feature = pick.id;
    viewer.entities.removeById("select_grid");
    viewer.entities.removeById(`line_${feature.id}`);
    let positions = feature.polygon.hierarchy.getValue(
        Cesium.JulianDate.now()
    ).positions;
    viewer.entities.add({
    id: "select_grid",
    polygon: {
      hierarchy: positions,
      material: this.getColorRamp(
        "rgba(0, 255, 255,1)",
        "rgba(255,0,0,0.3)"
      ),
      height: 499,
    },
    });
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

handler.setInputAction((movement) => {
    var pickFeature =
      viewer.scene.pick(movement.endPosition) &&
      viewer.scene.pick(movement.endPosition).id;
    if (Cesium.defined(pickFeature) && this.preLineId !== pickFeature.id) {
      this.preLineId &&viewer.entities.removeById(`line_${this.preLineId}`);
      this.preLineId = pickFeature.id;
      viewer.entities.add({
        id: "line_" + pickFeature.id,
        name: "line_" + pickFeature.name,
        polyline: {
          positions: pickFeature.polygon.hierarchy.getValue(
            Cesium.JulianDate.now()
          ).positions,
          width: 8,
          material: new Cesium.PolylineTrailMaterialProperty({
            // 尾迹线材质
            color: Cesium.Color.AQUA,
            trailLength: 0.9,
            period: 1,
          }),
        },
      });
    } else {
      this.preLineId && viewer.entities.removeById(`line_${this.preLineId}`);
      this.preLineId = null;
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

效果:

6.gif

其实总结一下就是获取到当前鼠标位置下的entity,根据面的外围坐标集生成一个新的面和新的线,添加到球体上。就是先我们的效果了。

附录

系列文章

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(一)

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(二)

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(三)