类名 common/base/feature/Feature.js
import Zondy from '../Zondy'
import Evented from '../Evented'
import { getGUID, defaultValue, Log, defined } from '../../util'
import { Geometry } from '../geometry'
import {
  SimpleFillSymbol,
  SimpleLineSymbol,
  SimpleMarkerSymbol,
  Symbol
} from '../symbol'
import { GeometryType, SymbolType } from '../enum'
import ElevationInfo from '../ElevationInfo'

/**
 * 要素对象,示例如下:<a id='add-Feature'>[初始化要素对象]</a>
 * <br><br>[ES5引入方式]:<br/>
 * Zondy.Feature() <br/>
 * [ES6引入方式]:<br/>
 * import { Feature } from "@mapgis/webclient-common" <br/>
 * <br/>
 * @class Feature
 * @moduleEX FeatureModule
 * @param {Object} options 构造参数
 * @param {String} [options.id] 要素的id,不给则给一个随机的默认id
 * @param {Object} [options.attributes = {}] 要素的属性
 * @param {Geometry} [options.geometry] 要素的几何对象,支持如下:<br/>
 * [圆]{@link Circle}、[矩形范围]{@link Extent}、[线]{@link LineString}、
 * [多线]{@link MultiLineString}、[点]{@link Point}、[多点]{@link MultiPoint}、[区]{@link Polygon}、
 * [多区]{@link MultiPolygon}
 * @param {Symbol} [options.symbol = {}] 要素的样式,支持如下:<br/>
 * [图片Marker符号]{@link PictureMarkerSymbol}、[简单Marker符号]{@link SimpleMarkerSymbol}、
 * [简单填充符号]{@link SimpleFillSymbol}、[简单线符号]{@link SimpleLineSymbol}、[文本符号]{@link TextSymbol}
 * @param {Boolean} [options.visible = true] 要素是否可见
 * @param {ElevationInfo} [options.elevationInfo] 高程信息
 *
 * @summary <h5>支持如下方法:</h5>
 * <a href='#fromGeoJSON'>[1、从geoJSON对象中导入数据]</a><br/>
 * <a href='#toGeoJSON'>[2、导出为GeoJSON数据]</a><br/>
 * <a href='#fromJSON'>[3、通过传入的json构造并返回一个新的几何对象]</a><br/>
 * <a href='#toJSON'>[4、导出一个JSON对像]</a><br/>
 * <a href='#clone'>[5、克隆并返回新要素]</a><br/>
 * <a href='#toIGSFeature'>[6、导出为igs服务接口的要素对象]</a><br/>
 * <a href='#toOldIGSFeature'>[7、出为igs1.0服务接口的要素对象]</a><br/>
 * <a href='#toGraphicInfo'>[8、导出为igs1.0的要素的图形信息]</a><br/>
 * <a href='#toAttValue'>[9、导出为igs1.0的要素的属性值]</a><br/>
 * <a href='#toFType'>[10、导出为igs1.0的要素的几何类型]</a><br/>
 *
 * @example <caption><h7 id='add-Feature'>创建几何对象</h7></caption>
 * // ES5引入方式
 * const { Feature, Color } = Zondy
 * const { LineString } = Zondy.Geometry
 * const { SimpleLineSymbol } = Zondy.Symbol
 * // ES6引入方式
 * import { Feature, Color, LineString, SimpleLineSymbol } from "@mapgis/webclient-common"
 * let feature = new Feature({
 *   //不填则创建一个随机的guid
 *   id: "你的id",
 *   //设置属性
 *   attributes: {},
 *   //构建几何
 *   geometry: new LineString({
 *     coordinates: [[112.0, 30.0], [113.0, 30.0], [113.0, 31.0]]
 *   }),
 *   //设置样式
 *   symbol: new SimpleLineSymbol({
 *     //设置颜色
 *     color: new Color(255, 0, 0, 1),
 *     //设置线宽
 *     width: 2
 *   })
 * })
 */
class Feature extends Evented {
  constructor(options) {
    super(options)
    options = defaultValue(options, {})
    /**
     * 要素id
     * default 随机id
     * @member {String} Feature.prototype.id
     */
    this.id = defaultValue(options.id, getGUID())
    /**
     * 要素的属性
     * default {}
     * @member {Object} Feature.prototype.attributes
     */
    this.attributes = defaultValue(options.attributes, {})
    /**
     * 要素的几何对象
     * @member {Geometry} Feature.prototype.geometry
     */
    this.geometry = this._decorate(
      'geometry',
      options.geometry,
      Geometry,
      Geometry.fromJSON
    )
    if (!this.geometry) {
      Log.error('要素几何信息缺失')
    }
    /**
     * 要素的样式
     * @member {Symbol} Feature.prototype.symbol
     */
    this.symbol = this._decorate(
      'symbol',
      options.symbol,
      Symbol,
      this._getSymbol.bind(this)
    )
    /**
     * 要素是否可见
     * default = true
     * @member {Boolean} Feature.prototype.visible
     */
    this.visible = defaultValue(options.visible, true)
    /**
     * 对象类型
     * @readonly
     * @member {String} Feature.prototype.type
     */
    this.type = 'Feature'
    /**
     * 高程信息
     * @member {ElevationInfo} Feature.prototype.elevationInfo
     */
    this.elevationInfo = defaultValue(
      options.elevationInfo,
      new ElevationInfo()
    )
    /**
     * 额外属性,其中的arc3表示三点弧的信息
     * @member {additional} Feature.prototype.additional
     */
    this.additional = defaultValue(options.additional, {})
  }

