类名 leaflet/document/theme/GeoFeatureThemeLayer.js
import { Zondy, FeatureSet, Extent } from '@mapgis/webclient-common'
import * as L from '@mapgis/leaflet'
// eslint-disable-next-line import/no-extraneous-dependencies
import { ShapeFactory, ThemeVector } from '@mapgis/webclient-graphic-render'
import ThemeLayer from './ThemeLayer'

/**
 * @class Zondy.ThemeLayer.GeoFeatureThemeLayer
 * @classdesc  地理几何专题要素型专题图层基类。此类型专题图的专题要素形状就是由 feature.geometry 决定。此类不建议直接实例化调用。
 * @extends Zondy.ThemeLayer.ThemeLayer
 * @param {string} name - 专题图名。
 * @param {Object} options - 需要设置的参数对象。
 * @param {string} [options.id] - 专题图层 ID。默认使用 CommonUtil.createUniqueID("themeLayer_") 创建专题图层 ID。
 * @param {number} [options.opacity=1] - 图层透明度。
 * @param {number} [options.nodesClipPixel=2] - 节点抽稀像素距离。
 * @param {boolean} [options.isHoverAble=false] -  图形是否在 hover 时高亮。
 * @param {boolean} [options.isMultiHover=false] - 是否多图形同时高亮,用于高亮同一个数据对应的所有图形(如:多面)。
 * @param {boolean} [options.isClickAble=true] - 图形是否可点击。
 * @param {boolean} [options.isAllowFeatureStyle=false] -  是否允许 feature 样式(style) 中的有效属性应用到专题图层。禁止对专题要素使用数据(feature)的 style。此属性可强制将数据 feature 的 style 中有效属性应用到专题要素上,且拥有比图层 style 和 styleGroups 更高的优先级,使专题要素的样式脱离专题图层的控制。可以通过此方式实现对特殊数据(feature) 对应专题要素赋予独立 style。
 * @fires Zondy.ThemeLayer.GeoFeatureThemeLayer#beforefeaturesadded
 */
