{"version":3,"file":"PortCanvas.mjs","sources":["../../../../../../packages/sdk/plugins/Port/PortCanvas.ts"],"sourcesContent":["import { CanvasLayer } from 'leaflet-canvas-layer'\nimport L from 'leaflet'\nimport { GPS } from '@map-sdk/sdk/utils/GPS'\nimport { PointClusterer } from '@map-sdk/sdk/utils/Dilution/PointClusterer'\nimport { CanvasEventHandler } from '@map-sdk/sdk/plugins/CanvasEventHandler'\nimport type { MyMap } from '@map-sdk/sdk/ShipxyAPISDK'\n\ninterface IPortData {\n  id: string\n  lat: number\n  lng: number\n  nameCN?: string\n  nameEN?: string\n  range?: number[]\n  flagDraw?: boolean\n  x: number\n  y: number\n  label?: string\n  rnd: number\n}\n\ninterface IPortCanvasOptions {\n  [key: string]: any\n}\n\nexport class PortCanvas {\n  private _imgWidth = 16\n  private _imgHeight = 16\n  private _map: any // 假设map是一个地图对象，具体类型根据实际情况定义\n  private _canvas!: HTMLCanvasElement\n  private _portImg: HTMLImageElement\n  private _zoomLabel = 8\n\n  private portData: IPortData[] = []\n  private villagePortData: IPortData[] = [] // 抽稀之后的点\n  private canvasLayer: CanvasLayer\n  constructor(map: MyMap, options: IPortCanvasOptions = {}) {\n    this._map = map\n    this._portImg = new Image()\n    this._portImg.src = `https://api.iconify.design/ph:anchor-bold.svg?color=%23ff0000`\n    this.canvasLayer = new CanvasLayer().delegate(this).addTo(this._map)\n    this._map.on('zoomend moveend', () => {\n      requestAnimationFrame(() => this.refreshPointClusterer())\n    })\n  }\n  protected onDrawLayer(info: { canvas: HTMLCanvasElement }): void {\n    this._canvas = info.canvas\n    this._canvas.classList.add('port-canvas')\n    new CanvasEventHandler(info.canvas, {\n      mousedown: this.handleCanvasClick.bind(this),\n      mousemove: this.handleCanvasClick.bind(this),\n    })\n  }\n  private format() {\n    this.portData = this.portData.map((item) => {\n      const { x, y } = this._map.latLngToContainerPoint(\n        GPS.latLngToGPSBymap([item.lat, item.lng], this._map)\n      )\n      return {\n        ...item,\n        x,\n        y,\n        label: item.nameCN || item.nameEN,\n        flagDraw: true,\n      }\n    })\n  }\n  public show(methods: (arg0: (data: IPortData[]) => void) => any) {\n    methods &&\n      methods((data: IPortData[]) => {\n        this.portData = data\n        requestAnimationFrame(() => this.refreshPointClusterer())\n      })\n  }\n  public hiden() {\n    this.portData = []\n    this.canvasLayer.remove()\n    requestAnimationFrame(() => this.refreshPointClusterer())\n  }\n  private isNearPoint(\n    mouseX: number,\n    mouseY: number,\n    point: IPortData,\n    threshold = 5\n  ) {\n    const { x, y } = point\n    if (x && y) {\n      const dx = Math.abs(mouseX - x)\n      const dy = Math.abs(mouseY - y)\n      return dx <= threshold && dy <= threshold\n    }\n    return false\n  }\n  private handleCanvasClick(event: {\n    clientX: number\n    clientY: number\n    type: string\n  }) {\n    const rect = this._canvas.getBoundingClientRect()\n    const mouseX = event.clientX - rect.left\n    const mouseY = event.clientY - rect.top\n\n    for (const point of this.villagePortData) {\n      if (this.isNearPoint(mouseX, mouseY, point)) {\n        // 鼠标靠近该点，准备显示提示框\n        if (event.type === 'mousemove') {\n          this._canvas.classList.add('leaflet-interactive')\n        }\n        this.showTooltip(point)\n        return\n      }\n    }\n    this._canvas.classList.remove('leaflet-interactive')\n    // 鼠标未靠近任何点，隐藏提示框\n    this.hideTooltip()\n  }\n\n  /**\n   * 绘制相关点\n   * @returns\n   */\n  private drawPorts(portData: IPortData[]) {\n    if (!this._canvas) {\n      return\n    }\n\n    const ctx = this._canvas.getContext('2d')\n    if (!ctx) return\n    ctx.clearRect(0, 0, this._canvas.width, this._canvas.height)\n    for (const port of portData) {\n      // 绘制港口图标，这里仅作示例，您可以根据实际需求替换为具体的绘制逻辑\n      // ctx.beginPath()\n      // ctx.arc(port.x, port.y, 5, 0, 2 * Math.PI) // 以 (x, y) 为中心绘制半径为 5 的圆\n      // ctx.fillStyle = 'rgba(255, 0, 0, 0.8)' // 红色半透明填充\n      // ctx.fill()\n      // ctx.strokeStyle = 'white'\n      // ctx.lineWidth = 2\n      // ctx.stroke()\n      ctx.save()\n      ctx.fillStyle = 'rgba(255, 255, 255, 0)'\n      ctx.translate(port.x, port.y)\n      ctx.drawImage(\n        this._portImg,\n        -this._imgWidth / 2,\n        -this._imgHeight / 2,\n        this._imgWidth,\n        this._imgHeight\n      )\n      // 复原画布\n      ctx.restore()\n      this.drawPortLabel(ctx, port)\n    }\n  }\n\n  private drawPortLabel(\n    ctx: CanvasRenderingContext2D,\n    portData: IPortData\n  ): void {\n    const zoom = this._map.getZoom()\n    const { x, y, label } = portData\n    if (!ctx || zoom < this._zoomLabel || !portData.flagDraw) {\n      return\n    }\n    if (x && y) {\n      ctx.beginPath()\n      ctx.moveTo(x, y)\n      ctx.lineTo(x + 10, y - 10)\n      ctx.strokeStyle = '#000000'\n      ctx.globalAlpha = 0.5\n      ctx.lineWidth = 1\n      ctx.stroke()\n      ctx.closePath()\n      const textWidth = ctx.measureText(label!).width\n      ctx.moveTo(x, y)\n      ctx.globalAlpha = 0.7\n      ctx.fillStyle = '#FFF'\n      ctx.fillRect(x + 10, y - 25, textWidth + 10, 20)\n      ctx.globalAlpha = 1.0\n      ctx.font = '14px Arial'\n      ctx.fillStyle = '#000'\n      ctx.fillText(label!, x + 15, y - 10, textWidth)\n    }\n  }\n\n  private showTooltip(point: IPortData) {\n    const leafletPopupPane = document.querySelector(\n      '.leaflet-popup-pane'\n    ) as HTMLDivElement\n    leafletPopupPane.innerHTML = `<div class=\"portTitle\" style=\"left: ${point.x}px; top: ${point.y}px;\n            position: absolute;\n            font-size: 12px;\n            padding: 0 5px;\n            margin: 10px;\n            background: #fff;\n            white-space: nowrap;\">\n            <span>${point.label}</span>\n            </div>`\n  }\n  private hideTooltip() {\n    const leafletPopupPane = document.querySelector(\n      '.portTitle'\n    ) as HTMLDivElement\n    leafletPopupPane && leafletPopupPane.remove()\n  }\n\n  refreshPointClusterer() {\n    const map = this._map\n    this.format()\n    // 稀疏算法\n    new PointClusterer(\n      map,\n      this.portData.map((item) => ({\n        ...item,\n        point: new L.LatLng(item.lat, item.lng),\n      })),\n      {\n        thresholdFactor: 0.03,\n        maxPointRange: 0.5,\n        collisionResolution: 'nearest',\n        callback: (params: any) => {\n          this.villagePortData = params\n          this.drawPorts(params)\n        },\n      }\n    )\n  }\n}\n"],"names":["PortCanvas","constructor","t","a","this","_imgWidth","_imgHeight","_zoomLabel","portData","villagePortData","_map","_portImg","Image","src","canvasLayer","l","delegate","addTo","on","requestAnimationFrame","refreshPointClusterer","onDrawLayer","_canvas","canvas","classList","add","v","mousedown","handleCanvasClick","bind","mousemove","format","map","x","y","i","latLngToContainerPoint","h","latLngToGPSBymap","lat","lng","label","nameCN","nameEN","flagDraw","show","hiden","remove","isNearPoint","r","e","o","n","Math","abs","s","getBoundingClientRect","clientX","left","clientY","top","type","showTooltip","hideTooltip","drawPorts","getContext","clearRect","width","height","save","fillStyle","translate","drawImage","restore","drawPortLabel","getZoom","beginPath","moveTo","lineTo","strokeStyle","globalAlpha","lineWidth","stroke","closePath","measureText","fillRect","font","fillText","document","querySelector","innerHTML","m","point","p","LatLng","thresholdFactor","maxPointRange","collisionResolution","callback"],"mappings":"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"}