vue+cesium+canvas实现自定义样式的聚合点集

cesium实现聚合点功能,cesium沙盒也有聚合样例。聚合时的图标是可以自定义样式的,使用CustomDataSource添加所有需要聚合显示的点数据;在clustering.clusterEvent事件中更改每次缩放时的聚合点的样式,自定义聚合图标的样式可以采用canvas画图去绘制自己想要的样式,使用cluster.billboard.image接收canvas绘制的图形更改样式即可,不使用canvas也可以找一些现有图标。代码基于vue2,ClusterLayer类可以直接使用。

聚合cesium沙盒实例:
vue+cesium+canvas实现自定义样式的聚合点集_第1张图片
自定义样式效果:
vue+cesium+canvas实现自定义样式的聚合点集_第2张图片

<template>
  <div class="mycontainer">
    <Map @Viewer="getViewer"></Map>
  </div>
</template>

<script>
import Map from '../map.vue'
import Position from '../../../utilsCesium/position/Position'
import ClusterLayer from '../../../utilsCesium/layer/ClusterLayer'
const Cesium = require('cesium/Cesium')
export default {
  components: { Map },
  data () {
    return {
      viewer: null
    }
  },
  mounted () {
    const layer = new ClusterLayer(this.viewer)
    const positions = this.generatePosition(1000)
    let id = 0
    positions.forEach(item => {
      id = id + 1
      layer._delegate.entities.add({
        position: Cesium.Cartesian3.fromDegrees(item._lng, item._lat),
        billboard: {
          id: id,
          show: true, // default
          image: 'data/imageData/camera.png',
          height: 32,
          // 宽度(以像素为单位)
          width: 32
        }
      })
    })
    this.viewer.flyTo(layer._delegate)
  },
  watch: {
  },
  methods: {
    getViewer (view) {
      this.viewer = view
    },
    generatePosition (num) {
      var list = []
      for (var i = 0; i < num; i++) {
        var lng = 120.38105869 + Math.random() * 0.5
        var lat = 31.10115627 + Math.random() * 0.5
        list.push(new Position(lng, lat))
      }
      return list
    }

  }
}

聚合类ClusterLayer代码:

let that
const Cesium = require('cesium/Cesium')
const DEF_OPT = {
  size: 18,
  pixelRange: 40,
  gradient: {
    0.0001: Cesium.Color.DEEPSKYBLUE,
    0.001: Cesium.Color.GREEN,
    0.01: Cesium.Color.ORANGE,
    0.1: Cesium.Color.RED
  },
  fontSize: 12,
  fontColor: Cesium.Color.BLACK,
  style: 'circle'
}

class ClusterLayer {
  constructor (viewer) {
    this._delegate = new Cesium.CustomDataSource()
    this._options = {
      ...DEF_OPT
    }
    this._delegate.clustering.enabled = true
    this._delegate.clustering.clusterEvent.addEventListener(
      this._clusterEventHandler
    )
    this._delegate.clustering.pixelRange = this._options.pixelRange
    that = this
    this._viewer = viewer
    if (this._delegate instanceof Cesium.PrimitiveCollection) {
      this._viewer.scene.primitives.add(this._delegate)
    } else {
      this._viewer.dataSources.add(this._delegate)
    }
  }

  set enableCluster (enableCluster) {
    this._delegate.clustering.enabled = enableCluster
    return this
  }

  /**
   *
   * @param color
   * @param numLength
   * @returns {*}
   * @private
   */
  _drawCircle (color, numLength) {
    const size = this._options.size * (numLength + 1)
    const canvas = document.createElement('canvas')
    canvas.width = size
    canvas.height = size
    const context2D = canvas.getContext('2d')
    context2D.save()
    context2D.scale(size / 24, size / 24) // Added to auto-generated code to scale up to desired size.
    context2D.fillStyle = color.withAlpha(0.2).toCssColorString() // Modified from auto-generated code.
    context2D.beginPath()
    context2D.arc(12, 12, 9, 0, 2 * Math.PI)
    context2D.closePath()
    context2D.fill()
    context2D.beginPath()
    context2D.arc(12, 12, 6, 0, 2 * Math.PI)
    context2D.fillStyle = color.toCssColorString()
    context2D.fill()
    context2D.closePath()
    context2D.restore()
    return canvas.toDataURL()
  }

  /**
   *
   * @param color
   * @param numLength
   * @returns {*}
   * @private
   */
  _drawClustering (color, numLength) {
    const size = this._options.size * (numLength + 1)
    let startAngle = -Math.PI / 12
    const angle = Math.PI / 2
    const intervalAngle = Math.PI / 6
    const canvas = document.createElement('canvas')
    canvas.width = size
    canvas.height = size
    const context2D = canvas.getContext('2d')
    context2D.save()
    context2D.scale(size / 24, size / 24) // Added to auto-generated code to scale up to desired size.
    context2D.beginPath()
    context2D.arc(12, 12, 6, 0, 2 * Math.PI)
    context2D.fillStyle = color.toCssColorString()
    context2D.fill()
    context2D.closePath()
    context2D.lineWidth = 2
    for (let i = 0; i < 3; i++) {
      context2D.beginPath()
      context2D.arc(12, 12, 8, startAngle, startAngle + angle, false)
      context2D.strokeStyle = color.withAlpha(0.4).toCssColorString()
      context2D.stroke()
      context2D.arc(12, 12, 11, startAngle, startAngle + angle, false)
      context2D.strokeStyle = color.withAlpha(0.2).toCssColorString()
      context2D.stroke()
      context2D.closePath()
      startAngle = startAngle + angle + intervalAngle
    }
    context2D.restore()
    return canvas.toDataURL()
  }

  /**
   *
   * @param {*} clusteredEntities
   * @param {*} cluster
   */

  _clusterEventHandler (clusteredEntities, cluster) {
    if (!that._delegate.clustering.enabled) {
      return
    }
    cluster.billboard.show = true
    cluster.label.font = `bold ${that._options.fontSize}px sans-serif`
    cluster.label.fillColor = that._options.fontColor
    cluster.label.disableDepthTestDistance = Number.POSITIVE_INFINITY
    if (that._delegate.entities.values.length) {
      const allCount = that._delegate.entities.values.length || 0
      for (const key in that._options.gradient) {
        if (clusteredEntities.length >= allCount * key) {
          const numLength = String(clusteredEntities.length).length
          if (that._options.style === 'circle') {
            cluster.billboard.image = that._drawCircle(
              that._options.gradient[key],
              numLength
            )
          } else {
            cluster.billboard.image = that._drawClustering(
              that._options.gradient[key],
              numLength
            )
          }
          cluster.label.show = true
          if (numLength === 1) {
            cluster.label.pixelOffset = new Cesium.Cartesian2(-2, 3)
          } else {
            cluster.label.pixelOffset = new Cesium.Cartesian2(
              -5 * (numLength - 1),
              5
            )
          }
        } else if (clusteredEntities.length <= 1) {
          cluster.label.show = false
        }
      }
    }
  }

  clear () {
    this._delegate.entities.removeAll()
    return this
  }
}
export default ClusterLayer

你可能感兴趣的:(gis,js)