const GeoFeatureThemeLayer = ThemeLayer.extend({
  options: {
    // {Number} 节点抽稀像素距离,默认值 2。
    nodesClipPixel: 2,

    // {Boolean} 图形是否在 hover 时高亮 ,默认值:false。
    isHoverAble: false,

    // {Boolean} 是否多图形同时高亮,用于高亮同一个数据对应的所有图形(如:多面),默认值:false。
    isMultiHover: false,

    // {Boolean} 图形是否可点击,默认 true
    isClickAble: true,
    // 是否允许 feature 样式(style) 中的有效属性应用到专题图层。
    // 默认值为: false,禁止对专题要素使用数据(feature)的 style。
    // 此属性可强制将数据 feature 的 style 中有效属性应用到专题要素上,且拥有比图层 style 和 styleGroups 更高的优先级,使专题要素的样式脱离专题图层的控制。可以通过此方式实现对特殊数据(feature) 对应专题要素赋予独立 style。
    isAllowFeatureStyle: false
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.initialize
   * @description 初始化。
   * @param {string} name - 专题图名。
   * @param {Object} options - 需要设置的参数对象。
   */
  initialize(name, options) {
    ThemeLayer.prototype.initialize.call(this, name, options)
    L.Util.setOptions(this, options)
    const me = this
    me.cache = {}
    me.cacheFields = []
    me.style = {}
    me.highlightStyle = {}
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.addFeatures
   * @description 向专题图图层中添加数据。
   * @param {Object} features - 待填加的要素。
   */
  addFeatures(features) {
    const me = this

    /**
     * @event Zondy.ThemeLayer.GeoFeatureThemeLayer#beforefeaturesadded
     * @description 向专题图图层中添加数据之前触发。
     * @property {Object} features - 事件对象。
     */
    me.fire('beforefeaturesadded', { features })
    if (features instanceof FeatureSet) {
      const attrs = null
      const attstruct = features.AttStruct
      const feaArr = features.SFEleArray
      if (feaArr !== null && feaArr.length > 0) {
        for (let j = 0; j < feaArr.length; j++) {
          const feature = feaArr[j]
          if (feature.AttValue !== null && feature.AttValue.length > 0) {
            const attrs = {}
            for (let i = 0; i < feature.AttValue.length; i++) {
              attrs[attstruct.FldName[i]] = feature.AttValue[i]
            }
            attrs['FID'] = feature.FID
          }
          feature.attributes = attrs
          me.features.push(feature)
        }
      }
    }
    if (!me.isCustomSetMaxCacheCount) {
      me.maxCacheCount = me.features.length * 5
    }

    if (!me.renderer) {
      return
    }
    // 绘制专题要素
    if (me._map) {
      me.redrawThematicFeatures(me._map.getBounds())
    } else {
      me.redrawThematicFeatures()
    }
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.removeFeatures
   * @description 从专题图中删除 feature。这个函数删除所有传递进来的矢量要素。参数中的 features 数组中的每一项,必须是已经添加到当前图层中的 feature。
   * @param {Object} features - 要删除的要素。
   */
  removeFeatures(features) {
    // eslint-disable-line no-unused-vars
    this.clearCache()
    ThemeLayer.prototype.removeFeatures.call(this, arguments)
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.removeAllFeatures
   * @description 清除当前图层所有的矢量要素。
   */
  removeAllFeatures() {
    this.clearCache()
    ThemeLayer.prototype.removeAllFeatures.call(this, arguments)
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.redrawThematicFeatures
   * @description 重绘所有专题要素。
   *              此方法包含绘制专题要素的所有步骤,包含用户数据到专题要素的转换,抽稀,缓存等步骤。
   *              地图漫游时调用此方法进行图层刷新。
   * @param {L.bounds} bounds - 重绘的范围。
   */
  redrawThematicFeatures(bounds) {
    const me = this
    // 获取高亮专题要素对应的用户 id
    const hoverone = me.renderer.getHoverOne()
    let hoverFid = null
    if (hoverone && hoverone.refDataID) {
      hoverFid = hoverone.refDataID
    }
    if (bounds && bounds instanceof L.LatLngBounds) {
      const crs = this._map.options.crs
      bounds = L.bounds(
        crs.project(bounds.getSouthWest()),
        crs.project(bounds.getNorthEast())
      )
      bounds = new Extent(
        bounds.min.x,
        bounds.min.y,
        bounds.max.x,
        bounds.max.y
      )
    }
    // 清除当前所有可视元素
    me.renderer.clearAll()

    const features = me.features
    const cache = me.cache
    const cacheFields = me.cacheFields
    const cmZoom = me._map.getZoom()

    const maxCC = me.maxCacheCount

    for (let i = 0, len = features.length; i < len; i++) {
      const feature = features[i]
      const feaBounds = feature.bound

      // 剔除当前视图(地理)范围以外的数据
      if (bounds && !bounds.intersectsBounds(feaBounds)) {
        continue
      }

      // 缓存字段
      const fields = `${feature.FID}_zoom_${cmZoom.toString()}`
      if (cache[fields]) {
        cache[fields].updateAndAddShapes()
        continue
      }

      const thematicFeature = me.createThematicFeature(features[i])
      // 检查 thematicFeature 是否有可视化图形
      if (thematicFeature.getShapesCount() < 1) {
        continue
      }
      // 加入缓存
      cache[fields] = thematicFeature
      cacheFields.push(fields)
      // 缓存数量限制
      if (cacheFields.length > maxCC) {
        const fieldsTemp = cacheFields[0]
        cacheFields.splice(0, 1)
        delete cache[fieldsTemp]
      }
    }

    me.renderer.render()

    // 地图漫游后,重新高亮图形
    if (hoverFid && me.options.isHoverAble && me.options.isMultiHover) {
      const hShapes = this.getShapesByFeatureID(hoverFid)
      this.renderer.updateHoverShapes(hShapes)
    }
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.createThematicFeature
   * @description 创建专题要素。
   * @param {Object} feature - 要创建的要素。
   */
  createThematicFeature(feature) {
    const me = this
    const style = me.getStyleByData(feature)
    // 创建专题要素时的可选参数
    const options = {}
    options.nodesClipPixel = me.options.nodesClipPixel
    options.isHoverAble = me.options.isHoverAble
    options.isMultiHover = me.options.isMultiHover
    options.isClickAble = me.options.isClickAble
    options.highlightStyle = ShapeFactory.transformStyle(me.highlightStyle)

    // 将数据转为专题要素(Vector)
    const thematicFeature = new ThemeVector(
      feature,
      me,
      ShapeFactory.transformStyle(style),
      options
    )

    // 直接添加图形到渲染器
    for (let m = 0; m < thematicFeature.shapes.length; m++) {
      me.renderer.addShape(thematicFeature.shapes[m])
    }

    return thematicFeature
  },
  getStyleByData(feat) {
    // 子类必须实现此方法
  },
  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.redraw
   * @description 重绘该图层。
   */
  redraw() {
    this.clearCache()
    return ThemeLayer.prototype.redraw.apply(this, arguments)
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.clearCache
   * @description 清除缓存数据。
   */
  clearCache() {
    this.cache = {}
    this.cacheFields = []
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.clear
   * @description 清除的内容包括数据(features) 、专题要素、缓存。
   */
  clear() {
    const me = this
    me.renderer.clearAll()
    me.renderer.refresh()
    me.removeAllFeatures()
    me.clearCache()
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.getCacheCount
   * @description 获取当前缓存数量。
   * @returns {number} 返回当前缓存数量。
   */
  getCacheCount() {
    return this.cacheFields.length
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.setMaxCacheCount
   * @description 设置最大缓存数量。
   * @param {number} cacheCount - 最大缓存量。
   */
  setMaxCacheCount(cacheCount) {
    if (isNaN(cacheCount)) {
      return
    }
    this.maxCacheCount = cacheCount
    this.isCustomSetMaxCacheCount = true
  },

  /**
   * @function Zondy.ThemeLayer.GeoFeatureThemeLayer.prototype.getShapesByFeatureID
   * @description 通过 FeatureID 获取 feature 关联的所有图形。如果不传入此参数,函数将返回所有图形。
   * @param {number} featureID - 要素 ID。
   */
  getShapesByFeatureID(featureID) {
    const me = this
    const list = []
    const shapeList = me.renderer.getAllShapes()

    if (!featureID) {
      return shapeList
    }

    for (let i = 0, len = shapeList.length; i < len; i++) {
      const si = shapeList[i]
      if (si.refDataID && featureID === si.refDataID) {
        list.push(si)
      }
    }
    return list
  }
})

Zondy.ThemeLayer.GeoFeatureThemeLayer = GeoFeatureThemeLayer
export default GeoFeatureThemeLayer
构造函数
成员变量
方法
事件