  /**
   * @description: 根据几何类型支持程度重设符号
   * @param {*} symbol
   * @return symbol
   */
  _getSymbol(symbol) {
    const symbolType = symbol ? symbol.type : 'undefine'
    const geometryType = this.geometry.type
    let instance = symbol instanceof Symbol ? symbol : Symbol.fromJSON(symbol)
    switch (geometryType) {
      case GeometryType.multiPoint:
      case GeometryType.point: {
        const limits = [
          SymbolType.simpleMarker,
          SymbolType.text,
          SymbolType.mapgisText,
          SymbolType.pictureMarker,
          SymbolType.point3D,
          SymbolType.label3D
        ]
        if (!defined(symbol)) {
          instance = new SimpleMarkerSymbol()
        }
        if (!limits.some((v) => v === symbolType)) {
          Log.info('图元几何和符号不匹配')
          const json = instance.toJSON()
          instance = new SimpleMarkerSymbol({
            color: json.color
          })
        }
        break
      }
      case GeometryType.multiLineString:
      case GeometryType.lineString: {
        const limits = [SymbolType.simpleLine, SymbolType.line3D]
        if (!defined(symbol)) {
          instance = new SimpleLineSymbol()
        }
        if (!limits.some((v) => v === symbolType)) {
          Log.info('图元几何和符号不匹配')
          const json = instance.toJSON()
          instance = new SimpleLineSymbol({
            color: json.color
          })
        }

        break
      }
      case GeometryType.polygon:
      case GeometryType.extent:
      case GeometryType.circle:
      case GeometryType.multiPolygon: {
        const limits = [
          SymbolType.simpleFill,
          SymbolType.simpleMarker,
          SymbolType.text,
          SymbolType.mapgisText,
          SymbolType.pictureMarker,
          SymbolType.pictureFill,
          SymbolType.polygon3D
        ]
        if (!defined(symbol)) {
          instance = new SimpleFillSymbol()
        }
        if (!limits.some((v) => v === symbolType)) {
          Log.info('图元几何和符号不匹配')
          const json = instance.toJSON()
          instance = new SimpleFillSymbol({
            color: json.color
          })
        }
        break
      }
      default: {
        break
      }
    }
    return instance
  }

  /**
   * 克隆并返回新要素<a id='clone'></a>
   * @return {Feature} 克隆后的新要素
   */
  clone() {
    return new Feature(this.toJSON())
  }

  /**
   * 导出一个JSON对像<a id='toJSON'></a>
   * @return {Object} JSON对像
   */
  toJSON() {
    const json = {}
    json.id = this.id
    json.attributes = JSON.parse(JSON.stringify(this.attributes))
    json.geometry = this.geometry.toJSON()
    json.symbol = this.symbol.toJSON()
    json.visible = this.visible
    json.type = this.type
    json.elevationInfo = this.elevationInfo
    return json
  }

  /**
   * 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
   * @param {Object} json JSON对象
   * @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>\
   * // ES5引入方式
   * const { LineString } = Zondy.Geometry
   * const { Feature } = Zondy
   * // ES6引入方式
   * import { LineString, Feature } from "@mapgis/webclient-common"
   * const json = {
   *   //设置属性
   *   attributes: {},
   *   //构建几何
   *   geometry: new LineString({
   *     coordinates: [[112.0, 30.0], [113.0, 30.0], [113.0, 31.0]]
   *   })
   * }
   * const feature = new Feature.fromJSON(json)
   */
  static fromJSON(json) {
    json = defaultValue(json, {})
    return new Feature(json)
  }

