SVG转Canvas实现蓝点随人体模型边缘动态缩放的简易方案问询
可行!实现SVG转Canvas并同步缩放蓝色圆点
核心思路
- 利用SVG的
viewBox获取原始尺寸,计算统一缩放比例,保证人体模型不变形 - 单独提取蓝色圆点的坐标与半径,应用相同缩放因子,确保圆点始终贴合人体边缘
- 将SVG转为DataURL加载到Canvas,叠加绘制缩放后的圆点实现精准控制
完整实现代码
HTML结构
<div> <label>输入目标高度(px):</label> <input type="number" id="heightInput" value="842" min="100" max="2000"> <button onclick="updateCanvas()">更新尺寸</button> </div> <canvas id="humanCanvas"></canvas>
JavaScript逻辑
// 你的原始SVG字符串 const svgString = ` <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 595.3 841.9" style="enable-background:new 0 0 595.3 841.9;" xml:space="preserve"> <style type="text/css"> .st0 { fill: #040305; } .st1 { fill: #5E459C; } </style> <g> <path class="st0" d="M322.2,837h143.3c19.6,0,37.1-15.6,39.1-34.7c7.8-77.7-7.9-175.3-22.6-211.1c-4.6-11.1-10.8-21.3-17.4-32.2 c-18-29.5-38.3-63-36.2-129.5c2-62,37.1-104.1,57.9-123.7c10.5-9.9,22-28.1,22.6-44.9c1.7-48.9-12.9-83.6-25.4-104.1 c-9.2-15.2-29.6-24.1-44.6-25.8c-17.8-2.1-50.7-7.6-71.1-20.7c-14.8-9.4-19-28.3-19.8-43c4.7-6,7.7-12.7,7.7-20.2 c0-23.1-26-41.1-59.2-41.1c-33.2,0-59.2,18.1-59.2,41.1c0,7.6,3.1,14.5,8,20.6c-0.9,14.6-5.1,33.2-19.9,42.5 c-20.4,13-53.3,18.6-71.1,20.7c-15.4,1.8-35.7,11.3-44.6,25.9c-12.5,20.5-27,55.2-25.4,104c0.6,16.8,12.1,35.1,22.6,44.9 c20.8,19.6,56,61.7,57.9,123.7c2.1,66.5-18.3,100-36.3,129.6c-6.6,10.8-12.8,21.1-17.4,32.1c-14.7,35.8-30.5,133.4-22.6,211.1 c1.9,19.1,19.5,34.7,39.1,34.7h103.8 M296.5,32.3c19.8,0,32.9,8.9,32.9,14.8s-13.1,14.8-32.9,14.8c-19.8,0-32.9-8.9-32.9-14.8 S276.7,32.3,296.5,32.3z M253.3,836.9h47 M473.6,799.1c-0.4,3.3-4.4,6.6-8.1,6.6H127.7c-3.7,0-7.7-3.3-8.1-6.6 c-7.2-71.8,7.3-164.1,20.5-196.1c3.6-8.8,9-17.6,15.2-27.9c19.2-31.6,43.1-70.9,40.7-146.7c-2.3-73.2-43.4-122.6-67.8-145.4 c-6.5-6.1-12.6-17.1-12.7-23.2c-1.4-41.1,10.6-69.9,20.8-86.8c2.5-4.1,13-10.1,21.6-11.1c24.9-3,59.8-9.8,84.2-25.3 c19.7-12.6,28.4-32.8,32.1-51.3c6.8,1.9,14.3,3,22.2,3c8.1,0,15.6-1.1,22.6-3c3.6,18.5,12.3,38.7,32.1,51.4 c24.4,15.6,59.3,22.4,84.2,25.3c8.9,1.1,19.1,6.9,21.6,11.1c10.3,16.9,22.2,45.7,20.8,86.8c-0.2,6-6.3,17.1-12.8,23.2 c-24.3,22.9-65.4,72.2-67.7,145.4c-2.4,75.9,21.5,115.1,40.7,146.7c6.2,10.2,11.6,19.1,15.2,27.9 C466.3,635.1,480.8,727.4,473.6,799.1z" /> </g> <circle class="st1" cx="100.1" cy="253.2" r="15.4" /> <circle class="st1" cx="494.1" cy="253.2" r="15.4" /> <circle class="st1" cx="144.1" cy="149.2" r="15.4" /> <circle class="st1" cx="455.1" cy="149.2" r="15.4" /> <circle class="st1" cx="147.1" cy="329.2" r="15.4" /> <circle class="st1" cx="180.1" cy="450.2" r="15.4" /> <circle class="st1" cx="161.1" cy="532.2" r="15.4" /> <circle class="st1" cx="433.1" cy="532.2" r="15.4" /> <circle class="st1" cx="413.1" cy="450.2" r="15.4" /> <circle class="st1" cx="446.1" cy="329.2" r="15.4" /> <circle class="st1" cx="110.1" cy="659.2" r="15.4" /> <circle class="st1" cx="103.1" cy="797.2" r="15.4" /> <circle class="st1" cx="489.1" cy="797.2" r="15.4" /> <circle class="st1" cx="483.1" cy="659.2" r="15.4" /> </svg> `; // 解析SVG提取关键数据 const parser = new DOMParser(); const svgDoc = parser.parseFromString(svgString, "image/svg+xml"); const viewBox = svgDoc.querySelector("svg").getAttribute("viewBox").split(" ").map(Number); const originalWidth = viewBox[2]; const originalHeight = viewBox[3]; const circles = Array.from(svgDoc.querySelectorAll("circle")).map(c => ({ cx: parseFloat(c.getAttribute("cx")), cy: parseFloat(c.getAttribute("cy")), r: parseFloat(c.getAttribute("r")) })); // 获取Canvas上下文 const canvas = document.getElementById("humanCanvas"); const ctx = canvas.getContext("2d"); // 初始化渲染 updateCanvas(); function updateCanvas() { const targetHeight = parseInt(document.getElementById("heightInput").value); const scale = targetHeight / originalHeight; const targetWidth = originalWidth * scale; // 设置Canvas尺寸 canvas.width = targetWidth; canvas.height = targetHeight; ctx.clearRect(0, 0, canvas.width, canvas.height); // 加载并绘制缩放后的人体模型 const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0, targetWidth, targetHeight); // 绘制同步缩放的蓝色圆点 ctx.fillStyle = "#5E459C"; circles.forEach(c => { ctx.beginPath(); ctx.arc(c.cx * scale, c.cy * scale, c.r * scale, 0, Math.PI * 2); ctx.fill(); }); }; img.src = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svgString)))}`; }
关键细节说明
- 宽高比保持:以输入的高度为基准,按SVG原始宽高比计算目标宽度,避免人体模型拉伸变形
- 圆点精准缩放:提前提取所有圆点的坐标和半径,应用与人体模型相同的缩放因子,确保位置和大小完全同步
- SVG转Canvas:通过DataURL将SVG转为图片资源加载,再叠加绘制圆点,既保留SVG的矢量清晰度,又实现对圆点的独立控制
内容的提问来源于stack exchange,提问作者Azim kolbackup
相关产品推荐
相关产品推荐

