const s = '<mark></mark>' + '<mark>x</mark>'.repeat(2000);
regex = /<mark><\/mark>/g,
millisecs = {};
for (let size = 100; size < 25000; size+=100) {
millisecs[size] = test(15, 8, _ => s.substr(0, size).replace(regex, ''));
}
chartFunction(canvas, millisecs, "len", "ms");
function test(countPerRun, runs, f) {
let fastest = Infinity;
for (let run = 0; run < runs; run++) {
const started = performance.now();
for (let i = 0; i < countPerRun; i++) f();
fastest = Math.min(fastest, (performance.now() - started) / countPerRun);
}
return fastest;
}
function chartFunction(canvas, y, labelX, labelY) {
const ctx = canvas.getContext('2d'),
axisPix = [40, 20],
largeY = Object.values(y).sort( (a, b) => b - a )[
Math.floor(Object.keys(y).length / 10)
] * 1.3;
max = [+Object.keys(y).pop(), largeY],
coeff = [(canvas.width-axisPix[0]) / max[0], (canvas.height-axisPix[1]) / max[1]],
textAlignPix = [-8, -13];
ctx.translate(axisPix[0], canvas.height-axisPix[1]);
text(labelY + "/" + labelX, [-5, -13], [1, 1], false, 2);
for (let dim = 0; dim < 2; dim++) {
const c = coeff[dim], world = [c, 1];
let interval = 10**Math.floor(Math.log10(60 / c));
while (interval * c < 30) interval *= 2;
if (interval * c > 60) interval /= 2;
let decimals = ((interval+'').split('.')[1] || '').length;
line([[0, 0], [max[dim], 0]], world, dim);
for (let x = 0; x <= max[dim]; x += interval) {
line([[x, 0], [x, -5]], world, dim);
text(x.toFixed(decimals), [x, textAlignPix[1-dim]], world, dim, dim+1);
}
}
line(Object.entries(y), coeff);
function translate(coordinates, world, swap) {
return coordinates.map( p => {
p = [p[0] * world[0], p[1] * world[1]];
return swap ? p.reverse() : p;
});
}
function line(coordinates, world, swap) {
coordinates = translate(coordinates, world, swap);
ctx.beginPath();
ctx.moveTo(coordinates[0][0], -coordinates[0][1]);
for (const [x, y] of coordinates.slice(1)) ctx.lineTo(x, -y);
ctx.stroke();
}
function text(s, p, world, swap, align) {
const [[x, y]] = translate([p], world, swap);
ctx.font = '9px courier';
ctx.fillText(s, x - 2.5*align*s.length, 2.5-y);
}
}
<canvas id="canvas" width="600" height="200"></canvas>