  /**
   * 从geoJSON对象中导入数据<a id='fromGeoJSON'></a>
   * @param geoJSON geoJSON数据
   * @example <caption><h7 id='fromJSON'>从geoJSON对象中导入数据</h7></caption>
   * // ES5引入方式
   * const { Feature } = Zondy
   * // ES6引入方式
   * import { Feature } from "@mapgis/webclient-common"
   * //数据格式参考https://geojson.org/
   * const feature = new Feature();
   * feature.fromGeoJSON({
   *   type: "Feature",
   *   geometry: {
   *     type: "LineString",
   *     coordinates: [
   *       [114.329481, 30.711953],
   *       [114.342372, 30.684553],
   *       [114.341474, 30.674527],
   *       [114.338273, 30.665863],
   *       [114.334533, 30.655893],
   *       [114.330017, 30.643386],
   *       [114.322936, 30.631171],
   *       [114.318749, 30.625032],
   *       [114.313923, 30.617818],
   *       [114.308156, 30.608404],
   *       [114.301348, 30.598718],
   *       [114.295038, 30.592581],
   *       [114.285992, 30.585234],
   *       [114.278415, 30.580865],
   *       [114.270119, 30.577433],
   *       [114.261901, 30.573909],
   *       [114.250444, 30.571547],
   *       [114.240741, 30.574025],
   *       [114.224975, 30.580306],
   *       [114.218822, 30.585491],
   *       [114.211532, 30.589347],
   *       [114.20474, 30.593382],
   *       [114.196667, 30.597536],
   *       [114.183062, 30.604521],
   *       [114.169464, 30.609907],
   *       [114.163868, 30.615064],
   *       [114.155941, 30.61846],
   *       [114.138907, 30.617699],
   *       [114.128567, 30.624968],
   *       [114.123644, 30.631684],
   *       [114.120804, 30.649056],
   *       [114.120828, 30.659055],
   *     ],
   *   },
   *   properties: {
   *     ln: "1号线",
   *     su: "1",
   *     kn: "轨道交通1号线",
   *     ls: "420100034364",
   *     cl: "3080B7",
   *     la: "",
   *     x: 1,
   *     li: "420100034364|420100034365",
   *     color: "#3080B7",
   *   },
   * });
   */
  fromGeoJSON(geoJSON) {
    geoJSON = defaultValue(geoJSON, {})
    const that = this
    // 从geometry中获取几何
    const geometry = defaultValue(geoJSON.geometry, {})
    that.geometry = Geometry.fromGeoJSON(geometry)
    // 从properties中获取属性
    const properties = defaultValue(geoJSON.properties, {})
    Object.keys(properties).forEach(function (key) {
      if (properties.hasOwnProperty(key)) {
        that.attributes[key] = properties[key]
      }
    })
  }

  /**
   * 导出为GeoJSON数据<a id='toGeoJSON'></a>
   * @return geoJSON geoJSON数据
   * @example <caption><h7 id='toGeoJSON'>导出为GeoJSON数据</h7></caption>
   * //导出为GeoJSON数据
   * let geojson = feature.toGeoJSON();
   */
  toGeoJSON() {
    return {
      type: 'Feature',
      geometry: this.geometry.toGeoJSON(),
      properties: JSON.parse(JSON.stringify(this.attributes)),
      style: this.symbol.toJSON()
    }
  }

  /**
   * 导出为igs服务接口的要素对象<a id='toIGSFeature'></a>
   * @return igs传输要素
   */
  toIGSFeature() {
    const geometry = this.geometry.toJSON()
    return {
      type: 'Feature',
      geometry: {
        type: geometry.type,
        coordinates: geometry.coordinates
      },
      attributes: JSON.parse(JSON.stringify(this.attributes)),
      styleInfo: null
    }
  }

  /**
   * 出为igs1.0服务接口的要素对象<a id='toOldIGSFeature'></a>
   * @return igs1.0的要素
   */
  toOldIGSFeature() {
    return {
      fGeom: this.geometry.toOldIGSGeometry(),
      GraphicInfo: this.toGraphicInfo(),
      AttValue: this.toAttValue(),
      FID: this.id,
      bound: null,
      ftype: this.toFType()
    }
  }

  /**
   * 导出为igs1.0的要素的图形信息<a id='toGraphicInfo'></a>
   * @return {Object} igs1.0的要素的图形信息
   */
  toGraphicInfo() {
    let graphicInfo

    switch (this.geometry.type) {
      case 'Point':
      case 'MultiPoint':
        graphicInfo = {
          InfoType: 1,
          PntInfo: this.symbol
        }
        break
      case 'LineString':
      case 'MultiLineString':
        graphicInfo = {
          InfoType: 2,
          LinInfo: this.symbol
        }
        break
      case 'Polygon':
      case 'MultiPolygon':
      default:
        graphicInfo = {
          InfoType: 3,
          RegInfo: this.symbol
        }
        break
    }

    return graphicInfo
  }

  /**
   * 导出为igs1.0的要素的属性值<a id='toAttValue'></a>
   * @return {Array} igs1.0的要素的属性值
   */
  toAttValue() {
    const attValue = []
    const self = this

    Object.keys(this.attributes).forEach((key) => {
      if (self.attributes.hasOwnProperty(key)) {
        attValue.push(self.attributes[key])
      }
    })

    return attValue
  }

  /**
   * 导出为igs1.0的要素的几何类型<a id='toFType'></a>
   * @return {Number} igs1.0的要素的几何类型
   */
  toFType() {
    let ftype

    switch (this.geometry.type) {
      case 'Point':
      case 'MultiPoint':
        ftype = 1
        break
      case 'LineString':
      case 'MultiLineString':
        ftype = 2
        break
      case 'Polygon':
      case 'MultiPolygon':
      default:
        ftype = 3
        break
    }

    return ftype
  }
}

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