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

点击SVG路径无法移至屏幕中心的问题求助

SVG路径点击后无法居中的问题修复

问题原因

  • 计算偏移量时错误传入整个SVG元素,而非当前点击的路径元素,导致偏移量基于SVG容器而非目标路径计算。
  • 对getBoundingClientRect()返回值乘以2是多余操作,该方法直接返回元素在屏幕上的实际坐标。
  • CSS中.selected类的transform: scale(2)与JS中设置的translate冲突,叠加后导致位置偏差。
  • 重置位置时采用反向计算偏移量的方式,未考虑缩放等叠加变换,无法正确还原。
  • mouseleave事件回调未传入event参数,导致event.target报错。

修复方案

  1. 修正偏移量计算逻辑:

    • 将calcCenterMove的参数改为当前点击的path元素,移除坐标和尺寸的*2操作。
    • 计算路径中心到屏幕中心的偏移量,确保路径中心与屏幕中心对齐。
  2. 协调CSS与JS的transform:

    • 将缩放和位移合并到同一个transform属性中,避免样式冲突。
  3. 简化重置逻辑:

    • 点击其他区域时,直接清除路径的transform样式,而非反向计算偏移量。
  4. 修复事件参数错误:

    • 给mouseleave回调添加event参数。

修改后的完整代码

JavaScript

const svg = document.querySelector("svg");
const paths = document.querySelectorAll("svg path");
const popUp = document.querySelector(".pop");  
let selectedPath = null;

function calcCenterMove(element){
    const rect = element.getBoundingClientRect();
    // 元素中心坐标
    const elementCenterX = rect.x + rect.width / 2;
    const elementCenterY = rect.y + rect.height / 2;
    // 屏幕中心坐标
    const screenCenterX = window.innerWidth / 2;
    const screenCenterY = window.innerHeight / 2;
    // 计算需要移动的偏移量(让元素中心对齐屏幕中心)
    const xVector = screenCenterX - elementCenterX;
    const yVector = screenCenterY - elementCenterY;
    return [xVector, yVector];
}

for (const path of paths) {
  path.addEventListener("click", (event) => {
        if (selectedPath === path) return;
        selectedPath = path;

        paths.forEach(otherPath => {
          if (otherPath !== selectedPath) {
            otherPath.style.opacity = "0.4";
            otherPath.style.fill = "lightgray";
            otherPath.style.pointerEvents = "none";
          }
        });
        
        const [xAxisMove, yAxisMove] = calcCenterMove(path);
        // 合并缩放和平移变换
        path.style.transform = `translate(${xAxisMove}px, ${yAxisMove}px) scale(2)`;
        path.classList.add("selected");
        path.style.pointerEvents = "auto";

        document.documentElement.addEventListener("click", captureClick, true);
      });

      function captureClick(event) {
        if (!event.target.classList.contains("selected")) {
          for (const path of paths) {
            path.classList.remove("selected");
            path.style.opacity = 1;
            path.style.pointerEvents = "auto";
            path.style.fill = "gray";
            // 直接清除transform还原位置
            path.style.transform = "";
          }
          selectedPath = null; 
          document.documentElement.removeEventListener("click", captureClick, true); 
        }
      }    

  path.addEventListener("mouseenter", (event) => {
    const pathId = event.target.id; 
    popUp.querySelector("p").textContent = `Content for path: ${pathId}`;
    const pathRect = event.target.getBoundingClientRect();
    popUp.style.top = `${pathRect.top + pathRect.height / 2}px`;
    popUp.style.left = `${pathRect.left + pathRect.width / 2}px`;
    popUp.style.opacity = 0.8;
  });

  path.addEventListener("mouseenter", (event) => {  
    event.target.style.fill = "red";  
  });

  // 添加event参数
  path.addEventListener("mouseleave", (event) => {
    event.target.style.fill = "";
    popUp.style.opacity = 0;  
  });
}

CSS

.hoverme {  
  display: none;  
}

body{
  background: white;
  font-family: 'Open Sans Hebrew', Arial, sans-serif;
  text-align: center;
}
.div-svg{
  float: right;
}
svg{
  position: relative;
  height: auto;
}

