var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};

// packages/plugins/labels-layer/src/labelMarker.ts
import {
  CanvasTexture,
  Sprite,
  SpriteMaterial,
  Vector2,
  Vector3
} from "three";
import { Element } from "@ktmap/map";
var LabelMarker = class extends Element {
  constructor(options) {
    var _a, _b, _c, _d, _e, _f;
    super();
    this.options = options;
    __publicField(this, "scale", 4);
    __publicField(this, "sprite");
    options.position = (_a = options.position) != null ? _a : new Vector3();
    options.fontSize = ((_b = options.fontSize) != null ? _b : 12) * this.scale;
    options.color = (_c = options.color) != null ? _c : "#222";
    options.padding = (_d = options.padding) != null ? _d : 50;
    options.center = (_e = options.center) != null ? _e : new Vector2(0.5, 0.5);
    options.renderOrder = (_f = options.renderOrder) != null ? _f : 0;
  }
  complete() {
  }
  __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();
  }
  generateCanvas({ text, fontSize, padding, color }) {
    const strokeStyle = "rgba(255,255,255,1)";
    const canvas = document.createElement("canvas");
    const context = canvas.getContext("2d");
    context.font = `${fontSize}px Microsoft YaHei`;
    canvas.width = context.measureText(text).width + padding * 2;
    canvas.height = fontSize * 1.2 + padding * 2;
    context.font = `${fontSize}px Microsoft YaHei`;
    context.save();
    const textX = 0 + padding;
    context.lineWidth = 12;
    context.strokeStyle = strokeStyle;
    context.strokeText(text, textX, fontSize + padding);
    context.fillStyle = color;
    context.fillText(text, textX, fontSize + padding);
    context.restore();
    return canvas;
  }
  makeCanvasSprite(canvas, { name, renderOrder, position, center }) {
    const texture = new CanvasTexture(canvas);
    const spriteMaterial = new SpriteMaterial({
      map: texture,
      depthTest: false,
      depthWrite: false,
      transparent: true,
      opacity: 0.8
    });
    const sprite = new Sprite(spriteMaterial);
    sprite.name = name;
    sprite.renderOrder = renderOrder;
    sprite.center = center;
    sprite.position.copy(position);
    return sprite;
  }
};
__publicField(LabelMarker, "NAME", "LabelMarker");

// packages/plugins/labels-layer/src/labelsLayer.ts
import { Object3D, Vector3 as Vector32 } from "three";
import { Element as Element2 } from "@ktmap/map";
import { throttle } from "@ktmap/shared";
var LabelsLayer = class extends Element2 {
  constructor({ name, collision }) {
    super();
    __publicField(this, "scale", 4);
    __publicField(this, "options");
    __publicField(this, "group");
    __publicField(this, "updateSize");
    this.options = { name, collision };
    this.group = new 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];
        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) {
            compareSprite.visible = false;
          }
          if (scale.out)
            compareSprite.visible = false;
          compareSprite.scale.set(
            scale.x / this.scale,
            scale.y / this.scale,
            1
          );
          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);
      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 ? void 0 : item.sprite) == null ? void 0 : _a.geometry) == null ? void 0 : _b.dispose) == null ? void 0 : _c.call(_b);
      (_f = (_e = (_d = item == null ? void 0 : item.sprite) == null ? void 0 : _d.material) == null ? void 0 : _e.dispose) == null ? void 0 : _f.call(_e);
      (item == null ? void 0 : item.sprite) && this.group.remove(item == null ? void 0 : item.sprite);
    }
    this.map.reDraw();
    return this;
  }
  getPoiScale(position, poiRect) {
    const {
      camera,
      info: {
        boundingClientRect: { height }
      }
    } = this.map;
    const distance = camera.position.distanceTo(position);
    const top = Math.tan(camera.fov / 2 * Math.PI / 180) * distance;
    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 { x: scaleX, y: scaleY, distance, top, out };
  }
  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;
    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;
    }
  }
  toScreenPos(position, camera) {
    const {
      info: {
        boundingClientRect: { left, top, width, height }
      }
    } = this.map;
    const worldVector = new Vector32(position[0], position[1], position[2]);
    const standardVector = worldVector.project(camera);
    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
    };
  }
};
__publicField(LabelsLayer, "NAME", "LabelsLayer");
export {
  LabelMarker,
  LabelsLayer
};
//# sourceMappingURL=labels-layer.esm-bundler.js.map
