Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OverBoard PDF</title>
<meta name="description" content="OverBoard: write on any PDF on your smartboard. Runs in the browser; nothing is uploaded.">
<meta name="ob-version" content="4d7b27241fc6">
<meta name="ob-version" content="86f90347201b">
<meta name="theme-color" content="#1f1f1f">
<link rel="manifest" href="manifest.json">
<link rel="icon" href="icons/icon-192.png">
Expand Down Expand Up @@ -45,7 +45,7 @@ <h2 data-t="open_again">Open again</h2>
<p class="note"><span data-th="start_note">Your PDF and your ink stay in this browser on this computer. Nothing is uploaded.
Have a Word file? In Word, choose File → Save as PDF, then drop the PDF here.
Have an HTML worksheet? Drop it here to get a <i>_board.html</i> copy you can write on.</span>
<br><a href="../" data-t="back_demo">Back to the HTML worksheet demo</a> · <a href="https://github.com/BPMData/OverBoard" data-t="about">About OverBoard</a> · <a href="report/?from=start" target="_blank" data-t="board_help">Board not working?</a> · <span id="ob-release" title="OverBoard version">v30</span></p>
<br><a href="../" data-t="back_demo">Back to the HTML worksheet demo</a> · <a href="https://github.com/BPMData/OverBoard" data-t="about">About OverBoard</a> · <a href="report/?from=start" target="_blank" data-t="board_help">Board not working?</a> · <span id="ob-release" title="OverBoard version">v31</span></p>
<p class="note ob-langpick"><label><span aria-hidden="true">🌐</span> <select id="ob-lang" aria-label="Language" data-ta="language" data-tt="language" title="Language"></select></label></p>
</div>
</main>
Expand Down
2 changes: 1 addition & 1 deletion app/report/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ <h1 data-t="r_h1">Is OverBoard not working on your board?</h1>
<p data-th="r_intro2">If something doesn't work the way the page asks, that's fine. <b>That's exactly what I need to know.</b> Just keep going.</p>
<p class="mute small" data-th="r_privacy">Nothing is sent until you press <b>Send</b> at the very end, and you'll see everything first. No worksheets, PDFs or ink are ever included.</p>
<div class="row"><button class="go big" data-go="start" data-t="r_start">Start</button></div>
<p class="mute small" style="margin-top:28px">OverBoard <span id="ob-release" title="OverBoard version">v30</span></p>
<p class="mute small" style="margin-top:28px">OverBoard <span id="ob-release" title="OverBoard version">v31</span></p>
</div></div>
</section>

