fabric.js: Curved Text

Works with FabricJS 1.7.x.

by Anuraj MS

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<table>
	<tr>
		<td>Text</td>
		<td><input type="text" id="text" value="Lorem ipsum di samet"></td>
	</tr>
	<tr>
		<td>Diameter</td>
		<td><input type="range" id="diameter" min="100" max="2500" value="250" step="1"></td></tr>
	<tr>
		<td>Font size</td>
		<td><input type="range" id="fontSize" min="8" max="100" value="24" step="1"></td>
	</tr>
	<tr>
		<td>Kerning</td>
		<td><input type="range" id="kerning" min="-10" max="10" value="0" step="1"></td>
	</tr>
	<tr>
		<td>Flip</td>
		<td><input type="checkbox" id="flip" value="1"></td>
	</tr>
	<tr>
		<td></td>
		<td><button type="button" id="newObject">Add to Canvas</button></td>
	</tr>
</table>

<hr>

<div id="canvasContainer">
	<canvas id="c" width="450" height="450"></canvas>
</div>

CSS

body, input, button {
	font: 12pt Arial, Helvetica;
}

#canvasContainer {
	background-image: url(data:image/gif;base64,R0lGODlhCgAKAIAAAOLi4v///yH5BAAHAP8ALAAAAAAKAAoAAAIRhB2ZhxoM3GMSykqd1VltzxQAOw==);
	border: 2px solid #ccc;
	display: inline-block;
}

input[type=range], input[type=text] {
	width: 200px;
}

JavaScript

(function(fabric) {

/*
 * CurvedText object for fabric.js
 * @author Arjan Haverkamp (av01d)
 * @date January 2018
 */

fabric.CurvedText = fabric.util.createClass(fabric.Object, {
	type: 'curved-text',
  editable:true,
	diameter: 250,
	kerning: 0,
	text: '',
	flipped: false,
	fill: '#000',
	fontFamily: 'Times New Roman',
	fontSize: 24, // in px
	fontWeight: 'normal',
	fontStyle: '', // "normal", "italic" or "oblique".
 	cacheProperties: fabric.Object.prototype.cacheProperties.concat('diameter', 'kerning', 'flipped', 'fill', 'fontFamily', 'fontSize', 'fontWeight', 'fontStyle', 'strokeStyle', 'strokeWidth'),
	strokeStyle: null,
	strokeWidth: 0,

	initialize: function(text, options) {
		options || (options = {});
		this.text = text;

		this.callSuper('initialize', options);
		this.set({lockUniScaling: true,editable:true});

		// Draw curved text here initially too, while we need to know the width and height.
		var canvas = this.getCircularText();
		this._trimCanvas(canvas);
		this.set('width', canvas.width);
		this.set('height', canvas.height);
	},

	_getFontDeclaration: function()
	{
		return [
			// node-canvas needs "weight style", while browsers need "style weight"
			(fabric.isLikelyNode ? this.fontWeight : this.fontStyle),
			(fabric.isLikelyNode ? this.fontStyle : this.fontWeight),
			this.fontSize + 'px',
			(fabric.isLikelyNode ? ('"' + this.fontFamily + '"') : this.fontFamily)
		].join(' ');
	},

	_trimCanvas: function(canvas)
	{
		var ctx = canvas.getContext('2d'),
			w = canvas.width,
			h = canvas.height,
			pix = {x:[], y:[]}, n,
			imageData = ctx.getImageData(0,0,w,h),
			fn = function(a,b) { return a-b };

		for (var y = 0; y < h; y++) {
			for (var x = 0; x < w; x++) {
				if (imageData.data[((y * w + x) * 4)+3] > 0) {
					pix.x.push(x);
					pix.y.push(y);
				}
			}
		}
		pix.x.sort(fn);
		pix.y.sort(fn);
		n = pix.x.length-1;

		w = pix.x[n] - pix.x[0];
		h = pix.y[n] - pix.y[0];
		var cut = ctx.getImageData(pix.x[0], pix.y[0], w,...