mirror of
https://github.com/wassname/template.git
synced 2026-07-20 12:40:52 +08:00
Finish initial work on d-figure
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
"@webcomponents/webcomponentsjs": "^1.0.7",
|
||||
"assert": "^1.4.1",
|
||||
"d3-time-format": "^2.0.3",
|
||||
"intersection-observer": "^0.4.0",
|
||||
"jsdom-wc": "^11.0.0-alpha-1",
|
||||
"katex": "^0.7.1"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ componentsConfig.plugins.push(copy({
|
||||
'./node_modules/katex/dist/fonts': 'dist/fonts',
|
||||
'./node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js': 'dist/webcomponents-lite.js',
|
||||
'./node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js.map': 'dist/webcomponents-lite.js.map',
|
||||
'./node_modules/intersection-observer/intersection-observer.js': 'dist/intersection-observer.js',
|
||||
}));
|
||||
Object.assign(transformsConfig, defaultConfig);
|
||||
|
||||
|
||||
+77
-81
@@ -1,28 +1,17 @@
|
||||
`Figure
|
||||
|
||||
d-figure provides a state-machine of visibility events:
|
||||
|
||||
scroll out of view
|
||||
+----------------+
|
||||
*do work here* | |
|
||||
+------+ +----------------+ +-+---------+ +-v---------+
|
||||
| init +----> almostonscreen +----> onscreen | | offscreen |
|
||||
+------+ +----------------+ +---------^-+ +---------+-+
|
||||
| |
|
||||
+----------------+
|
||||
scroll into view
|
||||
|
||||
TODO:
|
||||
* default styling
|
||||
* get rid of init state?
|
||||
* shadow dom?
|
||||
* resizing/default size?
|
||||
* offer centerscreen event?
|
||||
* polyfills
|
||||
|
||||
`
|
||||
|
||||
const intersectionMargin = 1000;
|
||||
// Figure
|
||||
//
|
||||
// d-figure provides a state-machine of visibility events:
|
||||
//
|
||||
// scroll out of view
|
||||
// +----------------+
|
||||
// *do work here* | |
|
||||
// +----------------+ +-+---------+ +-v---------+
|
||||
// | ready +----> onscreen | | offscreen |
|
||||
// +----------------+ +---------^-+ +---------+-+
|
||||
// | |
|
||||
// +----------------+
|
||||
// scroll into view
|
||||
//
|
||||
|
||||
export class Figure extends HTMLElement {
|
||||
|
||||
@@ -30,81 +19,88 @@ export class Figure extends HTMLElement {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// keep track of communicated state
|
||||
this._init = false;
|
||||
this._ready = false;
|
||||
this._onscreen = false;
|
||||
this._offscreen = true;
|
||||
|
||||
// we use two separate observers:
|
||||
// one with an extra 1000px margin to warn if the viewpoint gets close,
|
||||
// and one for the actual on/off screen events
|
||||
this._marginObserver = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting && !this._almostonscreen) {
|
||||
this.almostonscreen();
|
||||
this._marginObserver.disconnect();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
root: null, // listen on entire viewport
|
||||
rootMargin: intersectionMargin + 'px 0px ' + intersectionMargin + 'px 0px',
|
||||
threshold: 1.0,
|
||||
});
|
||||
this._directObserver = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
if (!this._almostonscreen) { this.almostonscreen(); }
|
||||
if (this._offscreen) { this.onscreen(); }
|
||||
} else {
|
||||
if (this._onscreen) { this.offscreen(); }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
root: null, // listen on entire viewport
|
||||
rootMargin: '0px',
|
||||
threshold: [0, 1.0],
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._marginObserver.observe(this);
|
||||
this._directObserver.observe(this);
|
||||
this.init();
|
||||
Figure.marginObserver.observe(this);
|
||||
Figure.directObserver.observe(this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
Figure.marginObserver.unobserve(this);
|
||||
Figure.directObserver.unobserve(this);
|
||||
}
|
||||
|
||||
/* Override addEventListener
|
||||
* We want to notify elements that register late as well.
|
||||
*/
|
||||
// We use two separate observers:
|
||||
// One with an extra 1000px margin to warn if the viewpoint gets close,
|
||||
// And one for the actual on/off screen events
|
||||
|
||||
static get marginObserver() {
|
||||
if (!Figure._marginObserver) {
|
||||
const viewportHeight = window.innerHeight;
|
||||
const margin = Math.floor(2 * viewportHeight);
|
||||
Figure._marginObserver = new IntersectionObserver(
|
||||
Figure.didObserveMarginIntersection, {
|
||||
rootMargin: margin + 'px 0px ' + margin + 'px 0px', threshold: 0.01,
|
||||
});
|
||||
}
|
||||
return Figure._marginObserver;
|
||||
}
|
||||
|
||||
static didObserveMarginIntersection(entries) {
|
||||
for (const entry of entries) {
|
||||
const figure = entry.target;
|
||||
if (entry.isIntersecting && !figure._ready) {
|
||||
figure.ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static get directObserver() {
|
||||
if (!Figure._directObserver) {
|
||||
Figure._directObserver = new IntersectionObserver(
|
||||
Figure.didObserveDirectIntersection, {
|
||||
rootMargin: '0px', threshold: [0, 1.0],
|
||||
}
|
||||
);
|
||||
}
|
||||
return Figure._directObserver;
|
||||
}
|
||||
|
||||
static didObserveDirectIntersection(entries) {
|
||||
for (const entry of entries) {
|
||||
const figure = entry.target;
|
||||
if (entry.isIntersecting) {
|
||||
if (!figure._ready) { figure.ready(); }
|
||||
if (figure._offscreen) { figure.onscreen(); }
|
||||
} else {
|
||||
if (figure._onscreen) { figure.offscreen(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners that registered late, too:
|
||||
|
||||
addEventListener(eventName, callback) {
|
||||
super.addEventListener(eventName, callback);
|
||||
// if we had already dispatched something while presumingly no one was listening, we do so again
|
||||
if (this._init && eventName === 'init') {
|
||||
this.init();
|
||||
}
|
||||
if (this._almostonscreen && eventName === 'almostonscreen') {
|
||||
this.almostonscreen();
|
||||
if (this._ready && eventName === 'ready') {
|
||||
this.ready();
|
||||
}
|
||||
if (this._onscreen && eventName === 'onscreen') {
|
||||
this.onscreen();
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Events
|
||||
|
||||
/* Custom Events */
|
||||
|
||||
init() {
|
||||
this._init = true;
|
||||
const event = new CustomEvent('init');
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
almostonscreen() {
|
||||
this._almostonscreen = true;
|
||||
const event = new CustomEvent('almostonscreen');
|
||||
ready() {
|
||||
this._ready = true;
|
||||
this.marginObserver.unobserve(this);
|
||||
const event = new CustomEvent('ready');
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ d-article > * {
|
||||
grid-column: margin-left / body;
|
||||
}
|
||||
|
||||
.l-page {
|
||||
.l-page,
|
||||
d-figure {
|
||||
grid-column: margin-left / page;
|
||||
}
|
||||
|
||||
|
||||
+32
-11
@@ -1,17 +1,38 @@
|
||||
const webcomponentPath = '../dist/webcomponents-lite.js';
|
||||
const intersectionObserverPath = '../dist/intersection-observer.js';
|
||||
|
||||
const template = `
|
||||
if ('registerElement' in document &&
|
||||
'import' in document.createElement('link') &&
|
||||
'content' in document.createElement('template')) {
|
||||
// Platform supports webcomponents natively! :-)
|
||||
} else {
|
||||
// Platform does not support webcomponents--loading polyfills synchronously.
|
||||
const scriptTag = document.createElement('script');
|
||||
scriptTag.src = '${webcomponentPath}';
|
||||
scriptTag.async = false;
|
||||
document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling);
|
||||
}
|
||||
if ('IntersectionObserver' in window &&
|
||||
'IntersectionObserverEntry' in window &&
|
||||
'intersectionRatio' in IntersectionObserverEntry.prototype) {
|
||||
// Platform supports IntersectionObserver natively! :-)
|
||||
if (!('isIntersecting' in IntersectionObserverEntry.prototype)) {
|
||||
Object.defineProperty(IntersectionObserverEntry.prototype,
|
||||
'isIntersecting', {
|
||||
get: function () {
|
||||
return this.intersectionRatio > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Platform does not support webcomponents--loading polyfills synchronously.
|
||||
const scriptTag = document.createElement('script');
|
||||
scriptTag.src = '${intersectionObserverPath}';
|
||||
scriptTag.async = false;
|
||||
document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling);
|
||||
}
|
||||
|
||||
if ('registerElement' in document &&
|
||||
'import' in document.createElement('link') &&
|
||||
'content' in document.createElement('template')) {
|
||||
// Platform supports webcomponents natively! :-)
|
||||
} else {
|
||||
// Platform does not support webcomponents--loading polyfills synchronously.
|
||||
const scriptTag = document.createElement('script');
|
||||
scriptTag.src = '${webcomponentPath}';
|
||||
scriptTag.async = false;
|
||||
document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling);
|
||||
}
|
||||
`;
|
||||
|
||||
export default function render(dom) {
|
||||
|
||||
Reference in New Issue
Block a user