如何在 Javascript 中沿圆形路径实现曲线 SVG 文本?

问题描述 投票:0回答:0

我正在尝试基于圆形路径实现文本曲率,类似于 Canva 所做的。

我正在用 SVG 文本和路径实现它。因为该项目是用 Raphael js 编写的并且基于 SVG,所以我不得不使用 svg 而不是 html canvas 或像 circletype js 这样的 js 库。我目前正在研究原型。这是代码:

var paper = Raphael("paper");

document.getElementById("generate").addEventListener("click", function () {
  var radius = document.querySelector("#radius").value;
  var direction = document.querySelector("#direction").value;
  var pivotX = document.querySelector("#x").value;
  var pivotY = document.querySelector("#y").value;
  var circleCenter = calculateCenterOfCircle(parseFloat(pivotX), parseFloat(pivotY), parseFloat(radius));
var path = paper.path(getPath(circleCenter.cx, circleCenter.cy, parseFloat(radius))).attr("stroke", "#CCC")

var message = "Curve Text";
textOnPath(message, path, 16, 1.5 );
 //for pivot point
  paper.circle(pivotX, pivotY, 2).attr({fill: "red"});
  
});


function getPath(cx, cy, r)
 {
    return `M ${cx} ${cy}
    m -${r}, 0
    a ${r},${r} 0 1,1 ${(r * 2)},0
    a ${r},${r} 0 1,1 -${(r * 2)},0
    `;
 }

function calculateCenterOfCircle(x, y, r, direction = 'down')
{
    return {
        cx: x,
        cy: direction == 'down' ? y + r : y - r,
    }
}

function angle(v1, v2) {
   ang = Math.atan2(v2.y - v1.y, v2.x - v1.x);
   return {
      radians: ang,
      degrees: ang * 180 / Math.PI
   };
}

function textOnPath(message, path, fontSize, letterSpacing) {
    // if fontSize or letterSpacing are undefined, they are calculated to fill the path
    // 10% of fontSize is usually good for manual letterspacing
    var letters = [], places = [], messageLength = 0;
    for (var c=0; c < message.length; c++) {

        var letter = paper.text(180, 100, message[c]).attr({"text-anchor" : "middle"});
        var character = letter.attr('text');
        var kern = 0;
        letters.push(letter);
        messageLength = messageLength ? messageLength : letter.getBBox().width;
        messageLength += kern;
        places.push(messageLength);
        //spaces get a width of 0, so set min at 4px
        messageLength += Math.max(4.5, letter.getBBox().width);
    }

    if( !letterSpacing ){
        letterSpacing = letterSpacing || path.getTotalLength() /  messageLength;
    }
    fontSize = fontSize || 10 * letterSpacing;
    for (c = 0; c < letters.length; c++) {
        letters[c].attr("font-size", fontSize + "px");
        p = path.getPointAtLength(places[c] * letterSpacing);
        var pT = path.getPointAtLength(places[c]);
        var pp1 = path.getPointAtLength(places[c]*letterSpacing-0.1),
            pp2 = path.getPointAtLength(places[c]*letterSpacing+0.1),
            rotate = 'R' + angle(pp1, pp2).degrees +','+p.x+','+p.y;
        letters[c].attr({ x: p.x, y: p.y, transform: rotate });
    }
    return letters;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js"></script>
<div id="paper">
</div>
<label for="radius">Enter Radius:</label>
<input type="text" id="radius" placeholder="Enter radius" value="100" /> 
<br /> <br />
<!-- Mid point of the text -->
<label for="x">Pivot point (X):</label>
<input type="text" value="180"id="x" />
<br /> <br />
<label for="y">Pivot point (Y):</label>
<input type="text" value="100"id="y" /> <br /> <br />
<label for="direction">Select Direction: </label>
<select id="direction">
  <option value="up">Up</option>
  <option value="down">Down</option>
</select>
<button id="generate">Generate</button>

总结代码,使用提供的枢轴坐标和半径计算圆形路径。将计算枢轴坐标并将其位于基于文本尺寸的中心。文本中的每个字符都被转换为一个元素,并根据 getPointAtLength() 应用转换以在圆中对齐。

我无法计算起始字符和枢轴坐标之间的距离。类似于

上startOffset属性的值

任何人都可以帮我解决这个问题或推荐最好的文本弯曲方法吗?

javascript css svg raphael
© www.soinside.com 2019 - 2024. All rights reserved.