如何在Svelte中实现图片点击位置的红点标记功能?
给Svelte图片添加点击位置红点标记
方案一:绝对定位元素实现(轻量快捷)
这种方式无需Canvas,直接用DOM元素做标记,适合简单的标记需求。
修改后的完整代码:
<script lang="ts"> const image = `https://raw.githubusercontent.com/lieldvd/mturk/main/15545/frame_0.jpg`; let clickPositions = []; // 存储所有点击位置,支持多标记 const imageDimensions = {w: 1280, h: 640}; let container: HTMLElement; function handleImageClick(event){ const imageElement = event.currentTarget as HTMLImageElement; const rect = imageElement.getBoundingClientRect(); // 计算相对于图片原始尺寸的坐标(处理缩放) const scaleX = imageElement.naturalWidth / rect.width; const scaleY = imageElement.naturalHeight / rect.height; const relativeX = (event.clientX - rect.left) * scaleX; const relativeY = (event.clientY - rect.top) * scaleY; clickPositions = [...clickPositions, {x: relativeX, y: relativeY}]; } // 计算红点的显示位置(反向适配图片缩放) function getMarkerStyle(pos: {x: number, y: number}){ if(!container) return {}; const rect = container.getBoundingClientRect(); const scaleX = rect.width / imageDimensions.w; const scaleY = rect.height / imageDimensions.h; return { left: `${pos.x * scaleX}px`, top: `${pos.y * scaleY}px` }; } </script> <main> <div class="image-container" bind:this={container}> <!-- svelte-ignore a11y-click-events-have-key-events --> <img class="image" src={image} alt='Target image' on:click={(e)=>handleImageClick(e)} /> <!-- 渲染所有点击标记 --> {#each clickPositions as pos, index} <div class="click-marker" style={getMarkerStyle(pos)}></div> {/each} </div> <div>点击坐标:{clickPositions.map(p => `(${p.x.toFixed(0)}, ${p.y.toFixed(0)})`).join(', ')}</div> </main> <style> main { text-align: center; padding: 1em; max-width: 240px; margin: 0 auto; } .image-container { position: relative; display: inline-block; /* 容器宽度适配图片 */ } .image { max-width: 100%; height: auto; } .click-marker { position: absolute; width: 8px; height: 8px; border-radius: 50%; background-color: #ff0000; transform: translate(-50%, -50%); /* 红点中心对准点击点 */ pointer-events: none; /* 不干扰图片点击事件 */ } @media (min-width: 640px) { main { max-width: none; } } </style>
核心要点:
- 用
image-container作为相对定位容器,确保红点在图片上方正确定位 - 处理图片缩放问题:将页面点击坐标转换为图片原始坐标,再反向计算显示位置,保证标记准确
- 支持多标记,通过数组存储所有点击位置并循环渲染
方案二:Canvas实现(适合复杂绘图需求)
如果需要编辑标记、导出带标记的图片等功能,用Canvas更合适。
完整代码:
<script lang="ts"> const imageSrc = `https://raw.githubusercontent.com/lieldvd/mturk/main/15545/frame_0.jpg`; let canvas: HTMLCanvasElement; let ctx: CanvasRenderingContext2D; let image: HTMLImageElement; let clickPositions = []; // 初始化Canvas和图片 function initCanvas(){ image = new Image(); image.src = imageSrc; image.onload = () => { // 让Canvas尺寸匹配图片原始尺寸 canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; ctx = canvas.getContext('2d'); redraw(); } } // 重绘图片和所有标记 function redraw(){ if(!ctx || !image) return; ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制原图 ctx.drawImage(image, 0, 0); // 绘制所有红点标记 clickPositions.forEach(pos => { ctx.fillStyle = '#ff0000'; ctx.beginPath(); ctx.arc(pos.x, pos.y, 4, 0, Math.PI * 2); ctx.fill(); }); } function handleCanvasClick(event){ if(!ctx || !canvas) return; const rect = canvas.getBoundingClientRect(); // 计算相对于Canvas原始尺寸的坐标 const scaleX = canvas.width / rect.width; const scaleY = canvas.height / rect.height; const x = (event.clientX - rect.left) * scaleX; const y = (event.clientY - rect.top) * scaleY; clickPositions = [...clickPositions, {x, y}]; redraw(); } // 组件挂载时初始化 import { onMount } from 'svelte'; onMount(() => { initCanvas(); }); </script> <main> <div class="canvas-container"> <canvas bind:this={canvas} on:click={handleCanvasClick} style="max-width: 100%; height: auto;" ></canvas> </div> <div>点击坐标:{clickPositions.map(p => `(${p.x.toFixed(0)}, ${p.y.toFixed(0)})`).join(', ')}</div> </main> <style> main { text-align: center; padding: 1em; max-width: 240px; margin: 0 auto; } .canvas-container { display: inline-block; } @media (min-width: 640px) { main { max-width: none; } } </style>
核心要点:
- 将图片绘制到Canvas上,点击事件直接绑定在Canvas上
- 每次点击后重绘图片和标记,避免标记被覆盖
- Canvas通过
max-width:100%实现自适应缩放,同时保持绘图坐标的准确性
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

