@svelte-plugins/viewable
Advanced tools
Comparing version 0.1.3 to 1.0.0
@@ -8,4 +8,14 @@ # Changelog | ||
## [1.0.0](https://github.com/svelte-plugins/svelte-viewable/releases/tag/v1.0.0) - 2021-04-02 | ||
- Interface changes that include exposing observer props and events | ||
- Includes new `on:complete` event | ||
- Replaced `enableObstructionDetection` with `detectObstructions` | ||
## [0.1.3](https://github.com/svelte-plugins/svelte-viewable/releases/tag/v0.1.3) - 2021-04-01 | ||
- Enable SSR support | ||
## [0.1.0](https://github.com/svelte-plugins/svelte-viewable/releases/tag/v0.1.0) - 2021-03-29 | ||
- Initial release |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self)["@svelte-plugins/viewable"]=t()}(this,(function(){"use strict";function e(e){return e()}function t(t){t.forEach(e)}let n;function o(e){n=e}function i(){if(!n)throw new Error("Function called outside component initialization");return n}const r=[],l=[],c=[],d=[],s=Promise.resolve();let a=!1;function u(){return a||(a=!0,s.then(p)),s}function h(e){c.push(e)}let f=!1;const g=new Set;function p(){if(!f){f=!0;do{for(let e=0;e<r.length;e+=1){const t=r[e];o(t),v(t.$$)}for(o(null),r.length=0;l.length;)l.pop()();for(let e=0;e<c.length;e+=1){const t=c[e];g.has(t)||(g.add(t),t())}c.length=0}while(r.length);for(;d.length;)d.pop()();a=!1,f=!1,g.clear()}}function v(e){if(null!==e.fragment){e.update(),t(e.before_update);const n=e.dirty;e.dirty=[-1],e.fragment&&e.fragment.p(e.ctx,n),e.after_update.forEach(h)}}let b;return function(e){function i(t,i,r,l){const c=n;o({$$:{on_destroy:b,context:new Map(c?c.$$.context:[]),on_mount:[],before_update:[],after_update:[],callbacks:Object.create(null)}});const d=e(t,i,r,l);return o(c),d}return{render:(e={},n={})=>{b=[];const o={title:"",head:"",css:new Set},r=i(o,e,{},n);return t(b),{html:r,css:{code:Array.from(o.css).map((e=>e.code)).join("\n"),map:null},head:o.title+o.head}},$$render:i}}(((e,t,n,o)=>{let{element:r}=t,{rules:l}=t,{debug:c=!1}=t,{duration:d=0}=t,{percent:s=0}=t,{percentX:a=0}=t,{percentY:h=0}=t,{intervalRate:f=200}=t,{gridSize:g=20}=t,{enableObstructionDetection:p=!1}=t,v=null,b=null;const m=[],w=(...e)=>c&&console.log(...e),y=(e,t)=>{const n=(e=>{const t=g+1,n=Math.floor(e.width/t),o=Math.floor(e.height/t),i=Math.max(0,e.left),r=e.top,l=[];for(let e=1;e<t;e++){const c=i+n*e;for(let e=1;e<t;e++){const t=r+o*e;l[l.length]=[c,t]}}return l})(e);let o=0;for(let e=0,t=n.length;e<t;e++){const t=n[e][0],i=n[e][1],l=document.elementFromPoint(t,i);l===r||r.contains(l)||o++}const i=100*t,l=100-o/n.length*100,c=l<i;return c&&(s=l.toFixed(0)),c},$=e=>{const t=(()=>{const e=document.body,t=document.documentElement;return{height:window.innerHeight||t.clientHeight||e&&e.clientHeight,width:window.innerWidth||t.clientWidth||e&&e.clientWidth}})(),n=r.getBoundingClientRect(),o=Math.max(0,Math.min(n.bottom,t.height)-Math.max(n.top,0)),i=Math.max(0,Math.min(n.right,t.width)-Math.max(n.left,0)),l=o/(n.height||r.offsetHeight)||0,c=i/(n.width||r.offsetWidth)||0,d=Math.max(0,l+c-1);return a=(100*c).toFixed(0),h=(100*l).toFixed(0),s=(100*d).toFixed(0),p&&y(n,e)?0:d},x=()=>{const e=m.length;for(let t=0;t<e;t++){const e=m[t];if(e)if($(e.threshold)<e.threshold)e.history=null;else if(e.history||(d=0,e.history=Date.now()),d=(Date.now()-e.history)/1e3,w(`[ Tracking - ${d} - ${e.rule}]`),d>=e.duration&&(e.observer&&e.observer.unobserve(r),e.callback(e),e.history=Date.now(),m.splice(t,1),t-=1,w(m),!m.length)){w(`[ Finished - ${e.history} ]`),b&&(clearInterval(b),b=null);break}}},M=e=>{const t=t=>{const n=t[0];n.isIntersecting?n.isIntersecting&&!b&&(b=setInterval(x,f),x()):e.history=null};if(!e.observer){const n=new IntersectionObserver(t,{threshold:[0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1]});n.observe(r),e.observer=n}};var _;return _=async()=>{await u(),null===r||v||((()=>{for(let e in l){const t=l[e],{duration:n=0,percentage:o=0,fn:i,...r}=t,c={...r,percentage:o,threshold:o/100,duration:n,callback:function(e){i(e),w("[ Viewable Rule ]\n"+JSON.stringify({...e},null,2))},rule:e,history:null};m.push(c),M(c)}})(),v=!0)},i().$$.after_update.push(_),function(e){i().$$.on_destroy.push(e)}((()=>{m.forEach((e=>{e.observer&&e.observer.disconnect()}))})),void 0===t.element&&n.element&&void 0!==r&&n.element(r),void 0===t.rules&&n.rules&&void 0!==l&&n.rules(l),void 0===t.debug&&n.debug&&void 0!==c&&n.debug(c),void 0===t.duration&&n.duration&&void 0!==d&&n.duration(d),void 0===t.percent&&n.percent&&void 0!==s&&n.percent(s),void 0===t.percentX&&n.percentX&&void 0!==a&&n.percentX(a),void 0===t.percentY&&n.percentY&&void 0!==h&&n.percentY(h),void 0===t.intervalRate&&n.intervalRate&&void 0!==f&&n.intervalRate(f),void 0===t.gridSize&&n.gridSize&&void 0!==g&&n.gridSize(g),void 0===t.enableObstructionDetection&&n.enableObstructionDetection&&void 0!==p&&n.enableObstructionDetection(p),`${o.default?o.default({}):""}`}))})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self)["@svelte-plugins/viewable"]=t()}(this,(function(){"use strict";function e(e){return e()}function t(t){t.forEach(e)}let n;function o(e){n=e}function r(){if(!n)throw new Error("Function called outside component initialization");return n}function i(){const e=r();return(t,n)=>{const o=e.$$.callbacks[t];if(o){const r=function(e,t){const n=document.createEvent("CustomEvent");return n.initCustomEvent(e,!1,!1,t),n}(t,n);o.slice().forEach((t=>{t.call(e,r)}))}}}const l=[],c=[],s=[],d=[],u=Promise.resolve();let a=!1;function h(){return a||(a=!0,u.then(p)),u}function f(e){s.push(e)}let g=!1;const v=new Set;function p(){if(!g){g=!0;do{for(let e=0;e<l.length;e+=1){const t=l[e];o(t),m(t.$$)}for(o(null),l.length=0;c.length;)c.pop()();for(let e=0;e<s.length;e+=1){const t=s[e];v.has(t)||(v.add(t),t())}s.length=0}while(l.length);for(;d.length;)d.pop()();a=!1,g=!1,v.clear()}}function m(e){if(null!==e.fragment){e.update(),t(e.before_update);const n=e.dirty;e.dirty=[-1],e.fragment&&e.fragment.p(e.ctx,n),e.after_update.forEach(f)}}let b;return function(e){function r(t,r,i,l){const c=n;o({$$:{on_destroy:b,context:new Map(c?c.$$.context:[]),on_mount:[],before_update:[],after_update:[],callbacks:Object.create(null)}});const s=e(t,r,i,l);return o(c),s}return{render:(e={},n={})=>{b=[];const o={title:"",head:"",css:new Set},i=r(o,e,{},n);return t(b),{html:i,css:{code:Array.from(o.css).map((e=>e.code)).join("\n"),map:null},head:o.title+o.head}},$$render:r}}(((e,t,n,o)=>{let{element:l}=t,{rules:c}=t,{debug:s=!1}=t,{duration:d=0}=t,{percent:u=0}=t,{percentX:a=0}=t,{percentY:f=0}=t,{intervalRate:g=200}=t,{gridSize:v=20}=t,{detectObstructions:p=!1}=t,{root:m=null}=t,{rootMargin:b="0px"}=t,{threshold:y=[0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1]}=t,{entry:w=null}=t,{intersecting:$=!1}=t,{observer:x=null}=t,M=null,E=null;const _=i(),F=[],I=(...e)=>s&&console.log(...e),O=(e,t)=>{const n=(e=>{const t=v+1,n=Math.floor(e.width/t),o=Math.floor(e.height/t),r=Math.max(0,e.left),i=e.top,l=[];for(let e=1;e<t;e++){const c=r+n*e;for(let e=1;e<t;e++){const t=i+o*e;l[l.length]=[c,t]}}return l})(e);let o=0;for(let e=0,t=n.length;e<t;e++){const t=n[e][0],r=n[e][1],i=document.elementFromPoint(t,r);i===l||l.contains(i)||o++}const r=100*t,i=100-o/n.length*100,c=i<r;return c&&(u=i.toFixed(0)),c},S=e=>{const t=(()=>{const e=document.body,t=document.documentElement;return{height:window.innerHeight||t.clientHeight||e&&e.clientHeight,width:window.innerWidth||t.clientWidth||e&&e.clientWidth}})(),n=l.getBoundingClientRect(),o=Math.max(0,Math.min(n.bottom,t.height)-Math.max(n.top,0)),r=Math.max(0,Math.min(n.right,t.width)-Math.max(n.left,0)),i=o/(n.height||l.offsetHeight)||0,c=r/(n.width||l.offsetWidth)||0,s=Math.max(0,i+c-1);return a=(100*c).toFixed(0),f=(100*i).toFixed(0),u=(100*s).toFixed(0),p&&O(n,e)?0:s},k=()=>{const e=F.length;for(let t=0;t<e;t++){const e=F[t];if(e)if(S(e.threshold)<e.threshold)e.history=null;else if(e.history||(d=0,e.history=Date.now()),d=(Date.now()-e.history)/1e3,I(`[ Tracking - ${d} - ${e.rule}]`),d>=e.duration&&(e.callback(e),e.history=Date.now(),e.repeat||(F.splice(t,1),t-=1),I(F),!F.length)){I(`[ Finished - ${e.history} ]`),_("complete",c),x&&(x.unobserve(l),x.disconnect()),E&&(clearInterval(E),E=null);break}}},R=e=>{x||(x=new IntersectionObserver((t=>{w=t[0],$=w.isIntersecting,w.isIntersecting?w.isIntersecting&&!E&&(E=setInterval(k,g),k()):e.history=null}),{root:m,rootMargin:b,threshold:y}),x.observe(l))};var z;return z=async()=>{null!==w&&(_("observe",w),w.isIntersecting&&_("intersect",w)),await h(),null===l||M||((()=>{for(let e in c){const t=c[e],{duration:n=0,percentage:o=0,fn:r,...i}=t,l={...i,percentage:o,threshold:o/100,duration:n,callback:function(e){r(e),I("[ Viewable Rule ]\n"+JSON.stringify({...e},null,2))},rule:e,history:null};F.push(l),R(l)}})(),M=!0)},r().$$.after_update.push(z),function(e){r().$$.on_destroy.push(e)}((()=>x&&x.disconnect())),void 0===t.element&&n.element&&void 0!==l&&n.element(l),void 0===t.rules&&n.rules&&void 0!==c&&n.rules(c),void 0===t.debug&&n.debug&&void 0!==s&&n.debug(s),void 0===t.duration&&n.duration&&void 0!==d&&n.duration(d),void 0===t.percent&&n.percent&&void 0!==u&&n.percent(u),void 0===t.percentX&&n.percentX&&void 0!==a&&n.percentX(a),void 0===t.percentY&&n.percentY&&void 0!==f&&n.percentY(f),void 0===t.intervalRate&&n.intervalRate&&void 0!==g&&n.intervalRate(g),void 0===t.gridSize&&n.gridSize&&void 0!==v&&n.gridSize(v),void 0===t.detectObstructions&&n.detectObstructions&&void 0!==p&&n.detectObstructions(p),void 0===t.root&&n.root&&void 0!==m&&n.root(m),void 0===t.rootMargin&&n.rootMargin&&void 0!==b&&n.rootMargin(b),void 0===t.threshold&&n.threshold&&void 0!==y&&n.threshold(y),void 0===t.entry&&n.entry&&void 0!==w&&n.entry(w),void 0===t.intersecting&&n.intersecting&&void 0!==$&&n.intersecting($),void 0===t.observer&&n.observer&&void 0!==x&&n.observer(x),`${o.default?o.default({duration:d,entry:w,intersecting:$,observer:x,percent:u,percentX:a,percentY:f}):""}`}))})); |
{ | ||
"name": "@svelte-plugins/viewable", | ||
"version": "0.1.3", | ||
"version": "1.0.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "description": "A simple rule-based approach to tracking element viewability.", |
@@ -48,2 +48,60 @@ [![Run unit tests](https://github.com/svelte-plugins/viewable/actions/workflows/run-unit.yml/badge.svg)](https://github.com/svelte-plugins/viewable/actions/workflows/run-unit.yml) | ||
Try the basic example in [Svelte REPL](https://svelte.dev/repl/c811481b8e1b48e9bed0f6ff7d1fa9c2). | ||
## API | ||
### Props | ||
| Prop name | Description | Value | | ||
| :----------- | :---------------------------------------------------------------- | :---------------------------------------------------------------------------------------------- | | ||
| element | Element to observe | `HTMLElement` | | ||
| rules | Viewability rules | `object` (default: `null`) | | ||
| intervalRate | Rate to check measurement while intersecting (ms) | `number` (default: `200`) | | ||
| gridSize | Size of the obstruction grid | `number` (default: `20`) | | ||
| detectObstructions | If `true`, obstructions impacting the element will affect measurement | 'boolean' (default: `false`) | | ||
| root | Containing element | `null` or `HTMLElement` (default: `null`) | | ||
| rootMargin | Margin offset of the containing element | `string` (default: `"0px"`) | | ||
| intersecting | `true` if the observed element is intersecting | `boolean` (default: `false`) | | ||
| observer | IntersectionObserver instance | [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) | | ||
| entry | Observed element metadata | [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | | ||
| debug | If `true`, debug ouput will be logged to console | `boolean` (default: `false`) | | ||
#### rules | ||
| Prop name | Description | Value | | ||
| :----------- | :------------------------------------------------------------------ | :---------------------------------- | | ||
| duration | Consecutive time (seconds) that the element must be in view | `number` (default: `0`) | | ||
| percentage | Percentage of the element that must be viewable | `number` (default: `0`) | | ||
| repeat | If `true`, the rule will be applied indefinitely v once | `function` (default: `null`) | | ||
| fn | Callback function to execute when rule has been met | `function` (default: `null`) | | ||
```js | ||
const rules = { | ||
dwell: { | ||
duration: 1, | ||
percentage: 50, | ||
fn: () => { | ||
console.log('50% of the element was visible for at least 1 consecutive second.'); | ||
} | ||
} | ||
} | ||
``` | ||
### Debug props | ||
The properties below can be used to assist with debugging any issues you might have (ex: `bind:duration`, `bind:percent`, etc.) | ||
| Prop name | Description | Value | | ||
| :----------- | :---------------------------------------------------------------- | :---------------------- | | ||
| duration | Viewable duration of the tracked element | `number` (default: `0`) | | ||
| percent | Percentage of total viewable area (X+Y) | `number` (default: `0`) | | ||
| percentX | Percentage of horizontal viewable area | `number` (default: `0`) | | ||
| percentY | Percentage of vertical viewable area | `number` (default: `0`) | | ||
### Events | ||
- **on:observe**: Fired when an intersection change occurs (type `IntersectionObserverEntry`) | ||
- **on:intersect**: Fired when an intersection change occurs and the element is intersecting (type `IntersectionObserverEntry`) | ||
- **on:complete**: Fired when all rules have been executed | ||
## Changelog | ||
@@ -50,0 +108,0 @@ |
@@ -57,3 +57,3 @@ import { render } from '@testing-library/svelte'; | ||
await TestHarness({ debug: true, enableObstructionDetection: true, rules: { immediate: { fn: mock } } }); | ||
await TestHarness({ debug: true, detectObstructions: true, rules: { immediate: { fn: mock } } }); | ||
@@ -75,3 +75,3 @@ onIntersectionMock([{ isIntersecting: true }]); | ||
const { container } = await TestHarness({ | ||
enableObstructionDetection: true, | ||
detectObstructions: true, | ||
rules: { | ||
@@ -78,0 +78,0 @@ fifty4six: { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
33332
130
0
113