Live contentEditable foreignObject SVG to Canvas

by Isaiah Odhner

HTML

<svg width="100" height="150" id="test-svg" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <foreignObject x="0" y="0" width="100" height="150" >
      <div xmlns="http://www.w3.org/1999/xhtml" contenteditable>
          Here is a <strong>paragraph</strong> that requires <em>word wrap</em>.
					This is <code>contentEditable</code>.
			</div>
  </foreignObject>
</svg>

CSS

svg,
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;
}

svg * {
	color: transparent !important;
  background: transparent !important;
	caret-color: black;
}

JavaScript

var svg = document.getElementById("test-svg");

var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");

canvas.width = svg.clientWidth;
canvas.height = svg.clientHeight;
canvas.style.outline = "5px solid lightgray";

var last_svg_source;
setInterval(()=> {

	var svg_source = new XMLSerializer().serializeToString(svg);
	if (svg_source === last_svg_source) {
		return;
	}
  var blob = new Blob([svg_source], {type: "image/svg+xml;charset=utf-8"});
  var blob_url = URL.createObjectURL(blob);
	
	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";
	};
	img.onerror = (e)=> {
    URL.revokeObjectURL(blob_url);
		canvas.style.outlineColor = "red";
		console.log("failed to load image", e);
	};
	img.src = blob_url;
	
	last_svg_source = svg_source;

}, 10);