点击SVG路径无法移至屏幕中心的问题求助
SVG路径点击后无法居中的问题修复
问题原因
- 计算偏移量时错误传入整个SVG元素,而非当前点击的路径元素,导致偏移量基于SVG容器而非目标路径计算。
- 对
getBoundingClientRect()返回值乘以2是多余操作,该方法直接返回元素在屏幕上的实际坐标。 - CSS中
.selected类的transform: scale(2)与JS中设置的translate冲突,叠加后导致位置偏差。 - 重置位置时采用反向计算偏移量的方式,未考虑缩放等叠加变换,无法正确还原。
mouseleave事件回调未传入event参数,导致event.target报错。
修复方案
修正偏移量计算逻辑:
- 将
calcCenterMove的参数改为当前点击的path元素,移除坐标和尺寸的*2操作。 - 计算路径中心到屏幕中心的偏移量,确保路径中心与屏幕中心对齐。
- 将
协调CSS与JS的transform:
- 将缩放和位移合并到同一个transform属性中,避免样式冲突。
简化重置逻辑:
- 点击其他区域时,直接清除路径的transform样式,而非反向计算偏移量。
修复事件参数错误:
- 给
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
相关产品推荐
相关产品推荐

