1
0
mirror of https://github.com/lrsjng/pagemap.git synced 2025-09-30 21:56:40 +02:00
Files
pagemap/lib/pagemap.js
2016-06-11 22:57:52 +02:00

149 lines
4.1 KiB
JavaScript

const Rect = require('./rect');
const win = global.window;
const doc = win.document;
const body = doc.querySelector('body');
const black = pc => `rgba(0,0,0,${pc / 100})`;
const defaults = {
viewport: null,
styles: {
'header,footer,section,article': black(8),
'h1,a': black(10),
'h2,h3,h4': black(8)
},
back: black(2),
view: black(5),
drag: black(10),
interval: null
};
const _listener = (el, method, types, fn) => types.split(/\s+/).forEach(type => el[method](type, fn));
const on = (el, types, fn) => _listener(el, 'addEventListener', types, fn);
const off = (el, types, fn) => _listener(el, 'removeEventListener', types, fn);
module.exports = (canvas, options) => {
const settings = Object.assign({}, defaults, options);
const context = canvas.getContext('2d');
const calcScale = (() => {
const width = canvas.clientWidth;
const height = canvas.clientHeight;
return (w, h) => Math.min(width / w, height / h);
})();
const resizeCanvas = (w, h) => {
canvas.width = w;
canvas.height = h;
canvas.style.width = `${w}px`;
canvas.style.height = `${h}px`;
};
const viewport = settings.viewport;
const find = sel => Array.from((viewport || doc).querySelectorAll(sel));
let drag = false;
let rootRect;
let viewRect;
let scale;
let dragRx;
let dragRy;
const drawRect = (rect, col) => {
if (!col) {
return;
}
context.beginPath();
context.rect(rect.x, rect.y, rect.w, rect.h);
context.fillStyle = col;
context.fill();
};
const applyStyles = styles => {
Object.keys(styles).forEach(sel => {
const col = styles[sel];
find(sel).forEach(el => {
drawRect(Rect.ofElement(el).relativeTo(rootRect), col);
});
});
};
const draw = () => {
rootRect = viewport ? Rect.ofContent(viewport) : Rect.ofDocument();
viewRect = viewport ? Rect.ofViewport(viewport) : Rect.ofWindow();
scale = calcScale(rootRect.w, rootRect.h);
resizeCanvas(rootRect.w * scale, rootRect.h * scale);
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
context.scale(scale, scale);
drawRect(rootRect.relativeTo(rootRect), settings.back);
applyStyles(settings.styles);
drawRect(viewRect.relativeTo(rootRect), drag ? settings.drag : settings.view);
};
const onDrag = ev => {
ev.preventDefault();
const cr = Rect.ofViewport(canvas);
const x = (ev.pageX - cr.x) / scale - viewRect.w * dragRx;
const y = (ev.pageY - cr.y) / scale - viewRect.h * dragRy;
if (viewport) {
viewport.scrollLeft = x;
viewport.scrollTop = y;
} else {
win.scrollTo(x, y);
}
draw();
};
const onDragEnd = ev => {
drag = false;
canvas.style.cursor = 'pointer';
body.style.cursor = 'auto';
off(win, 'mousemove', onDrag);
off(win, 'mouseup', onDragEnd);
onDrag(ev);
};
const onDragStart = ev => {
drag = true;
const cr = Rect.ofViewport(canvas);
const vr = viewRect.relativeTo(rootRect);
dragRx = ((ev.pageX - cr.x) / scale - vr.x) / vr.w;
dragRy = ((ev.pageY - cr.y) / scale - vr.y) / vr.h;
if (dragRx < 0 || dragRx > 1 || dragRy < 0 || dragRy > 1) {
dragRx = 0.5;
dragRy = 0.5;
}
canvas.style.cursor = 'crosshair';
body.style.cursor = 'crosshair';
on(win, 'mousemove', onDrag);
on(win, 'mouseup', onDragEnd);
onDrag(ev);
};
const init = () => {
canvas.style.cursor = 'pointer';
on(canvas, 'mousedown', onDragStart);
on(viewport || win, 'load resize scroll', draw);
if (settings.interval > 0) {
setInterval(() => draw(), settings.interval);
}
draw();
};
init();
return {
redraw: draw
};
};