Live textarea foreignObject SVG to Canvas
by Isaiah Odhner
December 04, 2019
HTML
<textarea xmlns="http://www.w3.org/1999/xhtml" style="border: 0; width: 100px; height: 150px; overflow: hidden;">
Here is a paragraph that requires word wrap.
This is a <textarea>.
</textarea>
CSS
textarea,
canvas {
position: absolute;
top: 15px;
left: 15px;
transform: scale(3);
transform-origin: left top;
}
canvas {
pointer-events: none;
z-index: -1;
image-rendering: crisp-edges;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
}
textarea {
color: transparent !important;
background: transparent !important;
caret-color: black;
resize: none;
}
svg {
opacity: 0;
pointer-events: none;
}
JavaScript
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("version", 1.1);
svg.setAttribute("width", 100);
svg.setAttribute("height", 150);
var foreignObject = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
foreignObject.setAttribute("x", 0);
foreignObject.setAttribute("y", 0);
foreignObject.setAttribute("width", 100);
foreignObject.setAttribute("height", 150);
svg.append(foreignObject);
var edit_textarea = document.querySelector("textarea");
var mirror_textarea = edit_textarea.cloneNode(false);
foreignObject.append(mirror_textarea);
var canvas = document.createElement("canvas");
document.body.append(canvas);
var ctx = canvas.getContext("2d");
canvas.width = 100;
canvas.height = 150;
canvas.style.outline = "5px solid lightgray";
var update = ()=> {
requestAnimationFrame(()=> {
edit_textarea.scrollTop = 0; // prevent scrolling edit textarea to keep in sync
});
while (mirror_textarea.firstChild) {
mirror_textarea.removeChild(mirror_textarea.firstChild);
}
mirror_textarea.appendChild(document.createTextNode(edit_textarea.value));
var svg_source = new XMLSerializer().serializeToString(svg);
//var blob = new Blob([svg_source], {type: "image/svg+xml;charset=utf-8"});
//var blob_url = URL.createObjectURL(blob);
var data_url = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg_source);
var img = new Image();
img.onload = ()=> {
//URL.revokeObjectURL(blob_url);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
canvas.style.outlineColor = "lime";
ctx.getImageData(0, 0, 1, 1);
};
img.onerror = (e)=> {
//URL.revokeObjectURL(blob_url);
canvas.style.outlineColor = "red";
console.log("failed to load image", e);
};
img.src = data_url; // blob_url;
};
edit_textarea.addEventListener("input", update);
update();