var KTMapPluginLabelsLayer = (function (exports, three) {
  'use strict';

  var global$1 = (typeof global !== "undefined" ? global :
    typeof self !== "undefined" ? self :
    typeof window !== "undefined" ? window : {});

  /** Detect free variable `global` from Node.js. */
  var freeGlobal = typeof global$1 == 'object' && global$1 && global$1.Object === Object && global$1;

  var freeGlobal$1 = freeGlobal;

  /** Detect free variable `self`. */
  var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

  /** Used as a reference to the global object. */
  var root = freeGlobal$1 || freeSelf || Function('return this')();

  var root$1 = root;

  /** Built-in value references. */
  var Symbol = root$1.Symbol;

  var Symbol$1 = Symbol;

  /** Used for built-in method references. */
  var objectProto$1 = Object.prototype;

  /** Used to check objects for own properties. */
  var hasOwnProperty = objectProto$1.hasOwnProperty;

  /**
   * Used to resolve the
   * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
   * of values.
   */
  var nativeObjectToString$1 = objectProto$1.toString;

  /** Built-in value references. */
  var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;

  /**
   * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
   *
   * @private
   * @param {*} value The value to query.
   * @returns {string} Returns the raw `toStringTag`.
   */
  function getRawTag(value) {
    var isOwn = hasOwnProperty.call(value, symToStringTag$1),
        tag = value[symToStringTag$1];

    try {
      value[symToStringTag$1] = undefined;
      var unmasked = true;
    } catch (e) {}

    var result = nativeObjectToString$1.call(value);
    if (unmasked) {
      if (isOwn) {
        value[symToStringTag$1] = tag;
      } else {
        delete value[symToStringTag$1];
      }
    }
    return result;
  }

  /** Used for built-in method references. */
  var objectProto = Object.prototype;

  /**
   * Used to resolve the
   * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
   * of values.
   */
  var nativeObjectToString = objectProto.toString;

  /**
   * Converts `value` to a string using `Object.prototype.toString`.
   *
   * @private
   * @param {*} value The value to convert.
   * @returns {string} Returns the converted string.
   */
  function objectToString(value) {
    return nativeObjectToString.call(value);
  }

  /** `Object#toString` result references. */
  var nullTag = '[object Null]',
      undefinedTag = '[object Undefined]';

  /** Built-in value references. */
  var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined;

  /**
   * The base implementation of `getTag` without fallbacks for buggy environments.
   *
   * @private
   * @param {*} value The value to query.
   * @returns {string} Returns the `toStringTag`.
   */
  function baseGetTag(value) {
    if (value == null) {
      return value === undefined ? undefinedTag : nullTag;
    }
    return (symToStringTag && symToStringTag in Object(value))
      ? getRawTag(value)
      : objectToString(value);
  }

  /**
   * Checks if `value` is object-like. A value is object-like if it's not `null`
   * and has a `typeof` result of "object".
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
   * @example
   *
   * _.isObjectLike({});
   * // => true
   *
   * _.isObjectLike([1, 2, 3]);
   * // => true
   *
   * _.isObjectLike(_.noop);
   * // => false
   *
   * _.isObjectLike(null);
   * // => false
   */
  function isObjectLike(value) {
    return value != null && typeof value == 'object';
  }

  /** `Object#toString` result references. */
  var symbolTag = '[object Symbol]';

  /**
   * Checks if `value` is classified as a `Symbol` primitive or object.
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
   * @example
   *
   * _.isSymbol(Symbol.iterator);
   * // => true
   *
   * _.isSymbol('abc');
   * // => false
   */
  function isSymbol(value) {
    return typeof value == 'symbol' ||
      (isObjectLike(value) && baseGetTag(value) == symbolTag);
  }

  /** Used to match a single whitespace character. */
  var reWhitespace = /\s/;

  /**
   * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
   * character of `string`.
   *
   * @private
   * @param {string} string The string to inspect.
   * @returns {number} Returns the index of the last non-whitespace character.
   */
  function trimmedEndIndex(string) {
    var index = string.length;

    while (index-- && reWhitespace.test(string.charAt(index))) {}
    return index;
  }

  /** Used to match leading whitespace. */
  var reTrimStart = /^\s+/;

  /**
   * The base implementation of `_.trim`.
   *
   * @private
   * @param {string} string The string to trim.
   * @returns {string} Returns the trimmed string.
   */
  function baseTrim(string) {
    return string
      ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
      : string;
  }

  /**
   * Checks if `value` is the
   * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
   * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is an object, else `false`.
   * @example
   *
   * _.isObject({});
   * // => true
   *
   * _.isObject([1, 2, 3]);
   * // => true
   *
   * _.isObject(_.noop);
   * // => true
   *
   * _.isObject(null);
   * // => false
   */
  function isObject(value) {
    var type = typeof value;
    return value != null && (type == 'object' || type == 'function');
  }

  /** Used as references for various `Number` constants. */
  var NAN = 0 / 0;

  /** Used to detect bad signed hexadecimal string values. */
  var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

  /** Used to detect binary string values. */
  var reIsBinary = /^0b[01]+$/i;

  /** Used to detect octal string values. */
  var reIsOctal = /^0o[0-7]+$/i;

  /** Built-in method references without a dependency on `root`. */
  var freeParseInt = parseInt;

  /**
   * Converts `value` to a number.
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to process.
   * @returns {number} Returns the number.
   * @example
   *
   * _.toNumber(3.2);
   * // => 3.2
   *
   * _.toNumber(Number.MIN_VALUE);
   * // => 5e-324
   *
   * _.toNumber(Infinity);
   * // => Infinity
   *
   * _.toNumber('3.2');
   * // => 3.2
   */
  function toNumber(value) {
    if (typeof value == 'number') {
      return value;
    }
    if (isSymbol(value)) {
      return NAN;
    }
    if (isObject(value)) {
      var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
      value = isObject(other) ? (other + '') : other;
    }
    if (typeof value != 'string') {
      return value === 0 ? value : +value;
    }
    value = baseTrim(value);
    var isBinary = reIsBinary.test(value);
    return (isBinary || reIsOctal.test(value))
      ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
      : (reIsBadHex.test(value) ? NAN : +value);
  }

  /**
   * Gets the timestamp of the number of milliseconds that have elapsed since
   * the Unix epoch (1 January 1970 00:00:00 UTC).
   *
   * @static
   * @memberOf _
   * @since 2.4.0
   * @category Date
   * @returns {number} Returns the timestamp.
   * @example
   *
   * _.defer(function(stamp) {
   *   console.log(_.now() - stamp);
   * }, _.now());
   * // => Logs the number of milliseconds it took for the deferred invocation.
   */
  var now = function() {
    return root$1.Date.now();
  };

  var now$1 = now;

  /** Error message constants. */
  var FUNC_ERROR_TEXT$1 = 'Expected a function';

  /* Built-in method references for those with the same name as other `lodash` methods. */
  var nativeMax = Math.max,
      nativeMin = Math.min;

  /**
   * Creates a debounced function that delays invoking `func` until after `wait`
   * milliseconds have elapsed since the last time the debounced function was
   * invoked. The debounced function comes with a `cancel` method to cancel
   * delayed `func` invocations and a `flush` method to immediately invoke them.
   * Provide `options` to indicate whether `func` should be invoked on the
   * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
   * with the last arguments provided to the debounced function. Subsequent
   * calls to the debounced function return the result of the last `func`
   * invocation.
   *
   * **Note:** If `leading` and `trailing` options are `true`, `func` is
   * invoked on the trailing edge of the timeout only if the debounced function
   * is invoked more than once during the `wait` timeout.
   *
   * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
   * until to the next tick, similar to `setTimeout` with a timeout of `0`.
   *
   * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
   * for details over the differences between `_.debounce` and `_.throttle`.
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Function
   * @param {Function} func The function to debounce.
   * @param {number} [wait=0] The number of milliseconds to delay.
   * @param {Object} [options={}] The options object.
   * @param {boolean} [options.leading=false]
   *  Specify invoking on the leading edge of the timeout.
   * @param {number} [options.maxWait]
   *  The maximum time `func` is allowed to be delayed before it's invoked.
   * @param {boolean} [options.trailing=true]
   *  Specify invoking on the trailing edge of the timeout.
   * @returns {Function} Returns the new debounced function.
   * @example
   *
   * // Avoid costly calculations while the window size is in flux.
   * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
   *
   * // Invoke `sendMail` when clicked, debouncing subsequent calls.
   * jQuery(element).on('click', _.debounce(sendMail, 300, {
   *   'leading': true,
   *   'trailing': false
   * }));
   *
   * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
   * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
   * var source = new EventSource('/stream');
   * jQuery(source).on('message', debounced);
   *
   * // Cancel the trailing debounced invocation.
   * jQuery(window).on('popstate', debounced.cancel);
   */
  function debounce(func, wait, options) {
    var lastArgs,
        lastThis,
        maxWait,
        result,
        timerId,
        lastCallTime,
        lastInvokeTime = 0,
        leading = false,
        maxing = false,
        trailing = true;

    if (typeof func != 'function') {
      throw new TypeError(FUNC_ERROR_TEXT$1);
    }
    wait = toNumber(wait) || 0;
    if (isObject(options)) {
      leading = !!options.leading;
      maxing = 'maxWait' in options;
      maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
      trailing = 'trailing' in options ? !!options.trailing : trailing;
    }

    function invokeFunc(time) {
      var args = lastArgs,
          thisArg = lastThis;

      lastArgs = lastThis = undefined;
      lastInvokeTime = time;
      result = func.apply(thisArg, args);
      return result;
    }

    function leadingEdge(time) {
      // Reset any `maxWait` timer.
      lastInvokeTime = time;
      // Start the timer for the trailing edge.
      timerId = setTimeout(timerExpired, wait);
      // Invoke the leading edge.
      return leading ? invokeFunc(time) : result;
    }

    function remainingWait(time) {
      var timeSinceLastCall = time - lastCallTime,
          timeSinceLastInvoke = time - lastInvokeTime,
          timeWaiting = wait - timeSinceLastCall;

      return maxing
        ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
        : timeWaiting;
    }

    function shouldInvoke(time) {
      var timeSinceLastCall = time - lastCallTime,
          timeSinceLastInvoke = time - lastInvokeTime;

      // Either this is the first call, activity has stopped and we're at the
      // trailing edge, the system time has gone backwards and we're treating
      // it as the trailing edge, or we've hit the `maxWait` limit.
      return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
        (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
    }

    function timerExpired() {
      var time = now$1();
      if (shouldInvoke(time)) {
        return trailingEdge(time);
      }
      // Restart the timer.
      timerId = setTimeout(timerExpired, remainingWait(time));
    }

    function trailingEdge(time) {
      timerId = undefined;

      // Only invoke if we have `lastArgs` which means `func` has been
      // debounced at least once.
      if (trailing && lastArgs) {
        return invokeFunc(time);
      }
      lastArgs = lastThis = undefined;
      return result;
    }

    function cancel() {
      if (timerId !== undefined) {
        clearTimeout(timerId);
      }
      lastInvokeTime = 0;
      lastArgs = lastCallTime = lastThis = timerId = undefined;
    }

    function flush() {
      return timerId === undefined ? result : trailingEdge(now$1());
    }

    function debounced() {
      var time = now$1(),
          isInvoking = shouldInvoke(time);

      lastArgs = arguments;
      lastThis = this;
      lastCallTime = time;

      if (isInvoking) {
        if (timerId === undefined) {
          return leadingEdge(lastCallTime);
        }
        if (maxing) {
          // Handle invocations in a tight loop.
          clearTimeout(timerId);
          timerId = setTimeout(timerExpired, wait);
          return invokeFunc(lastCallTime);
        }
      }
      if (timerId === undefined) {
        timerId = setTimeout(timerExpired, wait);
      }
      return result;
    }
    debounced.cancel = cancel;
    debounced.flush = flush;
    return debounced;
  }

  /** Error message constants. */
  var FUNC_ERROR_TEXT = 'Expected a function';

  /**
   * Creates a throttled function that only invokes `func` at most once per
   * every `wait` milliseconds. The throttled function comes with a `cancel`
   * method to cancel delayed `func` invocations and a `flush` method to
   * immediately invoke them. Provide `options` to indicate whether `func`
   * should be invoked on the leading and/or trailing edge of the `wait`
   * timeout. The `func` is invoked with the last arguments provided to the
   * throttled function. Subsequent calls to the throttled function return the
   * result of the last `func` invocation.
   *
   * **Note:** If `leading` and `trailing` options are `true`, `func` is
   * invoked on the trailing edge of the timeout only if the throttled function
   * is invoked more than once during the `wait` timeout.
   *
   * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
   * until to the next tick, similar to `setTimeout` with a timeout of `0`.
   *
   * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
   * for details over the differences between `_.throttle` and `_.debounce`.
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Function
   * @param {Function} func The function to throttle.
   * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
   * @param {Object} [options={}] The options object.
   * @param {boolean} [options.leading=true]
   *  Specify invoking on the leading edge of the timeout.
   * @param {boolean} [options.trailing=true]
   *  Specify invoking on the trailing edge of the timeout.
   * @returns {Function} Returns the new throttled function.
   * @example
   *
   * // Avoid excessively updating the position while scrolling.
   * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
   *
   * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
   * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
   * jQuery(element).on('click', throttled);
   *
   * // Cancel the trailing throttled invocation.
   * jQuery(window).on('popstate', throttled.cancel);
   */
  function throttle(func, wait, options) {
    var leading = true,
        trailing = true;

    if (typeof func != 'function') {
      throw new TypeError(FUNC_ERROR_TEXT);
    }
    if (isObject(options)) {
      leading = 'leading' in options ? !!options.leading : leading;
      trailing = 'trailing' in options ? !!options.trailing : trailing;
    }
    return debounce(func, wait, {
      'leading': leading,
      'maxWait': wait,
      'trailing': trailing
    });
  }

  function mitt(n){return {all:n=n||new Map,on:function(t,e){var i=n.get(t);i?i.push(e):n.set(t,[e]);},off:function(t,e){var i=n.get(t);i&&(e?i.splice(i.indexOf(e)>>>0,1):n.set(t,[]));},emit:function(t,e){var i=n.get(t);i&&i.slice().map(function(n){n(e);}),(i=n.get("*"))&&i.slice().map(function(n){n(t,e);});}}}

  /**
   * mitt 事件总程
   */
  class MyMitt {
      constructor() {
          Object.defineProperty(this, "emitter", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: mitt()
          });
      }
      on(type, handler) {
          this.emitter.on(type, handler);
          return this;
      }
      off(type, handler) {
          this.emitter.off(type, handler);
          return this;
      }
  }

  /**
   * 基类，element
   *
   * 被添加到地图上的元素
   *
   * 若当前扩展类不需要 mitt，在继承时，泛型填写 any，如：
   *
   * ```ts
   * class Foo extends Element<any>{
   *
   * }
   * ```
   */
  class Element extends MyMitt {
      constructor() {
          super();
          /**
           * NAME
           * 一般为子类的类名（防止工具压缩把类名压缩了，导致一些拿类名判断的逻辑失效，所以手动加上类名）
           */
          // abstract NAME: string;
          Object.defineProperty(this, "map", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
      }
      /**
       * __inject
       * 当元素被 map.add 之后，会注入整个 map 对象到子类，提供子类使用 map
       */
      __inject(map) {
          this.map = map;
          return this;
      }
  }

  // circle = false,
  //   circleColor = '#000000',
  //   // 推测出来的一个比例
  //   radius = fontSize / 1,
  //   fontSize = 12,
  //   color = '#222',
  //   padding = 10,
  //   // center = new Vector2(0.5, 0),
  //   center:Vector2,
  //   renderOrder:number,
  //   // depthTest = false
  class LabelMarker extends Element {
      constructor(options) {
          var _a, _b, _c, _d, _e, _f;
          super();
          Object.defineProperty(this, "options", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: options
          });
          Object.defineProperty(this, "scale", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: 4
          });
          Object.defineProperty(this, "sprite", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          options.position = (_a = options.position) !== null && _a !== void 0 ? _a : new three.Vector3();
          // 放大 4 倍，为了 retina 屏幕的高清
          options.fontSize = ((_b = options.fontSize) !== null && _b !== void 0 ? _b : 12) * this.scale;
          options.color = (_c = options.color) !== null && _c !== void 0 ? _c : '#222';
          // options.padding = options.padding ?? 10;
          // padding 可以大一点，让碰撞检测"尽早检测"
          options.padding = (_d = options.padding) !== null && _d !== void 0 ? _d : 50;
          options.center = (_e = options.center) !== null && _e !== void 0 ? _e : new three.Vector2(0.5, 0.5);
          options.renderOrder = (_f = options.renderOrder) !== null && _f !== void 0 ? _f : 0;
      }
      complete() { }
      // 重写父类 _inject
      // __inject(map: Map, _scale?: number) {
      //   super.__inject(map);
      //   this._scale = _scale!;
      //   return this;
      // }
      __init() { }
      create() {
          const canvas = this.generateCanvas(this.options);
          this.sprite = this.makeCanvasSprite(canvas, this.options);
          return this.sprite;
      }
      setPosition(position) {
          this.sprite && this.sprite.position.copy(position);
          this.map.reDraw();
      }
      /**
       * 生成 canvas
       */
      generateCanvas({ text, fontSize, padding, color }) {
          // const strokeStyle = 'rgba(255,255,255,.9)';
          const strokeStyle = 'rgba(255,255,255,1)';
          // const marginLeft = this.radius * 2;
          // const marginLeft = this.radius * 1.5;
          const canvas = document.createElement('canvas');
          const context = canvas.getContext('2d');
          context.font = `${fontSize}px Microsoft YaHei`;
          // 根据文字内容获取宽度
          canvas.width = context.measureText(text).width + padding * 2;
          // +
          // (this.circle ? this.radius * 2 + marginLeft : 0);
          // fontsize * 1.5 = 58;
          // canvas.height = this.fontSize * 1.5 + this.padding * 2;
          canvas.height = fontSize * 1.2 + padding * 2;
          context.font = `${fontSize}px Microsoft YaHei`;
          context.save();
          const textX = 0 + padding;
          // + (this.circle ? this.radius * 2 + marginLeft : 0);
          // 白色边框
          context.lineWidth = 12;
          context.strokeStyle = strokeStyle;
          context.strokeText(text, textX, fontSize + padding);
          context.fillStyle = color;
          context.fillText(text, textX, fontSize + padding);
          context.restore();
          // if (this.circle) {
          //   // 是否需要前面的圆圈 icon
          //   context.strokeStyle = strokeStyle;
          //   context.lineWidth = 12;
          //   context.beginPath();
          //   // console.log('canvas.height/2 :>> ', canvas.height / 2);
          //   context.arc(
          //     0 + this.padding + this.radius,
          //     canvas.height / 2,
          //     this.radius,
          //     0,
          //     2 * Math.PI
          //   );
          //   context.stroke();
          //   context.fillStyle = circleColor;
          //   context.arc(
          //     0 + this.padding + this.radius,
          //     canvas.height / 2,
          //     this.radius,
          //     0,
          //     2 * Math.PI
          //   );
          //   context.fill();
          // }
          return canvas;
      }
      makeCanvasSprite(canvas, { name, renderOrder, position, center }) {
          // https://discourse.threejs.org/t/keep-sprite-size-the-same-as-canvas-texture-size/4407/5
          const texture = new three.CanvasTexture(canvas);
          // texture.minFilter = LinearFilter;
          // texture.needsUpdate = true;
          const spriteMaterial = new three.SpriteMaterial({
              map: texture,
              depthTest: false,
              depthWrite: false,
              // 设置透明，比较协调
              transparent: true,
              // opacity: 0.7
              opacity: 0.8
          });
          const sprite = new three.Sprite(spriteMaterial);
          // sprite.name = OBJECT_NAME.POILabel
          sprite.name = name;
          // sprite.userData.name = name
          sprite.renderOrder = renderOrder;
          sprite.center = center;
          sprite.position.copy(position);
          // sprite.position.z += 10
          // this.group.add(sprite)
          // reDraw()
          return sprite;
      }
  }
  Object.defineProperty(LabelMarker, "NAME", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 'LabelMarker'
  });

  class LabelsLayer extends Element {
      constructor({ name, collision }) {
          super();
          Object.defineProperty(this, "scale", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: 4
          });
          Object.defineProperty(this, "options", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "group", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "updateSize", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          this.options = { name, collision };
          this.group = new three.Object3D();
          this.group.name = name;
          this.updateSize = throttle(() => {
              const sprites = this.group ? this.group.children : [];
              if (sprites.length === 0)
                  return;
              //  是否需要碰撞检测
              if (this.options.collision) {
                  for (let i = 0, il = sprites.length; i < il; i++) {
                      const sprite = sprites[i];
                      sprite.visible = true;
                  }
              }
              for (let i = 0, il = sprites.length; i < il; i++) {
                  const compareSprite = sprites[i];
                  // @ts-ignore
                  const canvas = compareSprite.material.map.image;
                  if (canvas) {
                      const position = compareSprite.position;
                      const scale = this.getPoiScale(position, {
                          w: canvas.width,
                          h: canvas.height
                      });
                      // ✨ 距离相机较远的标签，不进行展示
                      if (scale.distance > this.map.info.fitDistance) {
                          // if (scale.top > 100000) {
                          compareSprite.visible = false;
                      }
                      // ✨ 在视野外，进行隐藏，减少没有必要的计算
                      if (scale.out)
                          compareSprite.visible = false;
                      // // 缩小 4 倍在 retina 屏幕会比较高清
                      // compareSprite.scale.set(
                      //   scale[0] / this.scale,
                      //   scale[1] / this.scale,
                      //   1.0
                      // );
                      // 缩小 4 倍在 retina 屏幕会比较高清
                      compareSprite.scale.set(scale.x / this.scale, scale.y / this.scale, 1.0);
                      // 是否需要碰撞检测
                      if (this.options.collision && compareSprite.visible) {
                          for (let j = i + 1, jl = sprites.length; j < jl; j++) {
                              const sprite = sprites[j];
                              if (sprite.visible) {
                                  if (this.isMarkerCollision(compareSprite, sprite))
                                      sprite.visible = false;
                              }
                          }
                      }
                  }
              }
          }, 10);
      }
      complete() { }
      __init() {
          this.map.scene.add(this.group);
          this.map.updateSizeMap.set(this, () => this.updateSize());
      }
      add(...markers) {
          for (const item of markers) {
              item.__inject(this.map);
              // item.__inject(this.map, this.scale);
              // const marker = await item.create();
              const marker = item.create();
              this.group.add(marker);
          }
          this.map.reDraw();
          return this;
      }
      remove(...markers) {
          var _a, _b, _c, _d, _e, _f;
          for (const item of markers) {
              (_c = (_b = (_a = item === null || item === void 0 ? void 0 : item.sprite) === null || _a === void 0 ? void 0 : _a.geometry) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
              (_f = (_e = (_d = item === null || item === void 0 ? void 0 : item.sprite) === null || _d === void 0 ? void 0 : _d.material) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
              (item === null || item === void 0 ? void 0 : item.sprite) && this.group.remove(item === null || item === void 0 ? void 0 : item.sprite);
          }
          this.map.reDraw();
          return this;
      }
      // /**
      //  * 暴露出更新size方法，使其可以在 cameraControls 控制时候更新
      //  */
      // private updateSize() {
      //   const sprites = this.group ? this.group.children : [];
      //   if (sprites.length === 0) return;
      //   //  是否需要碰撞检测
      //   if (this.options.collision) {
      //     for (let i = 0, il = sprites.length; i < il; i++) {
      //       const sprite = sprites[i];
      //       sprite.visible = true;
      //     }
      //   }
      //   for (let i = 0, il = sprites.length; i < il; i++) {
      //     const compareSprite = sprites[i];
      //     // @ts-ignore
      //     const canvas = compareSprite.material.map.image;
      //     if (canvas) {
      //       const position = compareSprite.position;
      //       const scale = this.getPoiScale(position, {
      //         w: canvas.width,
      //         h: canvas.height
      //       });
      //       // ✨ 在视野外，进行隐藏，减少没有必要的计算
      //       if (scale.out) compareSprite.visible = false;
      //       // // if (scale.distance > 100000) {
      //       // if (scale.top > 100000) {
      //       //   compareSprite.visible = false;
      //       // }
      //       // // 缩小 4 倍在 retina 屏幕会比较高清
      //       // compareSprite.scale.set(
      //       //   scale[0] / this.scale,
      //       //   scale[1] / this.scale,
      //       //   1.0
      //       // );
      //       // 缩小 4 倍在 retina 屏幕会比较高清
      //       compareSprite.scale.set(
      //         scale.x / this.scale,
      //         scale.y / this.scale,
      //         1.0
      //       );
      //       // 是否需要碰撞检测
      //       if (this.options.collision && compareSprite.visible) {
      //         for (let j = i + 1, jl = sprites.length; j < jl; j++) {
      //           const sprite = sprites[j];
      //           if (sprite.visible) {
      //             if (this.isMarkerCollision(compareSprite, sprite))
      //               sprite.visible = false;
      //           }
      //         }
      //       }
      //     }
      //   }
      // }
      getPoiScale(position, poiRect) {
          //   const tempV = firstArrow.position
          //   .clone()
          //   .applyMatrix4(camera.matrixWorldInverse)
          //   .applyMatrix4(camera.projectionMatrix);
          // if (
          //   Math.abs(tempV.x) > 1 ||
          //   Math.abs(tempV.y) > 1 ||
          //   Math.abs(tempV.z) > 1
          // ) {
          //   status = 'out';
          //   // 在视野外了
          //   // console.log('在视野外了 :>> ', '在视野外了');
          // } else {
          //   status = 'in';
          //   // 在视野内了
          //   // console.log('在视野内 :>> ', '在视野内');
          // }
          const { camera, info: { boundingClientRect: { height } } } = this.map;
          const distance = camera.position.distanceTo(position); // 相机和标注点的距离
          const top = Math.tan(((camera.fov / 2) * Math.PI) / 180) * distance; // camera.fov 相机的拍摄距离
          const meterPerPixel = (2 * top) / height;
          const scaleX = poiRect.w * meterPerPixel;
          const scaleY = poiRect.h * meterPerPixel;
          // 是否在视野外
          const tempPosi = position.clone().project(camera);
          const SCALE = 1;
          const out = Math.abs(tempPosi.x) > SCALE ||
              Math.abs(tempPosi.y) > SCALE ||
              Math.abs(tempPosi.z) > SCALE;
          // return [scaleX, scaleY, 1.0];
          return { x: scaleX, y: scaleY, distance, top, out };
      }
      // /**
      //  * 检测两个标注 sprite 是否碰撞
      //  */
      isMarkerCollision(compareSprite, sprite) {
          const comparePosition = this.toScreenPos([
              compareSprite.position.x,
              compareSprite.position.y,
              compareSprite.position.z
          ], this.map.camera);
          const spritePosition = this.toScreenPos([sprite.position.x, sprite.position.y, sprite.position.z], this.map.camera);
          const image1 = compareSprite.material.map.image;
          const image2 = sprite.material.map.image;
          const w1 = image1.width / this.scale;
          const h1 = image1.height / this.scale;
          const x1 = comparePosition.x - w1 / 2;
          const y1 = comparePosition.y - h1 / 2;
          const w2 = image2 ? image2.width / this.scale : 0;
          const h2 = image2 ? image2.height / this.scale : 0;
          const x2 = spritePosition.x - w2 / 2; // 点2左下角的xy点
          const y2 = spritePosition.y - h2 / 2;
          if (x1 >= x2 && x1 >= x2 + w2) {
              return false;
          }
          else if (x1 <= x2 && x1 + w1 <= x2) {
              return false;
          }
          else if (y1 >= y2 && y1 >= y2 + h2) {
              return false;
          }
          else if (y1 <= y2 && y1 + h1 <= y2) {
              return false;
          }
          else {
              return true;
          }
      }
      /**
       * three世界坐标转为屏幕坐标
       */
      toScreenPos(position, camera) {
          const { info: { boundingClientRect: { left, top, width, height } } } = this.map;
          const worldVector = new three.Vector3(position[0], position[1], position[2]);
          const standardVector = worldVector.project(camera); // 世界坐标转标准设备坐标
          // // ❌ 这些写法会触发重排，导致性能下降
          // // this.map.$map!.getBoundingClientRect();
          // // this.halfMapWidth = this.map.$map!.clientWidth / 2;
          // // this.halfMapHeight = this.map.$map!.clientHeight / 2;
          // // window.innerWidth;
          // // window.innerHeight;
          const halfWidth = width / 2;
          const halfHeight = height / 2;
          const x = Math.round(standardVector.x * halfWidth + halfWidth); // 标准设备坐标转屏幕坐标
          const y = Math.round(-standardVector.y * halfHeight + halfHeight); // 标准设备坐标转屏幕坐标
          return {
              x: x + left,
              y: y + top
          };
      }
  }
  Object.defineProperty(LabelsLayer, "NAME", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 'LabelsLayer'
  });

  exports.LabelMarker = LabelMarker;
  exports.LabelsLayer = LabelsLayer;

  Object.defineProperty(exports, '__esModule', { value: true });

  return exports;

})({}, THREE);
