// var parser = new DOMParser(),
// doc = parser.parseFromString('', 'text/xml'),
// deltas = parser.parseFromString('', 'text/xml'),
// canvas = document.getElementById('canvas'),
// ctx = canvas.getContext('2d'),
// points = [];
// var glyf = font.querySelector('glyf'),
// gvar = font.querySelector('gvar'),
// glyphs = glyf.querySelectorAll('TTGlyph'),
// variatonss = gvar.querySelectorAll('glyphVariations');
// glyphs.forEach((glyph) => { console.log(glyph) });
// doc.childNodes.forEach((glyph) => {
// if (glyph.nodeName.toLowerCase() == 'ttglyph') {
// glyph.childNodes.forEach((contour) => {
// if (contour.nodeName.toLowerCase() == 'contour') {
// ctx.save();
// ctx.transform(1, 0, 0, -1, 200, 800);
// ctx.beginPath();
// contour.childNodes.forEach((pt, k) => {
// if (pt.nodeName.toLowerCase() == 'pt') {
// var x = parseInt(pt.attributes.x.value),
// y = parseInt(pt.attributes.y.value);
// if (k > 0) {
// ctx.lineTo(x, y);
// } else {
// ctx.moveTo(x, y);
// }
// points.push([x, y]);
// }
// });
// ctx.closePath();
// ctx.stroke();
// ctx.restore();
// }
// });
// }
// });
// console.log(deltas)
// deltas.querySelectorAll('glyphVariations').forEach((glyphVariations) => {
// glyphVariations.querySelectorAll('tuple').forEach((tuple) => {
// tuple.querySelectorAll('delta').forEach((delta) => {
// var pt = delta.attributes.pt.value,
// x = parseInt(delta.attributes.x.value),
// y = parseInt(delta.attributes.y.value);
// ctx.save();
// ctx.transform(1, 0, 0, -1, 200, 800);
// ctx.beginPath();
// ctx.moveTo(points[pt][0], points[pt][1]);
// ctx.lineTo(points[pt][0] + x, points[pt][1] + y);
// ctx.stroke();
// ctx.beginPath();
// ctx.arc(points[pt][0] + x, points[pt][1] + y, 2, 0, 2 * Math.PI, false);
// ctx.fill();
// ctx.restore();
// });
// });
// });
var font;
class Font {
constructor(xml) {
this.xml = xml;
let parser = new DOMParser();
this.dom = parser.parseFromString(xml, 'text/xml');
}
table(name) { return this.dom.querySelector(name) };
glyphs() { return this.table('glyf').querySelectorAll('TTGlyph'); };
glyph(name) { return this.table('glyf').querySelector(`TTGlyph[name="${name}"]`); };
variations() { return this.table('fvar'); };
glyphVariations() { return this.table('gvar').querySelectorAll('glyphVariations'); };
glyphVariation(name) { return this.table('gvar').querySelector(`glyphVariations[glyph="${name}"]`); };
delta(name, point) { return this.glyphVariation(name).querySelectorAll(`delta[pt="${point}"]`); };
contours(name) { return this.glyph(name).querySelectorAll('contour'); };
}
function drawGlyph(name, font) {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
// deltaCtx = canvas.getContext('2d'),
points = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
var glyph = font.glyph(name);
var xmin = glyph.getAttribute('xMin'),
xmax = glyph.getAttribute('xMax'),
ymin = glyph.getAttribute('yMin'),
ymax = glyph.getAttribute('yMax'),
glyphWidth = xmax - xmin,
glyphHeight = ymax - ymin;
console.log(glyphWidth, glyphHeight, xmin, xmax, ymin, ymax);
prepareCanvas = (ctx) => {
ctx.transform(1, 0, 0, -1, 0, canvas.height);
ctx.translate((canvas.width - glyphWidth) / 2 - xmin, (canvas.height - glyphHeight) / 2);
};
// console.log(glyph.getAttribute('xMin'), glyglyph.getAttribute('xMax') - glyph.getAttribute('xMin');ph.getAttribute('xMax'));
font.contours(name).forEach(contour => {
ctx.save();
prepareCanvas(ctx);
// deltaCtx.save();
// prepareCanvas(deltaCtx);
var start = [];
var curveBuffer = [];
var sections = [];
contour.querySelectorAll('pt').forEach((point, k) => {
var x = parseInt(point.getAttribute('x')),
y = parseInt(point.getAttribute('y')),
onPath = (point.getAttribute('on') === "1") ? true : false;
ctx.beginPath();
ctx.arc(x, y, 3, 0, 2 * Math.PI, false);
if (onPath) {
ctx.fill();
} else {
ctx.stroke();
}
ctx.closePath();
ctx.font = "14px monospace";
ctx.fillStyle = "red";
ctx.fillText(k, 5 + x, 5 + y);
if (!onPath) {
if (curveBuffer.length > 0) {
curveBuffer.push(curveBuffer[0] + ((x - curveBuffer[0]) / 2), curveBuffer[1] + ((y - curveBuffer[1]) / 2));
sections.push(curveBuffer);
curveBuffer = [];
}
curveBuffer.push(x, y);
} else if (curveBuffer.length > 0) {
curveBuffer.push(x, y);
sections.push(curveBuffer);
curveBuffer = [];
} else {
sections.push([x, y]);
}
points.push([x, y]);
});
ctx.beginPath();
sections.forEach((p, k) => {
if (k === 0) {
if (p.length == 2) {
ctx.moveTo(p[0], p[1]);
} else {
var last = sections[sections.length - 1];
console.log('LAST', last)
if (last.length == 2) {
ctx.moveTo(last[0], last[1]);
} else {
ctx.moveTo(p[2], p[3]);
}
}
} else {
if (p.length == 4) {
ctx.quadraticCurveTo(p[0], p[1], p[2], p[3]);
} else {
ctx.lineTo(p[0], p[1]);
}
}
});
ctx.closePath();
ctx.stroke();
ctx.restore();
});
ctx.save();
prepareCanvas(ctx);
ctx.strokeStyle = 'red';
points.forEach((p, k) => {
font.delta(name, k).forEach((d) => {
var x = p[0], y = p[1], dx = parseInt(d.getAttribute('x')), dy = parseInt(d.getAttribute('y'));
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + dx, y + dy);
ctx.stroke();
arrowHead(ctx, x + dx, y + dy, calcAngle(dx, dy), 10);
console.log(calcAngle(dx, dy));
// ctx.beginPath();
// ctx.arc(x + parseInt(d.getAttribute('x')), y + parseInt(d.getAttribute('y')), 2, 0, 2 * Math.PI, false);
// ctx.fill();
});
});
ctx.restore();
}
function fillGlyphSelector() {
var glyphSelector = document.getElementById('glyph-selector');
while (glyphSelector.firstChild) {
glyphSelector.removeChild(glyphSelector.firstChild);
}
font.glyphs().forEach((glyph) => {
var option = document.createElement('option');
option.value = glyph.getAttribute('name');
option.appendChild(document.createTextNode(option.value));
glyphSelector.appendChild(option);
});
}
function arrowHead(ctx, x, y, angle, size) {
ctx.save();
ctx.translate(x, y);
// ctx.arc(0, 0, 10, 0, 2 * Math.PI, false);
// // ctx.stroke();
ctx.rotate(angle + Math.PI * .75);
ctx.scale(size / 10, size / 10);
ctx.beginPath();
ctx.moveTo(3, 10);
ctx.lineTo(0, 0);
ctx.lineTo(10, 3);
// ctx.endPath();
ctx.stroke();
ctx.restore();
}
function calcAngle(dx, dy) {
return Math.atan(dy / dx) + ((dx < 0) ? Math.PI : 0);
}
function loadTTX() {
var fontSelector = document.getElementById('font-selector');
if (fontSelector.files.length > 0) {
var reader = new FileReader();
reader.onload = function (event) {
font = new Font(event.target.result);
fillGlyphSelector();
};
reader.readAsText(document.getElementById('font-selector').files[0]);
}
}
document.getElementById('font-selector').addEventListener('change', loadTTX);
loadTTX();
document.getElementById('glyph-selector').addEventListener('change', function () {
var value = this.value;
drawGlyph(value, font);
});