svg path {  
  fill: gray;  
  cursor: pointer;
  transition: all 0.3s ease;  
  transform-origin: center center; /* 设置变换原点为中心,确保缩放围绕中心展开 */
}

svg path.selected {
  fill: #007bff;  
  transition: all 0.3s ease;
  /* 这里不再单独设置scale,由JS合并到transform中 */
}

svg path:hover {
  fill: rgba(0, 0, 0, 0.3);  
}

.pop { 
  pointer-events: none;
  position: absolute;
  transition: all 0.3s ease;  
  background-color: lightblue;
}

HTML

<div class="div-svg">
  <svg width="700" height="700" viewBox="0 0 12969 26674">
    <path id="Braga" data-z="32" class="Braga" d="M5329 1730c-66-17-64 0-92 15l-110 113c-121 4-292 156-324 162-42-3-181 2-190-1l-63-42-153 42c-101 28-190 153-246 162-51-1-120-63-171 40-4 70-22 172-11 235-20 5-54 13-72 31l-21 36c-2 67 22 43 26 107l-40 111-33 28-36-11-62-98c-65-6-65 3-114 40-67-40-52-40-108-46l-17-34-39 18 1 73c-47-2-31 4-66-28-40 2-230 40-268 53l-15 35c-82 42-170 47-257 69l65 294v261l66 131v131c58-22 39-9 81-55l27 42c109 12 53-8 132 66l116-33 37 19c30 44 51 107 91 124 77 31 65 60 140 30 45 26 29 11 64 87l-136 68 54 184c22 1 354-18 355-19 43-53 52-56 91-127l199-29 49 55c169 16 391-82 456-69-5 45-7 28 10 72 85-32 174-64 260-95 18-12 31-70 32-70 71-42 91-27 138-55l9-72c200 51 198-5 310 190-62 100 186 171 254 209 28-43 13-30 58-54 34 44 76 73 118 125 13-1 198-149 211-169l33-101c7-14 156-340 157-344 9-53-16-96 14-224l57-58c77 5 27 32 103-17 20-33-6-61 15-92l68 6c18-31 175-267 176-267 47-34 93-52 67-124l-67-130-77-25c-39 47-31 42-60 106-28 5-189 31-190 31-53-16-324-80-356-101-10-157 16-226 65-356-19-23-196-122-214-117-103 32-202 79-336 73 47-93 81-60 123-143 21-42 16-47 19-78 7-67 32-123 89-158-19-156 4-155 96-264l-98-33-163 131-327-66z"/>
    <path id= "Porto" cx="50" cy="50" r="40" data-z="33" class="Porto" d="M2979 3657c58-22 39-9 81-55l27 42c109 12 53-8 132 66l116-33 37 19c30 44 51 107 91 124 77 31 65 60 140 30 45 26 29 11 64 87l-136 68 54 184c22 1 354-18 355-19 43-53 52-56 91-127l199-29 49 55c169 16 391-82 456-69-5 45-7 28 10 72 85-32 174-64 260-95 18-12 31-70 32-70 71-42 91-27 138-55l9-72c200 51 198-5 310 190-62 100 186 171 254 209 28-43 13-30 58-54 34 44 76 73 118 125 13-1 198-149 211-169l33-101c16 22 26 37 54 52 45 24 25-8 53 50l-63 72 17 36c22 24 296 61 184 170 8 70 98 202 161 240l-67 180c60 164-59 157-5 260-80 148-101 93-78 206-81-1-47 33-132-15l-63 52c-4 1-330 118-382 134-200 36 0-77-312 49-60 24-159-10-215-29-99-33-95 35-136 75-61-6-43-9-81 9l-80 56c-66-44-124-64-152-46-34 46-183 240-248 197-88-57-84-35-184-62 29 91-23 107 68 163-6 89 13 55-17 111-120-48-33-85-155-107l19-71c-109-48-10-16-110-91-61 62-65 8-143 50 110 52 39 12 47 139-49 42-41 32-112 63l-90-133-33-19c-73 42-75 33-102 107l-76 28c-96-16-95-48-202-36l-32-26-33-130-32-98v-196l-66-196-153-308c-15-180-51-371-108-541v-131l-32-98-66-98-65-195 33-196z"/>
  </svg>
</div>

<div class="pop">  <p>This is the pop-up content.</p>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:04:51