Text on a Path
by Steve Eberhardt
HTML
<script src="https://unpkg.com/[email protected]/dist/fabric.min.js"></script>
<canvas id="c" width="600" height="300"></canvas>
<div>
<div>
<input type="text" id="textInput" value="" placeholder="Enter text here">
</div>
<div>
<span>Start Offset: </span>
<input type="range" id="startOffsetInput" step="0.25" min="-50" max="50">
<h2 id="offsetAmount">0</h2>
</div>
<div>
<span>Character Spacing: </span>
<input type="range" id="charSpacingInput" step="1" min="-100" max="200">
<h2 id="spacingAmount">0</h2>
</div>
<div>
<span>Font Size: </span>
<input type="range" id="fontSizeInput" step="1" min="10" max="100">
<h2 id="fontSize">0</h2>
</div>
<div>
<span>Text Align: </span>
<button onclick="setProp('textAlign','left')">
Left
</button>
<button onclick="setProp('textAlign','center')">
Center
</button>
<button onclick="setProp('textAlign','right')">
Right
</button>
</div>
<div>
<span>Side: </span>
<button onclick="setProp('pathSide','left')">
Left
</button>
<button onclick="setProp('pathSide','right')">
Right
</button>
</div>
</div>
CSS
canvas {
border: 1px solid #999;
}
div > * {
display: inline-block;
}
h2 {
width: 30px;
margin: 0 20px 0 0;
}
div > div {
display: block;
padding: 4px;
}
input {
margin-top: 10px;
}
JavaScript
var canvas = new fabric.Canvas('c');
fabric.Object.prototype.noScaleCache = false;
var pathString = "M 75 0 A 10 10 0 0 1 75 -150 A 1 1 0 0 1 75 0 Z";
var path = new fabric.Path(pathString, {
strokeWidth: 2,
stroke: 'red',
left: 100,
top: 50,
fill: 'transparent',
scaleX: 1,
strokeUniform: true
});
var path2 = new fabric.Path('M 0 0 Q 180 0 180 -101.25 Q 180 -180 90 -180 Q 0 -180 0 -112.5 Q 0 -45 78.75 -45 Q 135 -45 146.25 -90', {
strokeWidth: 2,
stroke: 'red',
left: 300,
top: 50,
fill: 'transparent'
});
var text = new fabric.Text('Text on a Path', {
path: path,
fontSize: 30,
left: 50,
top: 50,
textAlign: 'center',
pathStartOffset: 0,
pathSide: 'left'
});
var text2 = new fabric.Text('Text on a Path', {
path: path2,
fontSize: 30,
left: 300,
top: 50,
pathStartOffset: 0,
textAlign: 'center',
pathSide: 'left'
});
canvas.add(text);
canvas.add(text2);
document.getElementById('startOffsetInput').addEventListener("input", function() {
setProp('pathStartOffset', parseInt(this.value));
document.getElementById('offsetAmount').innerHTML = this.value;
});
document.getElementById('charSpacingInput').addEventListener("input", function() {
setProp('charSpacing', parseInt(this.value));
document.getElementById('spacingAmount').innerHTML = this.value;
});
document.getElementById('fontSizeInput').addEventListener("input", function() {
setProp('fontSize', parseInt(this.value));
document.getElementById('fontSize').innerHTML = this.value;
});
document.getElementById('textInput').addEventListener("input", function() {
setProp('text', this.value);
});
function setProp(prop, value) {
var objects = canvas.getObjects();
objects.forEach(function(obj) {
obj.set(prop, value);
canvas.renderAll();
});
}
canvas.on({
'object:scaling': function(e) {
applyScaling(e.target);
}
})
function applyScaling(obj) {
if (obj.type === "text" && obj.path) {
path = obj.path;
path.set({
scaleX:...