两种方式实现图片标记

效果图
第一种:通过动态添加dom元素实现标记
代码如下
cpp 复制代码
// index.tsx
import React from "react";
import "./index.less";

export default function index() {
  const parentRef = React.useRef<any>(null);
  const ulRef = React.useRef<any>(null);
  let count = 0;

  const generateMark = (x: number, y: number) => {
    const li = document.createElement("li");
    li.innerHTML = count.toString();
    li.style.left = x + "px";
    li.style.top = y + "px";
    ulRef.current.appendChild(li);
  };

  const onClick = (e) => {
    const rect = ulRef.current.getBoundingClientRect();
    const x = e.clientX - rect.left - 10; // 减去li宽度一半、居中
    const y = e.clientY - rect.top - 10;
    count += 1;
    generateMark(x, y);
  };
  return (
    <div ref={parentRef} className="wrap" onClick={onClick}>
      <img
        src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp"
        alt=""
      />
      <ul ref={ulRef}></ul>
    </div>
  );
}
cpp 复制代码
// index.less
.wrap {
  width: 600px;
  height: 600px;
  margin: auto;
  position: relative;
  img {
    width: 100%;
    height: 100%;
  }
  ul {
    position: absolute;
    top: 0;
    border: 1px solid green;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
    li {
      position: absolute;
      width: 20px;
      height: 20px;
      line-height: 20px;
      border-radius: 50%;
      background-color: orange;
      text-align: center;
      color: white;
    }
  }
}
第二种:通过canvas实现标记
cpp 复制代码
import React, { useEffect } from "react";
import "./index.less";

export default function index() {
  const parentRef = React.useRef<any>(null);
  const imgRef = React.useRef<any>(null);
  const canvasRef = React.useRef<any>(null);
  let count = 0;

  const drawMark = (ctx, x: number, y: number) => {
    const textWidth = ctx.measureText(count).width;
    ctx.strokeStyle = "#FFFFFF";
    ctx.fillStyle = "orange";
    ctx.lineWidth = 2;
    ctx.shadowOffsetX = 2;
    ctx.shadowBlur = 2;
    ctx.shadowColor = "rgba(10, 18, 28, 0.20)";
    ctx.beginPath();
    ctx.arc(x, y, 15, 0, Math.PI * 2);
    ctx.fill();
    ctx.stroke();
    ctx.font = "16px IBM Plex Sans";
    ctx.fillStyle = "#FFFFFF";
    ctx?.fillText(count, x - textWidth / 2, y + 5);
    ctx.closePath();
  };

  const onClick = (e) => {
    const canvas = canvasRef.current;
    const rect = canvas.getBoundingClientRect();
    const ctx = canvas.getContext("2d");
    const x = e.clientX - rect.left; // 减去li宽度一半、居中
    const y = e.clientY - rect.top;
    count += 1;
    console.log("ctx", ctx);
    if (ctx) {
      drawMark(ctx, x, y);
    }
  };

  useEffect(() => {
    // 动态赋值canvas宽高
    canvasRef.current.width = imgRef.current.width;
    canvasRef.current.height = imgRef.current.height;
  }, [imgRef]);
  return (
    <div ref={parentRef} className="wrap" onClick={onClick}>
      <img
        ref={imgRef}
        src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp"
        alt=""
      />
      <canvas ref={canvasRef}></canvas>
    </div>
  );
} 
c 复制代码
.wrap {
  width: 600px;
  height: 600px;
  margin: auto;
  position: relative;
  img {
    width: 100%;
    height: 100%;
  }
  canvas {
    position: absolute;
    left: 0;
    border: 1px solid green;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
  }
}
相关推荐
阿蒙Amon3 小时前
TypeScript学习-第7章:泛型(Generic)
javascript·学习·typescript
睡美人的小仙女1273 小时前
Threejs加载环境贴图报错Bad File Format: bad initial token
开发语言·javascript·redis
fanruitian4 小时前
uniapp android开发 测试板本与发行版本
前端·javascript·uni-app
rayufo4 小时前
【工具】列出指定文件夹下所有的目录和文件
开发语言·前端·python
RANCE_atttackkk4 小时前
[Java]实现使用邮箱找回密码的功能
java·开发语言·前端·spring boot·intellij-idea·idea
摘星编程5 小时前
React Native + OpenHarmony:Timeline垂直时间轴
javascript·react native·react.js
缺点内向5 小时前
C#编程实战:如何为Word文档添加背景色或背景图片
开发语言·c#·自动化·word·.net
一起养小猫5 小时前
Flutter for OpenHarmony 实战:记账应用数据统计与可视化
开发语言·jvm·数据库·flutter·信息可视化·harmonyos
zhougl9965 小时前
Java 所有关键字及规范分类
java·开发语言
java1234_小锋5 小时前
Java高频面试题:MyISAM索引与InnoDB索引的区别?
java·开发语言