You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular实现图片点击定位指定编号区域并添加边框

后续问题:点击图片指定区域添加边框

这是Stack Overflow问题《在图片特定区域选择坐标并添加边框》的后续问询。

需求说明:

  • 允许直接点击图片,根据鼠标相对于图片的点击坐标计算对应区域
  • 自动为图片上的指定编号区域(如编号81)添加边框
  • 仅能选中图片上的编号区域,其他区域不可选
  • 图片点击实现的边框效果需与此前已实现的「点击表格行添加对应区域边框」功能完全一致

以下是关键代码片段:

HTML代码

<table>
  <thead>
    <tr>
      <th scope="col">Name</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let row of columns">
      <td (click)="showCorner(row)">{{ row.itemNumber }}</td>
      <td (click)="showCorner(row)">{{ row.partNumber }}</td>
    </tr>
  </tbody>
</table>

<div class="flex-1 relative">
  <div class="relative">
    <img
      #imgPath
      (click.double)="addBorder($event)"
      style="width: 832px; max-width: fit-content;"
      src="../../assets/flow-editor/Image/ev00129014.png"
    />
    <div
      id="rec1"
      class="absolute"
      [ngStyle]="{ left: coordinateX + 'px', top: coordinateY + 'px' }"
    ></div>
  </div>
</div>

TypeScript代码

export class AppComponent implements AfterViewInit {
  @ViewChild('imgPath', { static: false }) imgElementRef!: ElementRef;
  coordinateX!: number;
  coordinateY!: number;
  originalCoordinates: any; // 存储原始坐标
  columns = [
    {
      itemNumber: '1',
      partNumber: '4400535240',
      coordinates: [
        {
          itemCounter: 0,
          xposition: 970,
          yposition: 375,
        },
      ],
    },
    {
      itemNumber: '2',
      partNumber: '4400541680',
      coordinates: [
        {
          itemCounter: 0,
          xposition: 1282,
          yposition: 522,
        },
      ],
    },
    {
      itemNumber: '4',
      partNumber: '4400541390',
      coordinates: [
        {
          itemCounter: 0,
          xposition: 445,
          yposition: 307,
        },
      ],
    },
  ];

  constructor() {
    // 深拷贝原始columns以保留原始坐标
    this.originalCoordinates = JSON.parse(JSON.stringify(this.columns));
  }

  ngAfterViewInit() {
    // 视图初始化时计算并应用缩放比例
    this.calculateAndApplyScaling();
  }

  private calculateOffset(): number {
    const imgElement = this.imgElementRef.nativeElement as HTMLImageElement;

    // 获取各项属性
    const imgTopPosition = imgElement.getBoundingClientRect().top;
    const imgOffsetTop = imgElement.offsetTop;
    const windowScrollY = window.scrollY;
    const documentClientTop = 
      document.documentElement.clientTop || document.body.clientTop || 0;

    // 打印属性日志
    console.log('图片元素getBoundingClientRect().top:', imgTopPosition);
    console.log('图片元素offsetTop:', imgOffsetTop);
    console.log('窗口scrollY:', windowScrollY);
    console.log('文档clientTop:', documentClientTop);

    return window.scrollY + imgTopPosition;
  }

  showCorner(event: any) {
    // 计算并应用缩放比例
    this.calculateAndApplyScaling();

    // 使用缩放后的坐标
    this.coordinateX = event.coordinates[0].xposition;
    const offsetY = this.calculateOffset();
    this.coordinateY = event.coordinates[0].yposition + offsetY - 15;

    // 打印坐标到控制台
    console.log('选中的坐标:', this.coordinateX, this.coordinateY);

    // 更新边框元素
    this.updateBorderElement();
  }

  private calculateAndApplyScaling() {
    const imgElement = this.imgElementRef.nativeElement as HTMLImageElement;
    const currentWidth = imgElement.clientWidth;
    const currentHeight = imgElement.clientHeight;

    console.log(
      '图片当前宽度:',
      currentWidth,
      '当前高度:',
      currentHeight
    );

    // 使用naturalWidth和naturalHeight属性获取原始尺寸
    const originalWidth = imgElement.naturalWidth;
    const originalHeight = imgElement.naturalHeight;

    const scaleX = currentWidth / originalWidth;
    const scaleY = currentHeight / originalHeight;

    console.log('X轴缩放比例:', scaleX, 'Y轴缩放比例:', scaleY);

    // 为每个原始坐标应用缩放比例
    this.columns.forEach((column, index) => {
      column.coordinates.forEach((coordinate, coordIndex) => {
        const originalCoordinate = 
          this.originalCoordinates[index].coordinates[coordIndex];
        coordinate.xposition = originalCoordinate.xposition * scaleX;
        coordinate.yposition = originalCoordinate.yposition * scaleY;

        console.log(
          `原始坐标: (${originalCoordinate.xposition}, ${originalCoordinate.yposition}), 缩放后坐标: (${coordinate.xposition}, ${coordinate.yposition})`
        );
      });
    });
  }

  private updateBorderElement() {
    const recElement = document.getElementById('rec1') as HTMLElement;
    if (recElement) {
      recElement.style.border = '2px solid red';
      recElement.style.width = '25px';
      recElement.style.height = '25px';
      recElement.style.left = this.coordinateX + 'px';
      recElement.style.top = this.coordinateY + 'px';

      console.log(
        '边框元素已更新:',
        `左偏移: ${this.coordinateX}px, 上偏移: ${this.coordinateY}px`
      );
    }
  }

  addBorder(event: any) {
    console.log('添加边框事件:', event);
    const e = event.target.getBoundingClientRect();
    console.log('Bounding Client Rect:', e);
    const xClientH = event.screenY;
    const xClientY = event.screenX;

    this.coordinateX = xClientY;
    this.coordinateY = xClientH;
    console.log(
      '事件获取的坐标:',
      `X: ${this.coordinateX}, Y: ${this.coordinateY}`
    );

    const recElement = document.getElementById('rec1') as HTMLInputElement;
    if (recElement) {
      recElement.innerHTML = 
        "<img src='../../assets/flow-editor/Image/rec.gif' style='width:25px; height:25px;'></img>";
    }
  }
}

内容的提问来源于stack exchange,提问作者TheCoderGuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 02:21:04