mirror of
https://github.com/lrsjng/pagemap.git
synced 2025-09-07 03:30:44 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f6fcd78cec | ||
|
d76b3c4dd5 | ||
|
a05a11d795 | ||
|
cfd5be77a9 | ||
|
94086fff4e | ||
|
294813ff26 | ||
|
341bf3e960 | ||
|
84118a0463 | ||
|
407c6617db | ||
|
8f15b44a13 | ||
|
f6b1e153a0 |
@@ -12,7 +12,7 @@ insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
|
||||
[{package.json,.eslintrc,.travis.yml}]
|
||||
[{*.json,*.yml,.eslintrc}]
|
||||
indent_size = 2
|
||||
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
build
|
||||
coverage
|
||||
dist
|
||||
es5
|
||||
local
|
||||
node_modules
|
||||
/build/
|
||||
/coverage/
|
||||
/dist/
|
||||
/es5/
|
||||
/local/
|
||||
/node_modules/
|
||||
|
@@ -5,8 +5,8 @@
|
||||
es6: true
|
||||
node: true
|
||||
|
||||
ecmaFeatures:
|
||||
ecmaVersion: 6
|
||||
parserOptions:
|
||||
ecmaVersion: 2019
|
||||
|
||||
rules:
|
||||
array-bracket-spacing: [2, never]
|
||||
@@ -42,7 +42,7 @@
|
||||
max-len: [0, 80, 4]
|
||||
max-nested-callbacks: [1, 3]
|
||||
max-params: [1, 5] ###
|
||||
max-statements: [1, 32] ###
|
||||
max-statements: [1, 48] ###
|
||||
new-cap: 0
|
||||
new-parens: 2
|
||||
newline-after-var: 0
|
||||
|
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
build
|
||||
coverage
|
||||
local
|
||||
node_modules
|
||||
npm-debug.log
|
||||
/.nyc_output/
|
||||
/build/
|
||||
/coverage/
|
||||
/local/
|
||||
/node_modules/
|
||||
/npm-debug.log
|
||||
|
15
.travis.yml
Normal file
15
.travis.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
language: node_js
|
||||
|
||||
sudo: false
|
||||
|
||||
node_js:
|
||||
- node
|
||||
- "12"
|
||||
- "11"
|
||||
- "10"
|
||||
- "9"
|
||||
- "8"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
10
README.md
10
README.md
@@ -1,7 +1,7 @@
|
||||
# pagemap
|
||||
|
||||
[![license][license-img]][github] [![web][web-img]][web] [![github][github-img]][github] [![npm][npm-img]][npm]
|
||||
[![version][npm-v-img]][npm] [![downloads][npm-dm-img]][npm] [![dependencies status][gemnasium-img]][gemnasium]
|
||||
[![version][npm-v-img]][npm] [![downloads][npm-dm-img]][npm] [![build status][travis-img]][travis]
|
||||
|
||||
Mini map for web pages.
|
||||
|
||||
@@ -10,7 +10,7 @@ Mini map for web pages.
|
||||
|
||||
add a `canvas` tag to your HTML page:
|
||||
```html
|
||||
<canvas id='#map'></canvas>
|
||||
<canvas id='map'></canvas>
|
||||
```
|
||||
|
||||
fix it's position on the screen:
|
||||
@@ -45,7 +45,7 @@ pagemap(document.querySelector('#map'), {
|
||||
## License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Lars Jung (https://larsjung.de)
|
||||
Copyright (c) 2020 Lars Jung (https://larsjung.de)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -69,7 +69,7 @@ THE SOFTWARE.
|
||||
[web]: https://larsjung.de/pagemap/
|
||||
[github]: https://github.com/lrsjng/pagemap
|
||||
[npm]: https://www.npmjs.org/package/pagemap
|
||||
[gemnasium]: https://gemnasium.com/lrsjng/pagemap
|
||||
[travis]: https://travis-ci.org/lrsjng/pagemap
|
||||
|
||||
[license-img]: https://img.shields.io/badge/license-MIT-a0a060.svg?style=flat-square
|
||||
[web-img]: https://img.shields.io/badge/web-larsjung.de/pagemap-a0a060.svg?style=flat-square
|
||||
@@ -78,4 +78,4 @@ THE SOFTWARE.
|
||||
|
||||
[npm-v-img]: https://img.shields.io/npm/v/pagemap.svg?style=flat-square
|
||||
[npm-dm-img]: https://img.shields.io/npm/dm/pagemap.svg?style=flat-square
|
||||
[gemnasium-img]: https://img.shields.io/gemnasium/lrsjng/pagemap.svg?style=flat-square
|
||||
[travis-img]: https://img.shields.io/travis/lrsjng/pagemap.svg?style=flat-square
|
||||
|
@@ -1,84 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>pagemap boxes demo</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
width: 2000px;
|
||||
height: 2000px;
|
||||
background-color: #eee;
|
||||
}
|
||||
#map {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 120px;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
#container {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
outline: 4px solid #222;
|
||||
overflow: auto;
|
||||
}
|
||||
#content {
|
||||
width: 800px;
|
||||
height: 1000px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#container2 {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
outline: 4px solid #222;
|
||||
overflow: auto;
|
||||
}
|
||||
#content2 {
|
||||
width: 500px;
|
||||
height: 600px;
|
||||
background-color: #aaa;
|
||||
}
|
||||
.checkers {
|
||||
background-image:
|
||||
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
|
||||
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
|
||||
background-size: 100px 100px;
|
||||
background-position: 0 0, 50px 50px
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="checkers">
|
||||
<div id="container">
|
||||
<div id="content" class="checkers">
|
||||
<div id="container2">
|
||||
<div id="content2" class="checkers"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas id="map"></canvas>
|
||||
|
||||
<script src="../dist/pagemap.js"></script>
|
||||
<script>
|
||||
pagemap(document.querySelector('#map'), {
|
||||
// viewport: document.querySelector('#container'),
|
||||
interval: 50,
|
||||
styles: {
|
||||
div: 'rgba(0,0,0,0.1)'
|
||||
},
|
||||
back: 'rgba(255,255,255,1)'
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
351
dist/pagemap.js
vendored
351
dist/pagemap.js
vendored
@@ -1,2 +1,349 @@
|
||||
/*! pagemap v0.1.0 - https://larsjung.de/pagemap/ */
|
||||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.pagemap=e():t.pagemap=e()}(this,function(){return function(t){function e(n){if(o[n])return o[n].exports;var r=o[n]={exports:{},id:n,loaded:!1};return t[n].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var o={};return e.m=t,e.c=o,e.p="",e(0)}([function(t,e,o){(function(e){"use strict";var n=o(1),r=e.window,i=r.document,c=i.querySelector("body"),u=function(t){return"rgba(0,0,0,"+t/100+")"},f={viewport:null,styles:{"header,footer,section,article":u(8),"h1,a":u(10),"h2,h3,h4":u(8)},back:u(2),view:u(5),drag:u(10),interval:null},l=function(t,e,o,n){return o.split(/\s+/).forEach(function(o){return t[e](o,n)})},s=function(t,e,o){return l(t,"addEventListener",e,o)},a=function(t,e,o){return l(t,"removeEventListener",e,o)};t.exports=function(t,e){var o=Object.assign({},f,e),u=t.getContext("2d"),l=function(){var e=t.clientWidth,o=t.clientHeight;return function(t,n){return Math.min(e/t,o/n)}}(),p=function(e,o){t.width=e,t.height=o,t.style.width=e+"px",t.style.height=o+"px"},h=o.viewport,d=function(t){return Array.from((h||i).querySelectorAll(t))},v=!1,y=void 0,g=void 0,w=void 0,x=void 0,m=void 0,b=function(t,e){e&&(u.beginPath(),u.rect(t.x,t.y,t.w,t.h),u.fillStyle=e,u.fill())},T=function(t){Object.keys(t).forEach(function(e){var o=t[e];d(e).forEach(function(t){b(n.ofElement(t).relativeTo(y),o)})})},E=function(){y=h?n.ofContent(h):n.ofDocument(),g=h?n.ofViewport(h):n.ofWindow(),w=l(y.w,y.h),p(y.w*w,y.h*w),u.setTransform(1,0,0,1,0,0),u.clearRect(0,0,t.width,t.height),u.scale(w,w),b(y.relativeTo(y),o.back),T(o.styles),b(g.relativeTo(y),v?o.drag:o.view)},O=function(e){e.preventDefault();var o=n.ofViewport(t),i=(e.pageX-o.x)/w-g.w*x,c=(e.pageY-o.y)/w-g.h*m;h?(h.scrollLeft=i,h.scrollTop=c):r.scrollTo(i,c),E()},W=function L(e){v=!1,t.style.cursor="pointer",c.style.cursor="auto",a(r,"mousemove",O),a(r,"mouseup",L),O(e)},j=function(e){v=!0;var o=n.ofViewport(t),i=g.relativeTo(y);x=((e.pageX-o.x)/w-i.x)/i.w,m=((e.pageY-o.y)/w-i.y)/i.h,(0>x||x>1||0>m||m>1)&&(x=.5,m=.5),t.style.cursor="crosshair",c.style.cursor="crosshair",s(r,"mousemove",O),s(r,"mouseup",W),O(e)},H=function(){t.style.cursor="pointer",s(t,"mousedown",j),s(h||r,"load resize scroll",E),o.interval>0&&setInterval(function(){return E()},o.interval),E()};return H(),{redraw:E}}}).call(e,function(){return this}())},function(t,e){(function(e){"use strict";var o=e.window,n=o.document.documentElement,r=t.exports=function(t,e,o,n){return Object.assign(Object.create(r.prototype),{x:t,y:e,w:o,h:n})};r.prototype={constructor:r,relativeTo:function(){var t=arguments.length<=0||void 0===arguments[0]?{x:0,y:0}:arguments[0];return r(this.x-t.x,this.y-t.y,this.w,this.h)}},r.ofDocument=function(){return r(0,0,n.scrollWidth,n.scrollHeight)},r.ofWindow=function(){return r(o.pageXOffset,o.pageYOffset,n.clientWidth,n.clientHeight)};var i=function(t){var e=t.getBoundingClientRect();return{x:e.left+o.pageXOffset,y:e.top+o.pageYOffset}};r.ofElement=function(t){var e=i(t),o=e.x,n=e.y;return r(o,n,t.offsetWidth,t.offsetHeight)},r.ofViewport=function(t){var e=i(t),o=e.x,n=e.y;return r(o+t.clientLeft,n+t.clientTop,t.clientWidth,t.clientHeight)},r.ofContent=function(t){var e=i(t),o=e.x,n=e.y;return r(o+t.clientLeft-t.scrollLeft,n+t.clientTop-t.scrollTop,t.scrollWidth,t.scrollHeight)}}).call(e,function(){return this}())}])});
|
||||
/*! pagemap v1.3.0 - https://larsjung.de/pagemap/ */
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory();
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define("pagemap", [], factory);
|
||||
else if(typeof exports === 'object')
|
||||
exports["pagemap"] = factory();
|
||||
else
|
||||
root["pagemap"] = factory();
|
||||
})((typeof self !== 'undefined' ? self : this), function() {
|
||||
return /******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = function (canvas, options) {
|
||||
var WIN = global.window;
|
||||
var DOC = WIN.document;
|
||||
var DOC_EL = DOC.documentElement;
|
||||
var BODY = DOC.querySelector('body');
|
||||
var CTX = canvas.getContext('2d');
|
||||
|
||||
var black = function black(pc) {
|
||||
return "rgba(0,0,0,".concat(pc / 100, ")");
|
||||
};
|
||||
|
||||
var settings = Object.assign({
|
||||
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
|
||||
}, options);
|
||||
|
||||
var _listener = function _listener(el, method, types, fn) {
|
||||
return types.split(/\s+/).forEach(function (type) {
|
||||
return el[method](type, fn);
|
||||
});
|
||||
};
|
||||
|
||||
var on = function on(el, types, fn) {
|
||||
return _listener(el, 'addEventListener', types, fn);
|
||||
};
|
||||
|
||||
var off = function off(el, types, fn) {
|
||||
return _listener(el, 'removeEventListener', types, fn);
|
||||
};
|
||||
|
||||
var Rect = function Rect(x, y, w, h) {
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
w: w,
|
||||
h: h
|
||||
};
|
||||
};
|
||||
|
||||
var rect_rel_to = function rect_rel_to(rect) {
|
||||
var pos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
return Rect(rect.x - pos.x, rect.y - pos.y, rect.w, rect.h);
|
||||
};
|
||||
|
||||
var rect_of_doc = function rect_of_doc() {
|
||||
return Rect(0, 0, DOC_EL.scrollWidth, DOC_EL.scrollHeight);
|
||||
};
|
||||
|
||||
var rect_of_win = function rect_of_win() {
|
||||
return Rect(WIN.pageXOffset, WIN.pageYOffset, DOC_EL.clientWidth, DOC_EL.clientHeight);
|
||||
};
|
||||
|
||||
var el_get_offset = function el_get_offset(el) {
|
||||
var br = el.getBoundingClientRect();
|
||||
return {
|
||||
x: br.left + WIN.pageXOffset,
|
||||
y: br.top + WIN.pageYOffset
|
||||
};
|
||||
};
|
||||
|
||||
var rect_of_el = function rect_of_el(el) {
|
||||
var _el_get_offset = el_get_offset(el),
|
||||
x = _el_get_offset.x,
|
||||
y = _el_get_offset.y;
|
||||
|
||||
return Rect(x, y, el.offsetWidth, el.offsetHeight);
|
||||
};
|
||||
|
||||
var rect_of_viewport = function rect_of_viewport(el) {
|
||||
var _el_get_offset2 = el_get_offset(el),
|
||||
x = _el_get_offset2.x,
|
||||
y = _el_get_offset2.y;
|
||||
|
||||
return Rect(x + el.clientLeft, y + el.clientTop, el.clientWidth, el.clientHeight);
|
||||
};
|
||||
|
||||
var rect_of_content = function rect_of_content(el) {
|
||||
var _el_get_offset3 = el_get_offset(el),
|
||||
x = _el_get_offset3.x,
|
||||
y = _el_get_offset3.y;
|
||||
|
||||
return Rect(x + el.clientLeft - el.scrollLeft, y + el.clientTop - el.scrollTop, el.scrollWidth, el.scrollHeight);
|
||||
};
|
||||
|
||||
var calc_scale = function () {
|
||||
var width = canvas.clientWidth;
|
||||
var height = canvas.clientHeight;
|
||||
return function (w, h) {
|
||||
return Math.min(width / w, height / h);
|
||||
};
|
||||
}();
|
||||
|
||||
var resize_canvas = function resize_canvas(w, h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
canvas.style.width = "".concat(w, "px");
|
||||
canvas.style.height = "".concat(h, "px");
|
||||
};
|
||||
|
||||
var viewport = settings.viewport;
|
||||
|
||||
var find = function find(sel) {
|
||||
return Array.from((viewport || DOC).querySelectorAll(sel));
|
||||
};
|
||||
|
||||
var drag = false;
|
||||
var root_rect;
|
||||
var view_rect;
|
||||
var scale;
|
||||
var drag_rx;
|
||||
var drag_ry;
|
||||
|
||||
var draw_rect = function draw_rect(rect, col) {
|
||||
if (col) {
|
||||
CTX.beginPath();
|
||||
CTX.rect(rect.x, rect.y, rect.w, rect.h);
|
||||
CTX.fillStyle = col;
|
||||
CTX.fill();
|
||||
}
|
||||
};
|
||||
|
||||
var apply_styles = function apply_styles(styles) {
|
||||
Object.keys(styles).forEach(function (sel) {
|
||||
var col = styles[sel];
|
||||
find(sel).forEach(function (el) {
|
||||
draw_rect(rect_rel_to(rect_of_el(el), root_rect), col);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var draw = function draw() {
|
||||
root_rect = viewport ? rect_of_content(viewport) : rect_of_doc();
|
||||
view_rect = viewport ? rect_of_viewport(viewport) : rect_of_win();
|
||||
scale = calc_scale(root_rect.w, root_rect.h);
|
||||
resize_canvas(root_rect.w * scale, root_rect.h * scale);
|
||||
CTX.setTransform(1, 0, 0, 1, 0, 0);
|
||||
CTX.clearRect(0, 0, canvas.width, canvas.height);
|
||||
CTX.scale(scale, scale);
|
||||
draw_rect(rect_rel_to(root_rect, root_rect), settings.back);
|
||||
apply_styles(settings.styles);
|
||||
draw_rect(rect_rel_to(view_rect, root_rect), drag ? settings.drag : settings.view);
|
||||
};
|
||||
|
||||
var on_drag = function on_drag(ev) {
|
||||
ev.preventDefault();
|
||||
var cr = rect_of_viewport(canvas);
|
||||
var x = (ev.pageX - cr.x) / scale - view_rect.w * drag_rx;
|
||||
var y = (ev.pageY - cr.y) / scale - view_rect.h * drag_ry;
|
||||
|
||||
if (viewport) {
|
||||
viewport.scrollLeft = x;
|
||||
viewport.scrollTop = y;
|
||||
} else {
|
||||
WIN.scrollTo(x, y);
|
||||
}
|
||||
|
||||
draw();
|
||||
};
|
||||
|
||||
var on_drag_end = function on_drag_end(ev) {
|
||||
drag = false;
|
||||
canvas.style.cursor = 'pointer';
|
||||
BODY.style.cursor = 'auto';
|
||||
off(WIN, 'mousemove', on_drag);
|
||||
off(WIN, 'mouseup', on_drag_end);
|
||||
on_drag(ev);
|
||||
};
|
||||
|
||||
var on_drag_start = function on_drag_start(ev) {
|
||||
drag = true;
|
||||
var cr = rect_of_viewport(canvas);
|
||||
var vr = rect_rel_to(view_rect, root_rect);
|
||||
drag_rx = ((ev.pageX - cr.x) / scale - vr.x) / vr.w;
|
||||
drag_ry = ((ev.pageY - cr.y) / scale - vr.y) / vr.h;
|
||||
|
||||
if (drag_rx < 0 || drag_rx > 1 || drag_ry < 0 || drag_ry > 1) {
|
||||
drag_rx = 0.5;
|
||||
drag_ry = 0.5;
|
||||
}
|
||||
|
||||
canvas.style.cursor = 'crosshair';
|
||||
BODY.style.cursor = 'crosshair';
|
||||
on(WIN, 'mousemove', on_drag);
|
||||
on(WIN, 'mouseup', on_drag_end);
|
||||
on_drag(ev);
|
||||
};
|
||||
|
||||
var init = function init() {
|
||||
canvas.style.cursor = 'pointer';
|
||||
on(canvas, 'mousedown', on_drag_start);
|
||||
on(viewport || WIN, 'load resize scroll', draw);
|
||||
|
||||
if (settings.interval > 0) {
|
||||
setInterval(function () {
|
||||
return draw();
|
||||
}, settings.interval);
|
||||
}
|
||||
|
||||
draw();
|
||||
};
|
||||
|
||||
init();
|
||||
return {
|
||||
redraw: draw
|
||||
};
|
||||
};
|
||||
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
var g;
|
||||
|
||||
// This works in non-strict mode
|
||||
g = (function() {
|
||||
return this;
|
||||
})();
|
||||
|
||||
try {
|
||||
// This works if eval is allowed (see CSP)
|
||||
g = g || new Function("return this")();
|
||||
} catch (e) {
|
||||
// This works if the window reference is available
|
||||
if (typeof window === "object") g = window;
|
||||
}
|
||||
|
||||
// g can still be undefined, but nothing to do about it...
|
||||
// We return undefined, instead of nothing here, so it's
|
||||
// easier to handle this case. if(!global) { ...}
|
||||
|
||||
module.exports = g;
|
||||
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
});
|
2
dist/pagemap.min.js
vendored
Normal file
2
dist/pagemap.min.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/*! pagemap v1.3.0 - https://larsjung.de/pagemap/ */
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("pagemap",[],t):"object"==typeof exports?exports.pagemap=t():e.pagemap=t()}("undefined"!=typeof self?self:this,function(){return r={},o.m=n=[function(e,t,n){(function(M){e.exports=function(c,e){function t(e){return"rgba(0,0,0,".concat(e/100,")")}function r(t,n,e,r){return e.split(/\s+/).forEach(function(e){return t[n](e,r)})}function o(e,t,n){return r(e,"addEventListener",t,n)}function n(e,t,n){return r(e,"removeEventListener",t,n)}function u(e,t,n,r){return{x:e,y:t,w:n,h:r}}function l(e,t){var n=1<arguments.length&&void 0!==t?t:{x:0,y:0};return u(e.x-n.x,e.y-n.y,e.w,e.h)}function f(e){var t=e.getBoundingClientRect();return{x:t.left+O.pageXOffset,y:t.top+O.pageYOffset}}function a(e){var t=f(e),n=t.x,r=t.y;return u(n+e.clientLeft,r+e.clientTop,e.clientWidth,e.clientHeight)}function s(e,t){t&&(H.beginPath(),H.rect(e.x,e.y,e.w,e.h),H.fillStyle=t,H.fill())}function p(n){Object.keys(n).forEach(function(e){var t,i=n[e];t=e,Array.from((W||S).querySelectorAll(t)).forEach(function(e){var t,n,r,o;s(l((n=f(t=e),r=n.x,o=n.y,u(r,o,t.offsetWidth,t.offsetHeight)),m),i)})})}function i(){var e,t,n,r,o,i;m=W?(t=f(e=W),n=t.x,r=t.y,u(n+e.clientLeft-e.scrollLeft,r+e.clientTop-e.scrollTop,e.scrollWidth,e.scrollHeight)):u(0,0,T.scrollWidth,T.scrollHeight),x=W?a(W):u(O.pageXOffset,O.pageYOffset,T.clientWidth,T.clientHeight),b=P(m.w,m.h),o=m.w*b,i=m.h*b,c.width=o,c.height=i,c.style.width="".concat(o,"px"),c.style.height="".concat(i,"px"),H.setTransform(1,0,0,1,0,0),H.clearRect(0,0,c.width,c.height),H.scale(b,b),s(l(m,m),L.back),p(L.styles),s(l(x,m),_?L.drag:L.view)}function d(e){e.preventDefault();var t=a(c),n=(e.pageX-t.x)/b-x.w*w,r=(e.pageY-t.y)/b-x.h*j;W?(W.scrollLeft=n,W.scrollTop=r):O.scrollTo(n,r),i()}function h(e){_=!1,c.style.cursor="pointer",E.style.cursor="auto",n(O,"mousemove",d),n(O,"mouseup",h),d(e)}function y(e){_=!0;var t=a(c),n=l(x,m);w=((e.pageX-t.x)/b-n.x)/n.w,j=((e.pageY-t.y)/b-n.y)/n.h,(w<0||1<w||j<0||1<j)&&(j=w=.5),c.style.cursor="crosshair",E.style.cursor="crosshair",o(O,"mousemove",d),o(O,"mouseup",h),d(e)}var g,v,m,x,b,w,j,O=M.window,S=O.document,T=S.documentElement,E=S.querySelector("body"),H=c.getContext("2d"),L=Object.assign({viewport:null,styles:{"header,footer,section,article":t(8),"h1,a":t(10),"h2,h3,h4":t(8)},back:t(2),view:t(5),drag:t(10),interval:null},e),P=(g=c.clientWidth,v=c.clientHeight,function(e,t){return Math.min(g/e,v/t)}),W=L.viewport,_=!1;return c.style.cursor="pointer",o(c,"mousedown",y),o(W||O,"load resize scroll",i),0<L.interval&&setInterval(function(){return i()},L.interval),i(),{redraw:i}}}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n}],o.c=r,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=0);function o(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}var n,r});
|
60
ghu.js
Normal file
60
ghu.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const {resolve, join} = require('path');
|
||||
const {ghu, jszip, mapfn, read, remove, uglify, webpack, wrap, write} = require('ghu');
|
||||
|
||||
const NAME = 'pagemap';
|
||||
|
||||
const ROOT = resolve(__dirname);
|
||||
const SRC = join(ROOT, 'src');
|
||||
const DEMO = join(SRC, 'demo');
|
||||
const BUILD = join(ROOT, 'build');
|
||||
const DIST = join(ROOT, 'dist');
|
||||
|
||||
ghu.defaults('release');
|
||||
|
||||
ghu.before(runtime => {
|
||||
runtime.pkg = Object.assign({}, require('./package.json'));
|
||||
runtime.comment = `${NAME} v${runtime.pkg.version} - ${runtime.pkg.homepage}`;
|
||||
runtime.commentJs = `/*! ${runtime.comment} */\n`;
|
||||
console.log(runtime.comment);
|
||||
});
|
||||
|
||||
ghu.task('clean', () => {
|
||||
return remove(`${BUILD}, ${DIST}`);
|
||||
});
|
||||
|
||||
ghu.task('build:script', runtime => {
|
||||
return read(`${SRC}/${NAME}.js`)
|
||||
.then(webpack(webpack.cfg_umd(NAME, [SRC])))
|
||||
.then(wrap(runtime.commentJs))
|
||||
.then(write(`${DIST}/${NAME}.js`, {overwrite: true}))
|
||||
.then(write(`${BUILD}/${NAME}-${runtime.pkg.version}.js`, {overwrite: true}))
|
||||
.then(uglify())
|
||||
.then(wrap(runtime.commentJs))
|
||||
.then(write(`${DIST}/${NAME}.min.js`, {overwrite: true}))
|
||||
.then(write(`${BUILD}/${NAME}-${runtime.pkg.version}.min.js`, {overwrite: true}));
|
||||
});
|
||||
|
||||
ghu.task('build:copy', () => {
|
||||
return read(`${ROOT}/*.md`)
|
||||
.then(write(mapfn.p(ROOT, BUILD), {overwrite: true}));
|
||||
});
|
||||
|
||||
ghu.task('build:demo', ['build:script'], () => {
|
||||
return Promise.all([
|
||||
read(`${DEMO}: *`)
|
||||
.then(write(mapfn.p(SRC, BUILD), {overwrite: true})),
|
||||
|
||||
read(`${BUILD}: ${NAME}-*.min.js`)
|
||||
.then(write(`${BUILD}/demo/${NAME}.min.js`, {overwrite: true}))
|
||||
]);
|
||||
});
|
||||
|
||||
ghu.task('build', ['build:script', 'build:copy', 'build:demo']);
|
||||
|
||||
ghu.task('zip', ['build'], runtime => {
|
||||
return read(`${BUILD}/**`)
|
||||
.then(jszip({dir: BUILD, level: 9}))
|
||||
.then(write(`${BUILD}/${NAME}-${runtime.pkg.version}.zip`, {overwrite: true}));
|
||||
});
|
||||
|
||||
ghu.task('release', ['clean', 'zip']);
|
148
lib/pagemap.js
148
lib/pagemap.js
@@ -1,148 +0,0 @@
|
||||
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
|
||||
};
|
||||
};
|
67
lib/rect.js
67
lib/rect.js
@@ -1,67 +0,0 @@
|
||||
const win = global.window;
|
||||
const docEl = win.document.documentElement;
|
||||
|
||||
const Rect = module.exports = (x, y, w, h) => {
|
||||
return Object.assign(Object.create(Rect.prototype), {
|
||||
x, y, w, h
|
||||
});
|
||||
};
|
||||
|
||||
Rect.prototype = {
|
||||
constructor: Rect,
|
||||
|
||||
relativeTo(pos = {x: 0, y: 0}) {
|
||||
return Rect(this.x - pos.x, this.y - pos.y, this.w, this.h);
|
||||
}
|
||||
};
|
||||
|
||||
Rect.ofDocument = () => {
|
||||
return Rect(0, 0, docEl.scrollWidth, docEl.scrollHeight);
|
||||
};
|
||||
|
||||
Rect.ofWindow = () => {
|
||||
return Rect(
|
||||
win.pageXOffset,
|
||||
win.pageYOffset,
|
||||
docEl.clientWidth,
|
||||
docEl.clientHeight
|
||||
);
|
||||
};
|
||||
|
||||
const getOffset = el => {
|
||||
const br = el.getBoundingClientRect();
|
||||
return {
|
||||
x: br.left + win.pageXOffset,
|
||||
y: br.top + win.pageYOffset
|
||||
};
|
||||
};
|
||||
|
||||
Rect.ofElement = el => {
|
||||
const {x, y} = getOffset(el);
|
||||
return Rect(
|
||||
x,
|
||||
y,
|
||||
el.offsetWidth,
|
||||
el.offsetHeight
|
||||
);
|
||||
};
|
||||
|
||||
Rect.ofViewport = el => {
|
||||
const {x, y} = getOffset(el);
|
||||
return Rect(
|
||||
x + el.clientLeft,
|
||||
y + el.clientTop,
|
||||
el.clientWidth,
|
||||
el.clientHeight
|
||||
);
|
||||
};
|
||||
|
||||
Rect.ofContent = el => {
|
||||
const {x, y} = getOffset(el);
|
||||
return Rect(
|
||||
x + el.clientLeft - el.scrollLeft,
|
||||
y + el.clientTop - el.scrollTop,
|
||||
el.scrollWidth,
|
||||
el.scrollHeight
|
||||
);
|
||||
};
|
6988
package-lock.json
generated
Normal file
6988
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pagemap",
|
||||
"version": "0.1.0",
|
||||
"version": "1.3.0",
|
||||
"description": "Mini map for web pages.",
|
||||
"homepage": "https://larsjung.de/pagemap/",
|
||||
"bugs": "https://github.com/lrsjng/pagemap/issues",
|
||||
@@ -13,17 +13,20 @@
|
||||
"main": "dist/pagemap",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"build": "rimraf dist && webpack",
|
||||
"precommit": "npm run -s lint && npm run -s build"
|
||||
"test": "node test",
|
||||
"check": "npm run -s lint && npm run -s test",
|
||||
"build": "node ghu release",
|
||||
"precommit": "npm run -s check && npm run -s build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-loader": "6.2.4",
|
||||
"babel-preset-es2015": "6.9.0",
|
||||
"eslint": "2.12.0",
|
||||
"rimraf": "2.5.2",
|
||||
"webpack": "1.13.1"
|
||||
"@babel/core": "7.8.4",
|
||||
"@babel/preset-env": "7.8.4",
|
||||
"eslint": "6.8.0",
|
||||
"ghu": "0.25.0",
|
||||
"jsdom": "16.2.0",
|
||||
"scar": "2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
}
|
||||
|
34
src/demo/boxes.html
Normal file
34
src/demo/boxes.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>pagemap demo - boxes</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body id="boxes-demo" class="checkers">
|
||||
<div id="banner">
|
||||
<div><a href="https://larsjung.de/pagemap/">pagemap</a> demo</div>
|
||||
<div><a href="text.html">text</a> - <strong>boxes</strong></div>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="content" class="checkers">
|
||||
<div id="container2">
|
||||
<div id="content2" class="checkers"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas id="map"></canvas>
|
||||
|
||||
<script src="pagemap.min.js"></script>
|
||||
<script>
|
||||
pagemap(document.querySelector('#map'), {
|
||||
// viewport: document.querySelector('#container'),
|
||||
interval: 50,
|
||||
styles: { div: 'rgba(0,0,0,0.1)' },
|
||||
back: 'rgba(255,255,255,1)'
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
111
src/demo/styles.css
Normal file
111
src/demo/styles.css
Normal file
@@ -0,0 +1,111 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Ubuntu, sans;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
body#boxes-demo {
|
||||
width: 2000px;
|
||||
height: 2000px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
a, a:visited, a:active {
|
||||
color: #1d77c2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: 3em auto 6em auto;
|
||||
max-width: 800px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
font-weight: normal;
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.8em;
|
||||
font-weight: normal;
|
||||
margin: 3em 0 1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
margin: 2em 0 1em;
|
||||
}
|
||||
|
||||
#banner {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
font-size: 16px;
|
||||
margin: 4px;
|
||||
padding: 4px 12px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
background: rgba(255,255,255,0.8);
|
||||
border: 1px solid rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
#map {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 160px;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
outline: 4px solid #222;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 800px;
|
||||
height: 1000px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
#container2 {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
outline: 4px solid #222;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#content2 {
|
||||
width: 500px;
|
||||
height: 600px;
|
||||
background-color: #aaa;
|
||||
}
|
||||
|
||||
.checkers {
|
||||
background-image:
|
||||
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
|
||||
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
|
||||
background-size: 100px 100px;
|
||||
background-position: 0 0, 50px 50px
|
||||
}
|
@@ -2,51 +2,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>pagemap text demo</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#map {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
body {
|
||||
font-family: Bitter, Ubuntu, Arial, sans;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
main {
|
||||
margin: 3em auto 6em auto;
|
||||
max-width: 800px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
font-weight: normal;
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.8em;
|
||||
font-weight: normal;
|
||||
margin: 3em 0 1em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
margin: 2em 0 1em;
|
||||
}
|
||||
a {
|
||||
color: #1E88E5;
|
||||
}
|
||||
</style>
|
||||
<title>pagemap demo - text</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<body id="text-demo">
|
||||
<div id="banner">
|
||||
<div><a href="https://larsjung.de/pagemap/">pagemap</a> demo</div>
|
||||
<div><strong>text</strong> - <a href="boxes.html">boxes</a></div>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<header>
|
||||
<h1>At Eos Accusamu</h1>
|
||||
@@ -80,7 +44,7 @@
|
||||
|
||||
<canvas id="map"></canvas>
|
||||
|
||||
<script src="../dist/pagemap.js"></script>
|
||||
<script src="pagemap.min.js"></script>
|
||||
<script>
|
||||
pagemap(document.querySelector('#map'));
|
||||
</script>
|
176
src/pagemap.js
Normal file
176
src/pagemap.js
Normal file
@@ -0,0 +1,176 @@
|
||||
module.exports = (canvas, options) => {
|
||||
const WIN = global.window;
|
||||
const DOC = WIN.document;
|
||||
const DOC_EL = DOC.documentElement;
|
||||
const BODY = DOC.querySelector('body');
|
||||
const CTX = canvas.getContext('2d');
|
||||
|
||||
const black = pc => `rgba(0,0,0,${pc / 100})`;
|
||||
const settings = Object.assign({
|
||||
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
|
||||
}, options);
|
||||
|
||||
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);
|
||||
|
||||
const Rect = (x, y, w, h) => { return {x, y, w, h}; };
|
||||
|
||||
const rect_rel_to = (rect, pos = {x: 0, y: 0}) => {
|
||||
return Rect(rect.x - pos.x, rect.y - pos.y, rect.w, rect.h);
|
||||
};
|
||||
|
||||
const rect_of_doc = () => {
|
||||
return Rect(0, 0, DOC_EL.scrollWidth, DOC_EL.scrollHeight);
|
||||
};
|
||||
|
||||
const rect_of_win = () => {
|
||||
return Rect(WIN.pageXOffset, WIN.pageYOffset, DOC_EL.clientWidth, DOC_EL.clientHeight);
|
||||
};
|
||||
|
||||
const el_get_offset = el => {
|
||||
const br = el.getBoundingClientRect();
|
||||
return {x: br.left + WIN.pageXOffset, y: br.top + WIN.pageYOffset};
|
||||
};
|
||||
|
||||
const rect_of_el = el => {
|
||||
const {x, y} = el_get_offset(el);
|
||||
return Rect(x, y, el.offsetWidth, el.offsetHeight);
|
||||
};
|
||||
|
||||
const rect_of_viewport = el => {
|
||||
const {x, y} = el_get_offset(el);
|
||||
return Rect(x + el.clientLeft, y + el.clientTop, el.clientWidth, el.clientHeight);
|
||||
};
|
||||
|
||||
const rect_of_content = el => {
|
||||
const {x, y} = el_get_offset(el);
|
||||
return Rect(x + el.clientLeft - el.scrollLeft, y + el.clientTop - el.scrollTop, el.scrollWidth, el.scrollHeight);
|
||||
};
|
||||
|
||||
const calc_scale = (() => {
|
||||
const width = canvas.clientWidth;
|
||||
const height = canvas.clientHeight;
|
||||
return (w, h) => Math.min(width / w, height / h);
|
||||
})();
|
||||
|
||||
const resize_canvas = (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 root_rect;
|
||||
let view_rect;
|
||||
let scale;
|
||||
let drag_rx;
|
||||
let drag_ry;
|
||||
|
||||
const draw_rect = (rect, col) => {
|
||||
if (col) {
|
||||
CTX.beginPath();
|
||||
CTX.rect(rect.x, rect.y, rect.w, rect.h);
|
||||
CTX.fillStyle = col;
|
||||
CTX.fill();
|
||||
}
|
||||
};
|
||||
|
||||
const apply_styles = styles => {
|
||||
Object.keys(styles).forEach(sel => {
|
||||
const col = styles[sel];
|
||||
find(sel).forEach(el => {
|
||||
draw_rect(rect_rel_to(rect_of_el(el), root_rect), col);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const draw = () => {
|
||||
root_rect = viewport ? rect_of_content(viewport) : rect_of_doc();
|
||||
view_rect = viewport ? rect_of_viewport(viewport) : rect_of_win();
|
||||
scale = calc_scale(root_rect.w, root_rect.h);
|
||||
|
||||
resize_canvas(root_rect.w * scale, root_rect.h * scale);
|
||||
|
||||
CTX.setTransform(1, 0, 0, 1, 0, 0);
|
||||
CTX.clearRect(0, 0, canvas.width, canvas.height);
|
||||
CTX.scale(scale, scale);
|
||||
|
||||
draw_rect(rect_rel_to(root_rect, root_rect), settings.back);
|
||||
apply_styles(settings.styles);
|
||||
draw_rect(rect_rel_to(view_rect, root_rect), drag ? settings.drag : settings.view);
|
||||
};
|
||||
|
||||
const on_drag = ev => {
|
||||
ev.preventDefault();
|
||||
const cr = rect_of_viewport(canvas);
|
||||
const x = (ev.pageX - cr.x) / scale - view_rect.w * drag_rx;
|
||||
const y = (ev.pageY - cr.y) / scale - view_rect.h * drag_ry;
|
||||
|
||||
if (viewport) {
|
||||
viewport.scrollLeft = x;
|
||||
viewport.scrollTop = y;
|
||||
} else {
|
||||
WIN.scrollTo(x, y);
|
||||
}
|
||||
draw();
|
||||
};
|
||||
|
||||
const on_drag_end = ev => {
|
||||
drag = false;
|
||||
canvas.style.cursor = 'pointer';
|
||||
BODY.style.cursor = 'auto';
|
||||
off(WIN, 'mousemove', on_drag);
|
||||
off(WIN, 'mouseup', on_drag_end);
|
||||
on_drag(ev);
|
||||
};
|
||||
|
||||
const on_drag_start = ev => {
|
||||
drag = true;
|
||||
|
||||
const cr = rect_of_viewport(canvas);
|
||||
const vr = rect_rel_to(view_rect, root_rect);
|
||||
drag_rx = ((ev.pageX - cr.x) / scale - vr.x) / vr.w;
|
||||
drag_ry = ((ev.pageY - cr.y) / scale - vr.y) / vr.h;
|
||||
if (drag_rx < 0 || drag_rx > 1 || drag_ry < 0 || drag_ry > 1) {
|
||||
drag_rx = 0.5;
|
||||
drag_ry = 0.5;
|
||||
}
|
||||
|
||||
canvas.style.cursor = 'crosshair';
|
||||
BODY.style.cursor = 'crosshair';
|
||||
on(WIN, 'mousemove', on_drag);
|
||||
on(WIN, 'mouseup', on_drag_end);
|
||||
on_drag(ev);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
canvas.style.cursor = 'pointer';
|
||||
on(canvas, 'mousedown', on_drag_start);
|
||||
on(viewport || WIN, 'load resize scroll', draw);
|
||||
if (settings.interval > 0) {
|
||||
setInterval(() => draw(), settings.interval);
|
||||
}
|
||||
draw();
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
return {
|
||||
redraw: draw
|
||||
};
|
||||
};
|
24
test/index.js
Normal file
24
test/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const {test, assert} = require('scar');
|
||||
const pagemap = require('../src/pagemap');
|
||||
|
||||
if (!global.window) {
|
||||
global.window = new (require('jsdom')).JSDOM().window;
|
||||
}
|
||||
|
||||
test('access', () => {
|
||||
assert.equal(typeof pagemap, 'function');
|
||||
});
|
||||
|
||||
test('no canvas throws', () => {
|
||||
assert.throws(() => pagemap(), /getContext/);
|
||||
assert.throws(() => pagemap(true), /getContext/);
|
||||
assert.throws(() => pagemap({}, {}), /getContext/);
|
||||
});
|
||||
|
||||
// test('basic canvas', () => {
|
||||
// const canvas = global.window.document.createElement('canvas');
|
||||
// const res = pagemap(canvas);
|
||||
// assert.equal(typeof res, 'object');
|
||||
// });
|
||||
|
||||
test.cli();
|
@@ -1,28 +0,0 @@
|
||||
const webpack = require('webpack');
|
||||
const pkg = require('./package.json');
|
||||
const banner = `${pkg.name} v${pkg.version} - ${pkg.homepage}`;
|
||||
|
||||
module.exports = {
|
||||
entry: './lib/pagemap.js',
|
||||
output: {
|
||||
path: './dist',
|
||||
filename: 'pagemap.js',
|
||||
library: 'pagemap',
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
module: {
|
||||
loaders: [{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
cacheDirectory: true,
|
||||
presets: ['es2015']
|
||||
}
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin(banner),
|
||||
new webpack.optimize.UglifyJsPlugin()
|
||||
]
|
||||
};
|
Reference in New Issue
Block a user