两种方式实现图片标记

效果图
第一种:通过动态添加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;
  }
}
相关推荐
zzzzzz31022 分钟前
react-bits:从 36K Stars 的组件库,看动画交互组件该如何被评估
前端·react.js·动效
luteres1 小时前
Mybatis+SSM整合笔记
java·开发语言·mybatis
郝学胜-神的一滴1 小时前
《C++11 工程级应用01:告别冗长类型,开启简洁高效编码新时代》深度解读
开发语言·c++·算法·软件开发·系统设计
其实防守也摸鱼1 小时前
推荐一个自动化教育SRC漏洞挖掘系统--AutoHunter
运维·开发语言·人工智能·学习·安全·web安全·自动化
Setsuna_F_Seiei8 小时前
前端的 AI 学习之路 01 之 Agent API 调用 - 和 Agent 的基础对话
前端·人工智能·ai编程
覆东流8 小时前
7.Java数组
java·开发语言·后端
码行山野赴时序归途8 小时前
三道经典数组题:从暴力到最优的算法思维
c语言·开发语言·数据结构·算法·leetcode
threerocks8 小时前
AI 原生软件开发生命周期手册 - 如何借助 AI,逐阶段改造软件开发生命周期
前端·javascript·后端
lzhdim8 小时前
提高 SQL 语句执行速度的方法
java·开发语言·数据库·sql·oracle
JavaPub-rodert8 小时前
王仕宇在 Go Context 如何解决协程泄漏与超时控制
开发语言·后端·golang·iphone·javapub·王仕宇