    function mapboxCustomCRS(mapboxgl, proj4) {
      class MapboxglCustomProjection extends mapboxgl.Projection {
        constructor(code, options) {
          super()
          const opts = options || {}
          const def = opts.def
          if (!def) {
            throw new Error('自定义参考系必须指定参数系信息def')
          }
          this._def = def
          // 验证proj4库是否存在
          if (!proj4) {
            throw new Error('proj4对象不存在，自定义投影必须引入proj4对象')
          }

          const isP4 = this._isProj4Obj(code)
          this._proj = isP4 ? code : this._projFromCodeDef(code, def)
        }

        /**
         * @description: 正投
         * @param {*} lnglat
         * @return {*}
         */
        project(lnglat) {
          let lng
          let lat
          if (Array.isArray(lnglat)) {
            lng = lnglat[0]
            lat = lnglat[1]
          } else {
            lng = lnglat.lng
            lat = lnglat.lat
          }
          return this._proj.forward([lng, lat])
        }

        /**
         * @description: 反投
         * @param {*} point
         * @return {*}
         */
        unproject(point) {
          let x
          let y
          if (Array.isArray(point)) {
            x = point[0]
            y = point[1]
          } else {
            x = point.x
            y = point.y
          }
          return this._proj.inverse([x, y])
        }

        /**
         * @description: 定义proj4
         * @param {*} code
         * @param {*} def
         * @return {*}
         */
        _projFromCodeDef(code, def) {
          if (def) {
            proj4.defs(code, def)
          } else if (proj4.defs[code] === undefined) {
            const urn = code.split(':')
            if (urn.length > 3) {
              code = `${urn[urn.length - 3]}:${urn[urn.length - 1]}`
            }
            if (proj4.defs[code] === undefined) {
              throw `No projection definition for code ${code}`
            }
          }
          return proj4(code)
        }

        // 判断是否为proj4对象
        _isProj4Obj(a) {
          return (
            typeof a.inverse !== 'undefined' && typeof a.forward !== 'undefined'
          )
        }
      }

      class MapboxglCustomCRS extends mapboxgl.CRS {
        _parseParams(args) {
          // proj4 type
          this._crsType = 'proj4'
          // epsg编号
          this.epsgCode = args[0]
          // def
          this.def = args[1]
          // 解析options
          const opts = args[2] || {}
          // 解析传入的参数
          this._parseOptions(opts)
        }

        /**
         * @description: 解析options
         * @param {*} opts
         * @return {*}
         */
        _parseOptions(opts) {
          super._parseOptions(opts)
          // 分辨率
          this._resolutions = opts.resolutions

          if (Array.isArray(this._resolutions)) {
            const resolutions = {}
            this._resolutions.forEach((v, i) => {
              resolutions[i] = v
            })
            this._resolutions = resolutions
          } else {
            this._resolutions = {}
          }

          if (!this._resolutions[0]) {
            throw new Error('自定义坐标系时，未设置分辨率数组')
          }

          if (!this.origin) {
            // 若原点不存在,设置bounds左上角为原点
            if (this.extent) {
              this.origin = [this.extent[0], this.extent[3]]
            } else {
              throw new Error('自定义坐标系时，未设置原点')
            }
          }
          // 解析第一张瓦片tileSize
          this.tileSize = opts.tileSize || 256
        }

        /**
         * @description: 获取投影系范围，如果投影系不满足长宽一致，会在这一步被处理成长宽一致
         * @return {*}
         */
        getExtent() {
          // 设置为正方形区域
          if (!this._rectifyExtent) {
            // 自定义坐标系时，重新设置范围
            const scale =
              this._resolutions[0 + this.getZoomOffset()] * this.tileSize
            const extent = [
              this.origin[0],
              this.origin[1] - scale,
              this.origin[0] + scale,
              this.origin[1]
            ]
            this._rectifyExtent = extent
          }
          return this._rectifyExtent
        }

        /**
         * @description: 设置投影对象
         * @return {*}
         */
        _setProjection() {
          this.projection = new MapboxglCustomProjection(this.getEpsgCode(), {
            origin: this.origin,
            def: this.def
          })
        }
      }

      if (!mapboxgl.Proj) {
        mapboxgl.Proj = {}
      }
      mapboxgl.Proj.CRS = MapboxglCustomCRS
      mapboxgl.Proj.Projection = MapboxglCustomProjection

      return MapboxglCustomCRS
    }
    export { mapboxCustomCRS }