--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>String Linear Interpolation Example</title>
+ <meta charset="utf-8" />
+ <style>
+ input[type=text] {
+ width: 40%;
+ display: table-cell;
+ margin: 2.5%;
+ text-align: center;
+ }
+ </style>
+ <script type="text/javascript" src="string-lerp.js"></script>
+ <script>
+ function update (p) {
+ var a = document.getElementById("a");
+ var b = document.getElementById("b");
+ var e = document.getElementById("text");
+ e.textContent = stringLerp.lerp(a.value, b.value, p);
+ }
+ </script>
+ </head>
+ <body onload="update(0.5)">
+ <div style="width: 70%; margin: 3em auto; column-spacing: 10%;">
+ <input type="text" id="a" value="source text">
+ <input type="text" id="b" value="target text">
+ </div>
+ <div id="text" style="font-size: 3em; text-align: center;"></div>
+ <input type="range" value=0.5 max=1.00 step=0.00390625 oninput="update(this.value);"
+ style="width: 80%; margin: 3em auto; display: block;">
+ </body>
+</html>
--- /dev/null
+(function (exports) {
+ "use strict";
+
+ var MAX_MATRIX_SIZE = 256 * 256;
+
+ function repeat(n, v) {
+ var r = [];
+ while (n--)
+ r.push(v);
+ return r;
+ }
+
+ function createMatrix(i, j) {
+ var m = [];
+ while (i--)
+ m.push(repeat(j, 0));
+ return m;
+ }
+
+ function levenshteinMatrix(s, t) {
+ /** Calculate the Levenshtein edit distance matrix for two strings
+
+ // Following http://en.wikipedia.org/wiki/Levenshtein_distance
+ */
+ var m = s.length + 1;
+ var n = t.length + 1;
+ var d = createMatrix(m, n);
+ var i, j;
+ for (i = 1; i < m; ++i)
+ d[i][0] = i;
+ for (j = 1; j < n; ++j)
+ d[0][j] = j;
+ for (j = 1; j < n; ++j)
+ for (i = 1; i < m; ++i)
+ if (s[i - 1] === t[j - 1])
+ d[i][j] = d[i - 1][j - 1];
+ else
+ d[i][j] = 1 + Math.min(d[i - 1][ j ],
+ d[ i ][j - 1],
+ d[i - 1][j - 1]);
+ return d;
+ }
+
+ function editPath(m, s, t) {
+ var path = []
+ var i = s.length;
+ var j = t.length;
+ while (i || j) {
+ var sub = (i && j) ? m[i - 1][j - 1] : Infinity;
+ var del = i ? m[i - 1][j] : Infinity;
+ var ins = j ? m[i][j - 1] : Infinity;
+ if (sub <= ins && sub <= del) {
+ if (m[i][j] !== m[i - 1][j - 1])
+ path.push(["sub", i - 1, t[j - 1]]);
+ --i; --j;
+ } else if (ins <= del) {
+ path.push(["ins", i, t[j - 1]]);
+ --j;
+ } else {
+ path.push(["del", i - 1]);
+ --i;
+ }
+ }
+ return path;
+ }
+
+ function applyEdits(edits, s, t) {
+ var i;
+ for (i = 0; i < edits.length; ++i) {
+ var edit = edits[i];
+ switch (edit[0]) {
+ case "sub":
+ s = s.slice(0, edit[1]) + edit[2] + s.slice(edit[1] + 1);
+ break;
+ case "ins":
+ s = s.slice(0, edit[1]) + edit[2] + s.slice(edit[1]);
+ break;
+ case "del":
+ s = s.slice(0, edit[1]) + s.slice(edit[1] + 1);
+ break;
+ }
+ }
+ return s;
+ }
+
+ function slowLerp(a, b, p) {
+ var m = levenshteinMatrix(a, b);
+ var edits = editPath(m, a, b);
+ var partial = edits.slice(0, Math.round(p * edits.length));
+ return applyEdits(partial, a, b);
+ }
+
+ function fastLerp(a, b, p) {
+ var alen = Math.round(a.length * p);
+ var blen = Math.round(b.length * p);
+ return b.substring(0, blen) + a.substring(alen, a.length);
+ }
+
+ function lerp(a, b, p) {
+ a = a.toString();
+ b = b.toString();
+ var n = a.length * b.length;
+ return (n && n < MAX_MATRIX_SIZE)
+ ? slowLerp(a, b, p)
+ : fastLerp(a, b, p);
+ }
+
+ exports.levenshteinMatrix = levenshteinMatrix;
+ exports.editPath = editPath;
+ exports.fastLerp = fastLerp;
+ exports.slowLerp = slowLerp;
+ exports.applyEdits = applyEdits;
+ exports.lerp = lerp;
+
+})(typeof exports === "undefined" ? (this.stringLerp = {}) : exports);