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

如何在运行时将带文本变形效果的Canvas转换为SVG图像

将Canvas文本变形效果转换为SVG格式(解决清晰度问题)

当前通过Canvas实现的文本变形效果(输入文本并适配桥形)存在图像清晰度不足的问题,我们可以将其转换为SVG矢量格式来解决,以下是具体实现方案:

实现思路

原Canvas代码的核心逻辑是:先将文本绘制到离屏Canvas,再逐列截取1像素宽的文本片段,按照正弦曲线调整每列的高度后重新绘制,从而实现桥形变形。我们将用SVG复刻这一逻辑,利用SVG的矢量特性保证清晰度。

完整实现代码

HTML结构

<div>
  <label>文本: <input type="text" id="iText" value="BRIDGE TEXT"></label>
  <label>弯曲度: <input type="range" id="iCurve" min="0" max="100" value="50"> <span id="vCurve">50</span></label>
  <label>Y偏移: <input type="range" id="iOffset" min="0" max="100" value="0"> <span id="vOffset">0</span></label>
  <label>文本高度: <input type="range" id="iHeight" min="20" max="100" value="64"> <span id="vHeight">64</span></label>
  <label>底部位置: <input type="range" id="iBottom" min="64" max="200" value="128"> <span id="vBottom">128</span></label>
</div>
<svg id="demo" width="600" height="200"></svg>

JavaScript代码

const svg = document.getElementById('demo');
const w = parseInt(svg.getAttribute('width'));
const h = parseInt(svg.getAttribute('height'));
let angleSteps = 180 / w;

// 创建隐藏的模板文本元素
const templateText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
templateText.setAttribute('font-family', 'impact');
templateText.setAttribute('text-anchor', 'middle');
templateText.setAttribute('dominant-baseline', 'hanging');
templateText.setAttribute('visibility', 'hidden');
templateText.setAttribute('x', w / 2);
templateText.setAttribute('y', 0);
svg.appendChild(templateText);

function renderBridgeText() {
  const curve = parseInt(document.getElementById('iCurve').value, 10);
  const offsetY = parseInt(document.getElementById('iOffset').value, 10);
  const textHeight = parseInt(document.getElementById('iHeight').value, 10);
  const bottom = parseInt(document.getElementById('iBottom').value, 10);
  const text = document.getElementById('iText').value;

  // 更新显示值
  document.getElementById('vCurve').textContent = curve;
  document.getElementById('vOffset').textContent = offsetY;
  document.getElementById('vHeight').textContent = textHeight;
  document.getElementById('vBottom').textContent = bottom;

  // 更新模板文本的字体大小
  templateText.setAttribute('font-size', textHeight);
  templateText.textContent = text;

  // 清除之前的变形文本元素
  const existingGroups = svg.querySelectorAll('.text-column');
  existingGroups.forEach(g => g.remove());
  const existingClips = svg.querySelectorAll('clipPath');
  existingClips.forEach(c => c.remove());

  // 逐列生成变形的文本片段
  for (let i = 0; i < w; i++) {
    const y = bottom - curve * Math.sin(i * angleSteps * Math.PI / 180);
    const scaleY = y / textHeight;

    // 创建裁剪路径,截取当前列的文本
    const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
    clipPath.setAttribute('id', `clip-${i}`);
    const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
    rect.setAttribute('x', i);
    rect.setAttribute('y', offsetY);
    rect.setAttribute('width', 1);
    rect.setAttribute('height', textHeight);
    clipPath.appendChild(rect);
    svg.appendChild(clipPath);

    // 创建文本组,应用裁剪和缩放
    const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
    group.setAttribute('class', 'text-column');
    group.setAttribute('clip-path', `url(#clip-${i})`);
    group.setAttribute('transform', `translate(0, ${offsetY * (1 - scaleY)}) scale(1, ${scaleY})`);

    // 复制模板文本到组中
    const textClone = templateText.cloneNode(true);
    textClone.setAttribute('visibility', 'visible');
    group.appendChild(textClone);
    svg.appendChild(group);
  }
}

// 绑定事件
document.getElementById('iCurve').addEventListener('input', renderBridgeText);
document.getElementById('iOffset').addEventListener('input', renderBridgeText);
document.getElementById('iHeight').addEventListener('input', renderBridgeText);
document.getElementById('iBottom').addEventListener('input', renderBridgeText);
document.getElementById('iText').addEventListener('input', renderBridgeText);

// 初始渲染
renderBridgeText();

说明

  • SVG使用矢量元素绘制,无论缩放多少倍都能保持清晰,彻底解决Canvas位图的清晰度问题
  • 核心逻辑与原Canvas代码一致:逐列处理文本,通过缩放高度实现正弦曲线变形
  • 使用隐藏的模板文本元素避免重复设置字体属性,提升效率
  • 所有输入控件的交互逻辑与原代码保持一致,用户体验不变

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:11:12