JSFiddle - React, Tailwind, and code Playground
by Scott Kaye
HTML
<textarea>Test</textarea>
<canvas id="c"></canvas>
CSS
textarea {
width: 300px;
height: 100px;
}
canvas {
position: absolute;
top: 8px;
left: 8px;
pointer-events: none;
}
div {
background: red;
animation: fade 2s ease 1 forwards;
}
@keyframes fade {
to { opacity: 0 }
}
JavaScript
// Element prototype extension pattern from
// http://lea.verou.me/2015/04/idea-extending-native-dom-prototypes-without-collisions/
// Thank you!
console.clear();
const CaretTools = function(element) {
this.element = element;
};
CaretTools.prototype = {
getTextDimensions: function(str) {
let clone = document.createElement("div");
let style = window.getComputedStyle(this.element);
clone.style.maxWidth = style.width;
clone.style.display = "inline-block";
clone.style.position = "absolute";
clone.style.top = 0;
clone.style.left = 0;
clone.style.pointerEvents = "none";
clone.style.font = style.font;
clone.style.lineHeight = style.fontSize;
clone.innerText = str;
console.log(clone);
document.body.appendChild(clone);
let dims = {
width: clone.clientWidth,
height: clone.clientHeight
};
//document.body.removeChild(clone);
return dims;
},
getPoint: function() {
let pos = this.element.selectionStart;
let before = this.element.value.substring(0, pos);
let totalSize = this.getTextDimensions(before);
let fontSize = parseFloat(window.getComputedStyle(this.element).fontSize.match(/[0-9.]+/));
let line = Math.round(totalSize.height / fontSize);
let x = totalSize.width;
let y = totalSize.height - (fontSize / 2);
//get linesize for x value, not totalsize
console.log(x, y);
return {x, y};
}
};
Object.defineProperty(HTMLTextAreaElement.prototype, "caretTools", {
get: function() {
Object.defineProperty(this, "caretTools", {
value: new CaretTools(this)
});
return this.caretTools;
},
configurable: true,
writeable: false
});
var canvas = document.getElementById("c");
canvas.width = 305;
canvas.height = 105;
var context = canvas.getContext("2d");
var area = document.querySelector("textarea");
area.addEventListener("input", () => {
var point = area.caretTools.getPoint();
console.log(point);
...