我正在尝试基于圆形路径实现文本曲率,类似于 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() 应用转换以在圆中对齐。
我无法计算起始字符和枢轴坐标之间的距离。类似于
任何人都可以帮我解决这个问题或推荐最好的文本弯曲方法吗?