Expand Down
10 changes: 5 additions & 5 deletions app/sw.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// ===== GENERATED by tools/build.py: every file the app needs, with the start of its SHA-256. Do not edit by hand. =====
const VERSION = 'e1d36925f338';
const VERSION = '02572123a8ee';
const FILES = {
"../overlay/ink_overlay.html": "31eb701f9f240009",
"../overlay/ink_overlay.html": "c8af57d0d48b19cd",
"../shared/ink-core.js": "f5235bb4ef99a375",
"../shared/strings.js": "d0525093455e4d45",
"../shared/toolbar.css": "d3155c02c903c96e",
Expand All @@ -14,14 +14,14 @@ const FILES = {
"icons/icon-192.png": "d245e15b36475003",
"icons/icon-512.png": "17c1021fe2a0ade1",
"icons/maskable-512.png": "0c58f1bdccc9eda9",
"index.html": "18ce16d379756213",
"index.html": "4b5c66216bb59125",
"ink.js": "069771a403be1378",
"libs.js": "c09f60186ab9029a",
"main.js": "ac823fa04ab55eb2",
"manifest.json": "f7ee4a6c6f83cd40",
"notebook.js": "47bcfd4f80712344",
"offline.js": "6504935b2738711a",
"report/index.html": "084e1351caafa212",
"report/index.html": "beee65975d0d2445",
"store.js": "66af54cd32e6cbd2",
"textlayer.js": "1911308ed3e2a8b5",
"vendor/[email protected]/LICENSE.md": "f2c9fc00fdb66eb9",
Expand Down Expand Up @@ -214,7 +214,7 @@ const FILES = {
"vendor/[email protected]/standard_fonts/LiberationSans-BoldItalic.ttf": "a224075ac17495ad",
"vendor/[email protected]/standard_fonts/LiberationSans-Italic.ttf": "832b4406dbef2362",
"vendor/[email protected]/standard_fonts/LiberationSans-Regular.ttf": "f8ace1f892b2bd9d",
"version.json": "445c090471c65004",
"version.json": "f59b4daff279aa28",
"viewer.js": "648b4479c5b68b93"
};
// ===== END GENERATED =====
Expand Down
2 changes: 1 addition & 1 deletion app/version.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"v": "4d7b27241fc6",
"v": "86f90347201b",
"js": [
"embed.js",
"export.js",
Expand Down
52 changes: 38 additions & 14 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ <h2>Exit ticket</h2>
<div class="lines"><div></div><div></div><div></div><div></div></div>
<div class="foot">OverBoard · page 2 / 2 · Your ink saves in this browser only. Nothing is uploaded.</div>
</div>
<!-- ===== INK OVERLAY START (v30) =====
<!-- ===== INK OVERLAY START (v31) =====
Smartboard writing layer. Paste this whole block just before </body> in any .html file.
SMART BOARD: pen tip writes. Palm, fist or side of hand erases (the board reports it as an eraser).
Finger (and the round end of the SMART pen) scrolls the page; the "Finger" button switches it to drawing if you lose the pen.
Expand Down Expand Up @@ -1686,14 +1686,20 @@ <h2>Exit ticket</h2>
/* ---------- drawing ---------- */
// pen ink and covers go on the top canvas, highlights on the layer under it, the eraser cuts through both
function layers(s){ return s.e ? [ctx, hctx] : seeThrough(s) ? [hctx] : [ctx]; }
function drawStroke(s){ layers(s).forEach(function(g){ paintStroke(g, s, scale, OX * scale, 0); }); }
function drawStroke(s){ layers(s).forEach(function(g){ paintStroke(g, s, scale, OX * scale, -BY * scale); }); }
// live drawing draws the same curve piece by piece as points arrive (matches paintStroke exactly)
var live = null;
function drawPieces(s, pieces){ layers(s).forEach(function(g){ paintPieces(g, s, pieces, scale, OX * scale, 0); }); }
function drawPieces(s, pieces){ layers(s).forEach(function(g){ paintPieces(g, s, pieces, scale, OX * scale, -BY * scale); }); }
function clearCanvas(c, g){ g.save(); g.setTransform(1,0,0,1,0,0); g.clearRect(0,0,c.width,c.height); g.restore(); }
function inBand(s){ // skip strokes wholly above or below the canvas band
var lo = Infinity, hi = -Infinity, p = s.p;
for (var k = 1; k < p.length; k += 2) { if (p[k] < lo) lo = p[k]; if (p[k] > hi) hi = p[k]; }
return hi + s.w >= BY && lo - s.w <= BY + BH;
}
function redraw(){
clearCanvas(canvas, ctx); clearCanvas(hcan, hctx);
for (var i = 0; i < strokes.length; i++) drawStroke(strokes[i]);
for (var i = 0; i < strokes.length; i++) if (inBand(strokes[i])) drawStroke(strokes[i]);
if (cur) drawStroke(cur); // a stroke still being drawn when the band moves
}
function calcCW(){
var w = 0;
Expand All @@ -1702,27 +1708,44 @@ <h2>Exit ticket</h2>
}
// The canvas spans the whole window so you can write in the empty space beside the page.
// Ink is stored relative to the page column (CW wide, centered), so it stays lined up when the window or zoom changes.
var FW = 0, OX = 0; // full canvas width (CSS px) and where the page column starts inside it
// Up and down, the canvas is only a band about three screens tall that follows the scrolling (BY = its top, BH = its
// height, in worksheet px). A canvas taller than 16384 screen pixels can't be drawn by the graphics chip, so Chrome
// falls back to the processor and every pen move gets slow: a 20-page worksheet on a 2x (Retina) screen ran at a few
// frames a second.
var FW = 0, OX = 0, BY = 0, BH = 0; // full canvas width (CSS px) and where the page column starts inside it
function docTop(){ return canvas.getBoundingClientRect().top - BY * Z; } // screen y of the worksheet's top edge
function size(){
var h = Math.ceil(body.offsetHeight), cw = calcCW();
var fw = Math.max(cw, Math.floor(document.documentElement.clientWidth / Z));
var sc = Math.min((window.devicePixelRatio || 1) * Z, 2 * Math.max(1, Z), 30000 / h, 30000 / fw, Math.sqrt(100e6 / (fw * h))); // sharp when zoomed in, under browser canvas limits (two canvases)
if (h === H && sc === scale && cw === CW && fw === FW && canvas.width) return;
H = h; scale = sc; CW = cw; FW = fw; OX = (fw - cw) / 2;
var bh = Math.min(h, Math.ceil(3 * innerHeight / Z));
var sc = Math.min((window.devicePixelRatio || 1) * Z, 2 * Math.max(1, Z), 16000 / bh, 16000 / fw, Math.sqrt(100e6 / (fw * bh))); // sharp when zoomed in, small enough for the graphics chip
if (h === H && sc === scale && cw === CW && fw === FW && bh === BH && canvas.width) { follow(); return; }
H = h; scale = sc; CW = cw; FW = fw; OX = (fw - cw) / 2; BH = bh;
[canvas, hcan].forEach(function(c){
c.width = Math.round(FW * scale); c.height = Math.round(H * scale);
c.style.width = FW + 'px'; c.style.height = H + 'px';
c.width = Math.round(FW * scale); c.height = Math.round(BH * scale);
c.style.width = FW + 'px'; c.style.height = BH + 'px';
});
follow(true);
}
// keep the band around what's on screen, with a screen to spare above and below; redraw when it moves
function follow(force){
var vh = innerHeight / Z, top = -docTop() / Z, by = BY;
if (force || top < BY + (BY > 0 ? vh / 3 : 0) || top + vh > BY + BH - (BY + BH < H ? vh / 3 : 0))
by = Math.round(Math.max(0, Math.min(H - BH, top - (BH - vh) / 2)));
if (by === BY && !force) return;
BY = by;
canvas.style.top = hcan.style.top = BY + 'px';
redraw();
}

function pt(e){
var r = canvas.getBoundingClientRect(); // screen px; ink is in the worksheet's own px, so divide by the zoom
return [Math.round(((e.clientX - r.left) / Z - OX) * 10) / 10, Math.round((e.clientY - r.top) / Z * 10) / 10];
var t = docTop(), r = canvas.getBoundingClientRect(); // screen px; ink is in the worksheet's own px, so divide by the zoom
return [Math.round(((e.clientX - r.left) / Z - OX) * 10) / 10, Math.round((e.clientY - t) / Z * 10) / 10];
}
canvas.addEventListener('pointerdown', function(e){
if (active !== null || !ready) return;
if (e.pointerType === 'mouse' && e.button !== 0) return;
follow();
// SMART board: pen tip = "pen"; palm/fist/side of hand = "pen" with the eraser button (32); finger and round pen end = "mouse"
var kind = pointerKind(e), palm = kind === 'palm', finger = kind === 'finger';
active = e.pointerId;
Expand Down Expand Up @@ -1783,7 +1806,7 @@ <h2>Exit ticket</h2>
it count as that page); "this page" is the one at the middle of the screen */
function pages(){ return [].slice.call(document.querySelectorAll('.page')); }
function clearPage(){
var ct = canvas.getBoundingClientRect().top;
var ct = docTop();
var tops = pages().map(function(pg){ return (pg.getBoundingClientRect().top - ct) / Z; });
function band(y){ var i = 0; while (i + 1 < tops.length && tops[i + 1] <= y) i++; return i; }
var n = band((innerHeight / 2 - ct) / Z);
Expand Down Expand Up @@ -2144,7 +2167,7 @@ <h2>Exit ticket</h2>
clearPrint();
var list = [].slice.call(document.querySelectorAll('.page'));
if (!list.length) list = [body];
var ctop = canvas.getBoundingClientRect().top, hasHl = !PRINT_INK_BLACK && strokes.some(seeThrough);
var ctop = docTop(), hasHl = !PRINT_INK_BLACK && strokes.some(seeThrough);
list.forEach(function(pg){
var ph = pg.offsetHeight, pw = pg.offsetWidth, top = (pg === body) ? 0 : pg.getBoundingClientRect().top - ctop;
var ps = Math.min(PRINT_SCALE, 30000 / ph, Math.sqrt(60e6 / (CW * ph)));
Expand All @@ -2171,6 +2194,7 @@ <h2>Exit ticket</h2>
/* ---------- start ---------- */
var src = load(); size(); translateAll(); renderPeriods(); refresh(); setMode('write'); layoutClear(); fitToolbar();
window.addEventListener('resize', size);
window.addEventListener('scroll', function(){ follow(); }, { passive: true });
window.addEventListener('load', size);
if (window.ResizeObserver) new ResizeObserver(size).observe(body);
function started(src){ setStatus(tr(src === 'file' ? 'st_loaded_file' : src === 'browser' ? 'st_restored' : src === 'old' ? 'st_old_carried' : 'st_ready', { p: D.active })); }
Expand Down
52 changes: 38 additions & 14 deletions overlay/ink_overlay.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- ===== INK OVERLAY START (v30) =====
<!-- ===== INK OVERLAY START (v31) =====
Smartboard writing layer. Paste this whole block just before </body> in any .html file.
SMART BOARD: pen tip writes. Palm, fist or side of hand erases (the board reports it as an eraser).
Finger (and the round end of the SMART pen) scrolls the page; the "Finger" button switches it to drawing if you lose the pen.
Expand Down Expand Up @@ -1630,14 +1630,20 @@
/* ---------- drawing ---------- */
// pen ink and covers go on the top canvas, highlights on the layer under it, the eraser cuts through both
function layers(s){ return s.e ? [ctx, hctx] : seeThrough(s) ? [hctx] : [ctx]; }
function drawStroke(s){ layers(s).forEach(function(g){ paintStroke(g, s, scale, OX * scale, 0); }); }
function drawStroke(s){ layers(s).forEach(function(g){ paintStroke(g, s, scale, OX * scale, -BY * scale); }); }
// live drawing draws the same curve piece by piece as points arrive (matches paintStroke exactly)
var live = null;
function drawPieces(s, pieces){ layers(s).forEach(function(g){ paintPieces(g, s, pieces, scale, OX * scale, 0); }); }
function drawPieces(s, pieces){ layers(s).forEach(function(g){ paintPieces(g, s, pieces, scale, OX * scale, -BY * scale); }); }
function clearCanvas(c, g){ g.save(); g.setTransform(1,0,0,1,0,0); g.clearRect(0,0,c.width,c.height); g.restore(); }
function inBand(s){ // skip strokes wholly above or below the canvas band
var lo = Infinity, hi = -Infinity, p = s.p;
for (var k = 1; k < p.length; k += 2) { if (p[k] < lo) lo = p[k]; if (p[k] > hi) hi = p[k]; }
return hi + s.w >= BY && lo - s.w <= BY + BH;
}
function redraw(){
clearCanvas(canvas, ctx); clearCanvas(hcan, hctx);
for (var i = 0; i < strokes.length; i++) drawStroke(strokes[i]);
for (var i = 0; i < strokes.length; i++) if (inBand(strokes[i])) drawStroke(strokes[i]);
if (cur) drawStroke(cur); // a stroke still being drawn when the band moves
}
function calcCW(){
var w = 0;
Expand All @@ -1646,27 +1652,44 @@
}
// The canvas spans the whole window so you can write in the empty space beside the page.
// Ink is stored relative to the page column (CW wide, centered), so it stays lined up when the window or zoom changes.
var FW = 0, OX = 0; // full canvas width (CSS px) and where the page column starts inside it
// Up and down, the canvas is only a band about three screens tall that follows the scrolling (BY = its top, BH = its
// height, in worksheet px). A canvas taller than 16384 screen pixels can't be drawn by the graphics chip, so Chrome
// falls back to the processor and every pen move gets slow: a 20-page worksheet on a 2x (Retina) screen ran at a few
// frames a second.
var FW = 0, OX = 0, BY = 0, BH = 0; // full canvas width (CSS px) and where the page column starts inside it
function docTop(){ return canvas.getBoundingClientRect().top - BY * Z; } // screen y of the worksheet's top edge
function size(){
var h = Math.ceil(body.offsetHeight), cw = calcCW();
var fw = Math.max(cw, Math.floor(document.documentElement.clientWidth / Z));
var sc = Math.min((window.devicePixelRatio || 1) * Z, 2 * Math.max(1, Z), 30000 / h, 30000 / fw, Math.sqrt(100e6 / (fw * h))); // sharp when zoomed in, under browser canvas limits (two canvases)
if (h === H && sc === scale && cw === CW && fw === FW && canvas.width) return;
H = h; scale = sc; CW = cw; FW = fw; OX = (fw - cw) / 2;
var bh = Math.min(h, Math.ceil(3 * innerHeight / Z));
var sc = Math.min((window.devicePixelRatio || 1) * Z, 2 * Math.max(1, Z), 16000 / bh, 16000 / fw, Math.sqrt(100e6 / (fw * bh))); // sharp when zoomed in, small enough for the graphics chip
if (h === H && sc === scale && cw === CW && fw === FW && bh === BH && canvas.width) { follow(); return; }
H = h; scale = sc; CW = cw; FW = fw; OX = (fw - cw) / 2; BH = bh;
[canvas, hcan].forEach(function(c){
c.width = Math.round(FW * scale); c.height = Math.round(H * scale);
c.style.width = FW + 'px'; c.style.height = H + 'px';
c.width = Math.round(FW * scale); c.height = Math.round(BH * scale);
c.style.width = FW + 'px'; c.style.height = BH + 'px';
});
follow(true);
}
// keep the band around what's on screen, with a screen to spare above and below; redraw when it moves
function follow(force){
var vh = innerHeight / Z, top = -docTop() / Z, by = BY;
if (force || top < BY + (BY > 0 ? vh / 3 : 0) || top + vh > BY + BH - (BY + BH < H ? vh / 3 : 0))
by = Math.round(Math.max(0, Math.min(H - BH, top - (BH - vh) / 2)));
if (by === BY && !force) return;
BY = by;
canvas.style.top = hcan.style.top = BY + 'px';
redraw();
}

function pt(e){
var r = canvas.getBoundingClientRect(); // screen px; ink is in the worksheet's own px, so divide by the zoom
return [Math.round(((e.clientX - r.left) / Z - OX) * 10) / 10, Math.round((e.clientY - r.top) / Z * 10) / 10];
var t = docTop(), r = canvas.getBoundingClientRect(); // screen px; ink is in the worksheet's own px, so divide by the zoom
return [Math.round(((e.clientX - r.left) / Z - OX) * 10) / 10, Math.round((e.clientY - t) / Z * 10) / 10];
}
canvas.addEventListener('pointerdown', function(e){
if (active !== null || !ready) return;
if (e.pointerType === 'mouse' && e.button !== 0) return;
follow();
// SMART board: pen tip = "pen"; palm/fist/side of hand = "pen" with the eraser button (32); finger and round pen end = "mouse"
var kind = pointerKind(e), palm = kind === 'palm', finger = kind === 'finger';
active = e.pointerId;
Expand Down Expand Up @@ -1727,7 +1750,7 @@
it count as that page); "this page" is the one at the middle of the screen */
function pages(){ return [].slice.call(document.querySelectorAll('.page')); }
function clearPage(){
var ct = canvas.getBoundingClientRect().top;
var ct = docTop();
var tops = pages().map(function(pg){ return (pg.getBoundingClientRect().top - ct) / Z; });
function band(y){ var i = 0; while (i + 1 < tops.length && tops[i + 1] <= y) i++; return i; }
var n = band((innerHeight / 2 - ct) / Z);
Expand Down Expand Up @@ -2088,7 +2111,7 @@
clearPrint();
var list = [].slice.call(document.querySelectorAll('.page'));
if (!list.length) list = [body];
var ctop = canvas.getBoundingClientRect().top, hasHl = !PRINT_INK_BLACK && strokes.some(seeThrough);
var ctop = docTop(), hasHl = !PRINT_INK_BLACK && strokes.some(seeThrough);
list.forEach(function(pg){
var ph = pg.offsetHeight, pw = pg.offsetWidth, top = (pg === body) ? 0 : pg.getBoundingClientRect().top - ctop;
var ps = Math.min(PRINT_SCALE, 30000 / ph, Math.sqrt(60e6 / (CW * ph)));
Expand All @@ -2115,6 +2138,7 @@
/* ---------- start ---------- */
var src = load(); size(); translateAll(); renderPeriods(); refresh(); setMode('write'); layoutClear(); fitToolbar();
window.addEventListener('resize', size);
window.addEventListener('scroll', function(){ follow(); }, { passive: true });
window.addEventListener('load', size);
if (window.ResizeObserver) new ResizeObserver(size).observe(body);
function started(src){ setStatus(tr(src === 'file' ? 'st_loaded_file' : src === 'browser' ? 'st_restored' : src === 'old' ? 'st_old_carried' : 'st_ready', { p: D.active })); }
Expand Down
Loading