New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

creepyface

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

creepyface - npm Package Compare versions

Comparing version

to
6.0.0

dist/observables/util/debounce.d.ts

4

dist/creepyface.d.ts
import { UserOptions } from './util/options';
import { Cancel } from './util/types';
import { Cancel, Observable } from './util/types';
import { Point } from './util/algebra';
declare const creepyface: {
(img: HTMLImageElement, options?: UserOptions | undefined): Cancel;
cancel(img: HTMLImageElement): void;
registerObservable(name: string, observable: Observable<Point>): void;
};
export default creepyface;
import attach from './util/attach';
import watchElement from './util/watch-element';
import noop from './util/noop';
import * as observableStore from './observables/util/store';
const creepyface = (img, options) => {
creepyface.cancel(img);
let detach = noop;
const creepyImage = img;
const stopWatching = watchElement(img, () => {
detach = attach(creepyImage, options);
detach = attach(img, options);
}, () => creepyface.cancel(img));
return (creepyImage.creepyfaceCancel = () => {
return (img.creepyfaceCancel = () => {
stopWatching();
detach();
delete creepyImage.creepyfaceCancel;
delete img.creepyfaceCancel;
});
};
creepyface.cancel = (img) => {
const creepyImage = img;
if (creepyImage.creepyfaceCancel)
creepyImage.creepyfaceCancel();
const cancel = img.creepyfaceCancel;
if (cancel)
cancel();
};
creepyface.registerObservable = (name, observable) => {
observableStore.register(name, observable);
};
document.addEventListener('DOMContentLoaded', () => {
;
[...document.querySelectorAll('img[data-creepy]')].forEach(el => {
const elements = document.querySelectorAll('img[data-creepy],img[data-creepyface]');
for (let i = 0; i < elements.length; i++) {
const el = elements[i];
if (el instanceof HTMLImageElement)
creepyface(el);
});
}
});
export default creepyface;

@@ -1,1 +0,1 @@

!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(n=n||self).creepyface=e()}(this,function(){"use strict";function c(n,e,t,r,o,i,u){try{var a=n[i](u),c=a.value}catch(n){return void t(n)}a.done?e(c):Promise.resolve(c).then(r,o)}function f(a){return function(){var n=this,u=arguments;return new Promise(function(e,t){var r=a.apply(n,u);function o(n){c(r,e,t,o,i,"next",n)}function i(n){c(r,e,t,o,i,"throw",n)}o(void 0)})}}function o(n,e){for(var t=0;t<e.length;t++){var r=e[t];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(n,r.key,r)}}function h(n,e){return function(n){if(Array.isArray(n))return n}(n)||function(n,e){var t=[],r=!0,o=!1,i=void 0;try{for(var u,a=n[Symbol.iterator]();!(r=(u=a.next()).done)&&(t.push(u.value),!e||t.length!==e);r=!0);}catch(n){o=!0,i=n}finally{try{r||null==a.return||a.return()}finally{if(o)throw i}}return t}(n,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function n(n){return function(n){if(Array.isArray(n)){for(var e=0,t=new Array(n.length);e<n.length;e++)t[e]=n[e];return t}}(n)||function(n){if(Symbol.iterator in Object(n)||"[object Arguments]"===Object.prototype.toString.call(n))return Array.from(n)}(n)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var l=function e(r){if(!r)return Promise.reject();if("string"==typeof r){var n=r;(r=new Image).src=n}else{if(void 0!==r.length){var t=[].map.call(r,function(n){return e(n).catch(function(n){return n})});return Promise.all(t).then(function(n){var e=n.filter(function(n){return n.naturalWidth});return e.length===n.length?e:Promise.reject({loaded:e,errored:n.filter(function(n){return!n.naturalWidth})})})}if("IMG"!==r.tagName)return Promise.reject()}var o=new Promise(function(n,e){function t(){r.naturalWidth?n(r):e(r),r.removeEventListener("load",t),r.removeEventListener("error",t)}r.naturalWidth?n(r):r.complete?e(r):(r.addEventListener("load",t),r.addEventListener("error",t))});return o.image=r,o};var v=function(n,e){var t,r={};return void 0===(e=e||{}).separator&&(e.separator="-"),Array.prototype.slice.call(n.attributes).filter((t=e.pattern,function(n){var e;return e=/^data\-/.test(n.name),void 0===t?e:e&&t.test(n.name.slice(5))})).forEach(function(o){o.name.slice(5).split(e.separator).reduce(function(n,e,t,r){return"data"===e?n:(t===r.length-1?n[e]=o.value:n[e]=n[e]||{},n[e])},r)}),r};var p=function(){function e(n){!function(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),this.subscriber=n}var n,t,r;return n=e,(t=[{key:"subscribe",value:function(n){return{unsubscribe:this.subscriber({next:n})}}}])&&o(n.prototype,t),r&&o(n,r),e}(),t=[];document.addEventListener("mousemove",function(e){return t.forEach(function(n){return n.next([e.clientX,e.clientY])})},!0);var m=new p(function(n){return t.push(n),function(){t.splice(t.indexOf(n),1)}}),s=function(n,t){return n.map(function(n,e){return n+t[e]})},a=function(n){return n*Math.PI/180},d=function(n){return e=Math.atan2(n[1],n[0]),t=2*Math.PI,180*((t+e%t)%t)/Math.PI;var e,t},e=[];document.addEventListener("touchmove",function(c){return e.forEach(function(n){var e=[0,0],t=!0,r=!1,o=void 0;try{for(var i,u=c.touches[Symbol.iterator]();!(t=(i=u.next()).done);t=!0){var a=i.value;e=s(e,[a.clientX,a.clientY])}}catch(n){r=!0,o=n}finally{try{t||null==u.return||u.return()}finally{if(r)throw o}}n.next(e)})},!0);var b=new p(function(n){return e.push(n),function(){e.splice(e.indexOf(n),1)}}),y=function(){},g=function(n){for(var e=[],t=Object.keys(n),r=0;r<t.length;r++){var o=t[r],i=n[o];i&&e.push({angle:parseFloat(o),src:i})}return e};function w(n){var e,t,r,o,i,u,a,c,f,l,s=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},d=Object.assign({},(t=v(e=n),r=t.src,o=void 0===r?{}:r,i=t.fieldofvision,u=t.timetodefault,a=t.resetoncancel,c=t.throttle,f={src:e.getAttribute("src")||void 0},u&&(f.timeToDefault=parseFloat(u)),c&&(f.throttle=parseFloat(c)),i&&(f.fieldOfVision=parseFloat(i)),a&&(f.resetOnCancel="true"===a),o.hover&&(f.hover=o.hover),o.look&&(f.looks=g(o.look)),f),s);if(!d.src)throw new Error("A default URL must be specified");return{fieldOfVision:d.fieldOfVision||150,src:d.src,hover:d.hover||"",points:d.points||(l=[m,b],new p(function(n){var e=n.next.bind(n),t=l.map(function(n){return n.subscribe(e)});return function(){return t.forEach(function(n){return n.unsubscribe()})}})),looks:d.looks||[],timeToDefault:d.timeToDefault||1e3,resetOnCancel:!(!1===d.resetOnCancel),throttle:d.throttle||100,onDebug:d.onDebug||y,onAttach:d.onAttach||y,onDetach:d.onDetach||y}}var O=function(n){var e=n.getBoundingClientRect(),t=e.top+window.pageYOffset+e.height/2,r=e.left+window.pageXOffset+e.width/2;return{y:t,x:r}};var x=function(n,e){return d((o=s([window.scrollX,window.scrollY],e),u=O(n),i=[u.x,u.y],t=o.map(function(n,e){return n-i[e]}),r=90,[t[0]*Math.cos(a(r))-t[1]*Math.sin(a(r)),t[0]*Math.sin(a(r))+t[1]*Math.cos(a(r))]));var t,r,o,i,u},E=function(n){return 180<Math.abs(n)?n-360*((e=n)?e<0?-1:1:0):n;var e},M=function(n,e){return e.slice(0).sort((t=n,function(n,e){return Math.abs(E(n.angle-t))-Math.abs(E(e.angle-t))}))[0];var t},j=function(n,e,t){return e<=n&&n<=t},T=function(n,e){var t,r,o,i,u,a,c,f,l,s=h(e,2),d=s[0],v=s[1];return document.elementFromPoint?document.elementFromPoint(d,v)===n:(t=n.getBoundingClientRect(),r=[d,v],o=t.left,i=t.top,u=t.right,a=t.bottom,c=h(r,2),f=c[0],l=c[1],j(f,o,u)&&j(l,i,a))},r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},D="Expected a function",i=NaN,u="[object Symbol]",A=/^\s+|\s+$/g,L=/^[-+]0x[0-9a-f]+$/i,P=/^0b[01]+$/i,C=/^0o[0-7]+$/i,I=parseInt,k="object"==typeof r&&r&&r.Object===Object&&r,R="object"==typeof self&&self&&self.Object===Object&&self,F=k||R||Function("return this")(),S=Object.prototype.toString,W=Math.max,N=Math.min,V=function(){return F.Date.now()};function X(r,o,n){var i,u,a,c,f,l,s=0,d=!1,v=!1,e=!0;if("function"!=typeof r)throw new TypeError(D);function h(n){var e=i,t=u;return i=u=void 0,s=n,c=r.apply(t,e)}function p(n){var e=n-l;return void 0===l||o<=e||e<0||v&&a<=n-s}function m(){var n,e,t=V();if(p(t))return b(t);f=setTimeout(m,(e=o-((n=t)-l),v?N(e,a-(n-s)):e))}function b(n){return f=void 0,e&&i?h(n):(i=u=void 0,c)}function t(){var n,e=V(),t=p(e);if(i=arguments,u=this,l=e,t){if(void 0===f)return s=n=l,f=setTimeout(m,o),d?h(n):c;if(v)return f=setTimeout(m,o),h(l)}return void 0===f&&(f=setTimeout(m,o)),c}return o=$(o)||0,Y(n)&&(d=!!n.leading,a=(v="maxWait"in n)?W($(n.maxWait)||0,o):a,e="trailing"in n?!!n.trailing:e),t.cancel=function(){void 0!==f&&clearTimeout(f),i=l=u=f=void(s=0)},t.flush=function(){return void 0===f?c:b(V())},t}function Y(n){var e=typeof n;return!!n&&("object"==e||"function"==e)}function $(n){if("number"==typeof n)return n;if("symbol"==typeof(e=n)||(t=e)&&"object"==typeof t&&S.call(e)==u)return i;var e,t;if(Y(n)){var r="function"==typeof n.valueOf?n.valueOf():n;n=Y(r)?r+"":r}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(A,"");var o=P.test(n);return o||C.test(n)?I(n.slice(2),o?2:8):L.test(n)?i:+n}var B=function(n,e,t){var r=!0,o=!0;if("function"!=typeof n)throw new TypeError(D);return Y(t)&&(r="leading"in t?!!t.leading:r,o="trailing"in t?!!t.trailing:o),X(n,e,{leading:r,maxWait:e,trailing:o})},q=function(i,u){return new p(function(r){var o=function(e,t,r){var o,i,u,a,c;function f(){var n=Date.now()-a;n<t&&0<=n?o=setTimeout(f,t-n):(o=null,r||(c=e.apply(u,i),u=i=null))}null==t&&(t=100);var n=function(){u=this,i=arguments,a=Date.now();var n=r&&!o;return o||(o=setTimeout(f,t)),n&&(c=e.apply(u,i),u=i=null),c};return n.clear=function(){o&&(clearTimeout(o),o=null)},n.flush=function(){o&&(c=e.apply(u,i),u=i=null,clearTimeout(o),o=null)},n}(function(){return r.next({src:u.src,options:u})},u.timeToDefault),n=u.points.subscribe(B(function(n){var e=x(i,n),t=function(n,e,t,r){var o=r.looks,i=r.hover,u=r.fieldOfVision,a=r.src;if(i&&T(n,e))a=i;else{var c=M(t,o);Math.abs(E(c.angle-t))<u/2&&(a=c.src)}return a}(i,n,e,u);r.next({point:n,angle:e,src:t,options:u}),o()},u.throttle));return function(){o.clear(),n.unsubscribe()}})},G=function(e,n){var t,r,o,i=w(e,n),u=function(n){e.src=n},a=(t=e,l((r=i,o=r.looks.map(function(n){return n.src}),r.src&&o.push(r.src),r.hover&&o.push(r.hover),o)).then(function(n){return t.creepyfaceReachableImages=n,function(){delete t.creepyfaceReachableImages}})),c=a.then(function(){return i.onAttach(),q(e,i).subscribe(function(n){u(n.src),i.onDebug(n)})});return f(regeneratorRuntime.mark(function n(){var e,t;return regeneratorRuntime.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:return n.next=2,c;case 2:return e=n.sent,n.next=5,a;case 5:t=n.sent,e.unsubscribe(),t(),i.resetOnCancel&&u(i.src),i.onDetach();case 10:case"end":return n.stop()}},n,this)}))},H=function n(e,t){n.cancel(e);var r=y,o=e,i=function(t,e,r){var o=function(n){return n?e():r()};if(MutationObserver){var i=document.body&&document.body.contains(t);i&&o(!0);var n=new MutationObserver(function(n){var e=document.body&&document.body.contains(t);!e&&i?(o(!1),i=!1):e&&!i&&(o(!0),i=!0)});return n.observe(document,{childList:!0,subtree:!0}),function(){return n.disconnect()}}return document.body&&document.body.contains(t)&&o(!0),t.addEventListener("DOMNodeInserted",function(){return o(!0)},!1),t.addEventListener("DOMNodeRemoved",function(){return o(!1)},!1),y}(e,function(){r=G(o,t)},function(){return n.cancel(e)});return o.creepyfaceCancel=function(){i(),r(),delete o.creepyfaceCancel}};return H.cancel=function(n){var e=n;e.creepyfaceCancel&&e.creepyfaceCancel()},document.addEventListener("DOMContentLoaded",function(){n(document.querySelectorAll("img[data-creepy]")).forEach(function(n){n instanceof HTMLImageElement&&H(n)})}),H});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).creepyface=e()}(this,function(){"use strict";var l=function(o,i){var c=[];o.forEach(function(t){var e,n,r;e=t,n=function(t){c.push(t),c.length===o.length&&i(c)},(r=new Image).src=e,r.onload=r.onerror=function(){r.naturalWidth||console.error("Creepyface was unable to load ".concat(e)),delete r.onload,delete r.onerror,n(r)}})};var c=function(){},n=[];document.addEventListener("mousemove",function(e){return n.forEach(function(t){return t([e.clientX,e.clientY])})},!0);var u=function(t,e){return[t[0]+e[0],t[1]+e[1]]},a=function(t){return t*Math.PI/180},f=function(t){return e=Math.atan2(t[1],t[0]),n=2*Math.PI,180*((n+e%n)%n)/Math.PI;var e,n},e=[];document.addEventListener("touchmove",function(o){return e.forEach(function(t){for(var e=[0,0],n=0;n<o.touches.length;n++){var r=o.touches[n];e=u(e,[r.clientX,r.clientY])}t(e)})},!0);var r,o={pointer:(r=[function(t){return n.push(t),function(){n.splice(n.indexOf(t),1)}},function(t){return e.push(t),function(){e.splice(e.indexOf(t),1)}}],function(e){var t=r.map(function(t){return t(e)});return function(){return t.forEach(function(t){return t()})}})},i=function(t){var e=t?parseFloat(t):NaN;return isNaN(e)?void 0:e},s=function(t){return{hover:t.getAttribute("data-src-hover")||void 0,looks:function(t){for(var e=/data-src-look-(\d+)/i,n=[],r=0;r<t.attributes.length;r++){var o=t.attributes[r],i=e.exec(o.name);i&&n.push({angle:parseFloat(i[1]),src:o.value})}return n.length?n:void 0}(t),points:t.getAttribute("data-points")||void 0,timeToDefault:i(t.getAttribute("data-timetodefault")),throttle:i(t.getAttribute("data-throttle")),fieldOfVision:i(t.getAttribute("data-fieldofvision"))}},d=function(t){return"function"==typeof t.points?t.points:(e=t.points||"pointer",o[e]?o[e]:(console.error("No observable registered as '".concat(e,"', defaulting to pointer.")),o.pointer));var e};function v(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=function(o){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{},e=Object.keys(i);"function"==typeof Object.getOwnPropertySymbols&&(e=e.concat(Object.getOwnPropertySymbols(i).filter(function(t){return Object.getOwnPropertyDescriptor(i,t).enumerable}))),e.forEach(function(t){var e,n,r;e=o,r=i[n=t],n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r})}return o}({},s(t),e),r=t.getAttribute("src");if(!r)throw new Error("A default URL must be specified");return{fieldOfVision:n.fieldOfVision||150,src:r,hover:n.hover||"",points:d(n),looks:n.looks||[],timeToDefault:n.timeToDefault||1e3,throttle:n.throttle||100,onDebug:n.onDebug||c,onAttach:n.onAttach||c,onDetach:n.onDetach||c}}var h=function(t){var e=t.getBoundingClientRect(),n=e.top+window.pageYOffset+e.height/2,r=e.left+window.pageXOffset+e.width/2;return{y:n,x:r}};var m=function(t,e){return f((o=u([window.scrollX,window.scrollY],e),c=h(t),i=[c.x,c.y],n=[o[0]-i[0],o[1]-i[1]],r=90,[n[0]*Math.cos(a(r))-n[1]*Math.sin(a(r)),n[0]*Math.sin(a(r))+n[1]*Math.cos(a(r))]));var n,r,o,i,c},b=function(t){return 180<Math.abs(t)?t-360*((e=t)?e<0?-1:1:0):t;var e},g=function(t,e){return e.slice(0).sort((n=t,function(t,e){return Math.abs(b(t.angle-n))-Math.abs(b(e.angle-n))}))[0];var n},p=function(t,e,n){return e<=t&&t<=n},y=function(t,e){return document.elementFromPoint?document.elementFromPoint(e[0],e[1])===t:(n=t.getBoundingClientRect(),r=[e[0],e[1]],o=n.left,i=n.top,c=n.right,u=n.bottom,p(r[0],o,c)&&p(r[1],i,u));var n,r,o,i,c,u},O=function(h,p){return function(r){var t,e,n,o,i,c,u,a,f,l,s,d=(t=function(){return r({src:p.src,options:p})},e=p.timeToDefault,(o=function(){n&&clearTimeout(n),n=setTimeout(function(){n=null,t()},e)}).clear=function(){n&&(clearTimeout(n),n=null)},o),v=p.points((i=function(t){var e=m(h,t),n=function(t,e,n,r){var o=r.looks,i=r.hover,c=r.fieldOfVision,u=r.src;if(i&&y(t,e))u=i;else{var a=g(n,o);Math.abs(b(a.angle-n))<c/2&&(u=a.src)}return u}(h,t,e,p);r({point:t,angle:e,src:n,options:p}),d()},c=p.throttle,f=0,l=function(){f=Date.now(),u=null,i(a)},(s=function(t){var e=Date.now(),n=c-(e-f);a=t,n<=0||c<n?(u&&(clearTimeout(u),u=null),f=e,i(t)):u||(u=setTimeout(l,n))}).clear=function(){u&&clearTimeout(u),f=0,u=null},s));return function(){d.clear(),v()}}},w=function(n,t){var e,r,o,i,c=v(n,t),u=function(t){n.src=t},a=!1,f=function(){a=!0};return e=n,r=function(t){if(!a){c.onAttach();var e=O(n,c)(function(t){u(t.src),c.onDebug(t)});f=function(){e(),u(c.src),c.onDetach(),t()}}},l((i=(o=c).looks.map(function(t){return t.src}),o.src&&i.push(o.src),o.hover&&i.push(o.hover),i),function(t){e.creepyfaceReachableImages=t,r(function(){delete e.creepyfaceReachableImages})}),function(){return f()}},M=function t(e,n){t.cancel(e);var r=c,o=function(n,e,r){var o=function(t){return t?e():r()};if(MutationObserver){var i=document.body.contains(n);i&&o(!0);var t=new MutationObserver(function(t){var e=document.body.contains(n);!e&&i?(o(!1),i=!1):e&&!i&&(o(!0),i=!0)});return t.observe(document,{childList:!0,subtree:!0}),function(){return t.disconnect()}}return document.body.contains(n)&&o(!0),n.addEventListener("DOMNodeInserted",function(){return o(!0)},!1),n.addEventListener("DOMNodeRemoved",function(){return o(!1)},!1),c}(e,function(){r=w(e,n)},function(){return t.cancel(e)});return e.creepyfaceCancel=function(){o(),r(),delete e.creepyfaceCancel}};return M.cancel=function(t){var e=t.creepyfaceCancel;e&&e()},M.registerObservable=function(t,e){var n;n=e,o[t]=n},document.addEventListener("DOMContentLoaded",function(){for(var t=document.querySelectorAll("img[data-creepy],img[data-creepyface]"),e=0;e<t.length;e++){var n=t[e];n instanceof HTMLImageElement&&M(n)}}),M});

@@ -1,3 +0,4 @@

import Observable from './util/observable';
declare const _default: (observables: Observable<number[]>[]) => Observable<number[]>;
import { Observable, Observer } from '../util/types';
import { Point } from '../util/algebra';
declare const _default: (observables: Observable<Point>[]) => (observer: Observer<Point>) => () => void;
export default _default;

@@ -1,6 +0,4 @@

import Observable from './util/observable';
export default (observables) => new Observable(observer => {
const next = observer.next.bind(observer);
const subscriptions = observables.map(o => o.subscribe(next));
return () => subscriptions.forEach(s => s.unsubscribe());
});
export default (observables) => (observer) => {
const cancels = observables.map(o => o(observer));
return () => cancels.forEach(cancel => cancel());
};

@@ -1,5 +0,4 @@

import Observable from './util/observable';
import { Observable } from '../util/types';
import { Options, CreepyData } from '../util/options';
import { CreepyImage } from '../util/types';
declare const _default: (img: CreepyImage, options: Options) => Observable<CreepyData>;
declare const _default: (img: HTMLImageElement, options: Options) => Observable<CreepyData>;
export default _default;
import getAngle from './util/get-angle';
import getSrc from './util/get-src';
import debounce from 'debounce';
import Observable from './util/observable';
import throttle from 'lodash.throttle';
export default (img, options) => new Observable(observer => {
const backToDefault = debounce(() => observer.next({ src: options.src, options }), options.timeToDefault);
const subscription = options.points.subscribe(throttle(point => {
import debounce from './util/debounce';
import throttle from './util/throttle';
export default (img, options) => observer => {
const backToDefault = debounce(() => observer({ src: options.src, options }), options.timeToDefault);
const cancel = options.points(throttle(point => {
const angle = getAngle(img, point);
const src = getSrc(img, point, angle, options);
observer.next({ point, angle, src, options });
observer({ point, angle, src, options });
backToDefault();

@@ -16,4 +15,4 @@ }, options.throttle));

backToDefault.clear();
subscription.unsubscribe();
cancel();
};
});
};

@@ -1,3 +0,4 @@

import Observable from './util/observable';
declare const _default: Observable<number[]>;
import { Observer } from '../util/types';
import { Point } from '../util/algebra';
declare const _default: (observer: Observer<Point>) => () => void;
export default _default;

@@ -1,2 +0,1 @@

import Observable from './util/observable';
import { add } from '../util/algebra';

@@ -6,8 +5,9 @@ const observers = [];

let point = [0, 0];
for (const touch of event.touches) {
for (let i = 0; i < event.touches.length; i++) {
const touch = event.touches[i];
point = add(point, [touch.clientX, touch.clientY]);
}
observer.next(point);
observer(point);
}), true);
export default new Observable(observer => {
export default (observer) => {
observers.push(observer);

@@ -17,2 +17,2 @@ return () => {

};
});
};

@@ -1,3 +0,4 @@

import Observable from './util/observable';
declare const _default: Observable<number[]>;
import { Observer } from '../util/types';
import { Point } from '../util/algebra';
declare const _default: (observer: Observer<Point>) => () => void;
export default _default;

@@ -1,5 +0,4 @@

import Observable from './util/observable';
const observers = [];
document.addEventListener('mousemove', (event) => observers.forEach(observer => observer.next([event.clientX, event.clientY])), true);
export default new Observable(observer => {
document.addEventListener('mousemove', (event) => observers.forEach(observer => observer([event.clientX, event.clientY])), true);
export default (observer) => {
observers.push(observer);

@@ -9,2 +8,2 @@ return () => {

};
});
};

@@ -1,3 +0,3 @@

import { CreepyImage } from '../../util/types';
declare const _default: (img: CreepyImage, point: number[]) => number;
import { Point } from '../../util/algebra';
declare const _default: (img: HTMLImageElement, point: Point) => number;
export default _default;

@@ -0,4 +1,4 @@

import { Point } from '../../util/algebra';
import { Options } from '../../util/options';
import { CreepyImage } from '../../util/types';
declare const _default: (img: CreepyImage, point: number[], angle: number, options: Options) => string;
declare const _default: (img: HTMLImageElement, point: Point, angle: number, options: Options) => string;
export default _default;

@@ -6,9 +6,9 @@ import { sign } from '../../util/algebra';

const within = (n, a, b) => n >= a && n <= b;
const rectContains = ({ left, top, right, bottom }, [x, y]) => within(x, left, right) && within(y, top, bottom);
const elementContains = (img, [x, y]) => {
const rectContains = ({ left, top, right, bottom }, point) => within(point[0], left, right) && within(point[1], top, bottom);
const elementContains = (img, point) => {
if (document.elementFromPoint) {
return document.elementFromPoint(x, y) === img;
return document.elementFromPoint(point[0], point[1]) === img;
}
else {
return rectContains(img.getBoundingClientRect(), [x, y]);
return rectContains(img.getBoundingClientRect(), [point[0], point[1]]);
}

@@ -15,0 +15,0 @@ };

@@ -1,7 +0,7 @@

export declare type Vector = Array<number>;
export declare type Point = [number, number];
export declare type Degrees = number;
export declare type Radians = number;
export declare type Angle = Degrees;
export declare const diff: (v1: number[], v2: number[]) => number[];
export declare const add: (v1: number[], v2: number[]) => number[];
export declare const diff: (v1: Point, v2: Point) => Point;
export declare const add: (v1: Point, v2: Point) => Point;
export declare const sign: (n: number) => 1 | 0 | -1;

@@ -11,3 +11,3 @@ export declare const rad: (deg: number) => number;

export declare const mod: (n: number, m: number) => number;
export declare const getAngle: (v: number[]) => number;
export declare const rotate: (v: number[], deg: number) => number[];
export declare const getAngle: (v: Point) => number;
export declare const rotate: (v: Point, deg: number) => Point;

@@ -1,3 +0,9 @@

export const diff = (v1, v2) => v1.map((x, i) => x - v2[i]);
export const add = (v1, v2) => v1.map((x, i) => x + v2[i]);
export const diff = (v1, v2) => [
v1[0] - v2[0],
v1[1] - v2[1]
];
export const add = (v1, v2) => [
v1[0] + v2[0],
v1[1] + v2[1]
];
export const sign = (n) => (n ? (n < 0 ? -1 : 1) : 0);

@@ -4,0 +10,0 @@ export const rad = (deg) => (deg * Math.PI) / 180;

import { UserOptions } from './options';
import { Cancel, CreepyImage } from './types';
declare const _default: (img: CreepyImage, userOptions?: UserOptions | undefined) => Cancel;
import { Cancel } from './types';
declare const _default: (img: HTMLImageElement, userOptions?: UserOptions | undefined) => Cancel;
export default _default;

@@ -9,19 +9,22 @@ import preload from './preload';

};
const preloaded = preload(img, options);
const subscribed = preloaded.then(() => {
let cancelled = false;
let cancel = () => {
cancelled = true;
};
preload(img, options, unload => {
if (cancelled)
return;
options.onAttach();
return creepy(img, options).subscribe(data => {
const stopCreepyface = creepy(img, options)(data => {
setSrc(data.src);
options.onDebug(data);
});
cancel = () => {
stopCreepyface();
setSrc(options.src);
options.onDetach();
unload();
};
});
return async () => {
const subscription = await subscribed;
const unload = await preloaded;
subscription.unsubscribe();
unload();
if (options.resetOnCancel)
setSrc(options.src);
options.onDetach();
};
return () => cancel();
};

@@ -1,4 +0,3 @@

import Observable from '../observables/util/observable';
import { Angle, Vector } from './algebra';
import { CreepyImage } from './types';
import { Observable } from './types';
import { Angle, Point } from './algebra';
export declare type Millis = number;

@@ -12,3 +11,3 @@ export declare type Time = Millis;

export declare type CreepyData = {
point?: Vector;
point?: Point;
angle?: Angle;

@@ -25,5 +24,4 @@ src: string;

looks: Array<Look>;
points: Observable<Vector>;
points: Observable<Point>;
timeToDefault: Time;
resetOnCancel: boolean;
throttle: Time;

@@ -36,8 +34,6 @@ onDebug: Debug;

fieldOfVision?: Angle;
src?: ImageURL;
hover?: ImageURL;
looks?: Array<Look>;
points?: Observable<Vector>;
points?: Observable<Point> | string;
timeToDefault?: Time;
resetOnCancel?: boolean;
throttle?: Time;

@@ -48,2 +44,2 @@ onDebug?: Debug;

};
export default function getOptions(img: CreepyImage, options?: UserOptions): Options;
export default function getOptions(img: HTMLImageElement, options?: UserOptions): Options;

@@ -1,47 +0,45 @@

import parseDataAttributes from 'data-attrs-to-js';
import mousePoints from '../observables/mouse';
import fingerPoints from '../observables/finger';
import combined from '../observables/combined';
import noop from './noop';
const getLooks = (look) => {
import * as observableStore from '../observables/util/store';
const getLooks = (img) => {
const regex = /data-src-look-(\d+)/i;
const looks = [];
for (const key of Object.keys(look)) {
const src = look[key];
if (src) {
looks.push({ angle: parseFloat(key), src });
for (let i = 0; i < img.attributes.length; i++) {
const attr = img.attributes[i];
const match = regex.exec(attr.name);
if (match) {
looks.push({ angle: parseFloat(match[1]), src: attr.value });
}
}
return looks;
return looks.length ? looks : undefined;
};
function fromImage(element) {
const { src = {}, fieldofvision, timetodefault, resetoncancel, throttle } = parseDataAttributes(element);
const options = {
src: element.getAttribute('src') || undefined
};
if (timetodefault)
options.timeToDefault = parseFloat(timetodefault);
if (throttle)
options.throttle = parseFloat(throttle);
if (fieldofvision)
options.fieldOfVision = parseFloat(fieldofvision);
if (resetoncancel)
options.resetOnCancel = resetoncancel === 'true';
if (src.hover)
options.hover = src.hover;
if (src.look)
options.looks = getLooks(src.look);
return options;
}
const getFloat = (s) => {
const float = s ? parseFloat(s) : NaN;
return isNaN(float) ? undefined : float;
};
const fromImage = (img) => ({
hover: img.getAttribute('data-src-hover') || undefined,
looks: getLooks(img),
points: img.getAttribute('data-points') || undefined,
timeToDefault: getFloat(img.getAttribute('data-timetodefault')),
throttle: getFloat(img.getAttribute('data-throttle')),
fieldOfVision: getFloat(img.getAttribute('data-fieldofvision'))
});
const getPoints = (userOptions) => {
if (typeof userOptions.points === 'function') {
return userOptions.points;
}
return observableStore.retrieve(userOptions.points || 'pointer');
};
export default function getOptions(img, options = {}) {
const userOptions = Object.assign({}, fromImage(img), options);
if (!userOptions.src)
const userOptions = { ...fromImage(img), ...options };
const src = img.getAttribute('src');
if (!src)
throw new Error('A default URL must be specified');
return {
fieldOfVision: userOptions.fieldOfVision || 150,
src: userOptions.src,
src,
hover: userOptions.hover || '',
points: userOptions.points || combined([mousePoints, fingerPoints]),
points: getPoints(userOptions),
looks: userOptions.looks || [],
timeToDefault: userOptions.timeToDefault || 1000,
resetOnCancel: !(userOptions.resetOnCancel === false),
throttle: userOptions.throttle || 100,

@@ -48,0 +46,0 @@ onDebug: userOptions.onDebug || noop,

import { Options } from './options';
import { CreepyImage, Cancel } from './types';
export default function preload(img: CreepyImage, options: Options): Promise<Cancel>;
export default function preload(img: CreepyImage, options: Options, callback: (cancel: Cancel) => void): void;

@@ -1,2 +0,1 @@

import loadImages from 'image-promise';
const getSrcs = (options) => {

@@ -10,9 +9,31 @@ const srcs = options.looks.map(({ src }) => src);

};
export default function preload(img, options) {
return loadImages(getSrcs(options)).then(imgs => {
const loadImage = (src, callback) => {
const img = new Image();
img.src = src;
img.onload = img.onerror = () => {
if (!img.naturalWidth) {
console.error(`Creepyface was unable to load ${src}`);
}
delete img.onload;
delete img.onerror;
callback(img);
};
};
const loadImages = (srcs, callback) => {
const imgs = [];
srcs.forEach(src => {
loadImage(src, img => {
imgs.push(img);
if (imgs.length === srcs.length)
callback(imgs);
});
});
};
export default function preload(img, options, callback) {
loadImages(getSrcs(options), imgs => {
img.creepyfaceReachableImages = imgs;
return () => {
callback(() => {
delete img.creepyfaceReachableImages;
};
});
});
}
export declare type Cancel = () => void;
export declare type Observer<T> = (t: T) => void;
export declare type Observable<T> = (observer: Observer<T>) => Cancel;
export declare type CreepyImage = HTMLImageElement & {

@@ -3,0 +5,0 @@ creepyfaceCancel?: Cancel;

@@ -5,7 +5,7 @@ import noop from './noop';

if (MutationObserver) {
let wasInDOM = document.body && document.body.contains(node);
let wasInDOM = document.body.contains(node);
if (wasInDOM)
isReady(true);
const observer = new MutationObserver(mutations => {
const isInDOM = document.body && document.body.contains(node);
const isInDOM = document.body.contains(node);
if (!isInDOM && wasInDOM) {

@@ -24,3 +24,3 @@ isReady(false);

else {
if (document.body && document.body.contains(node))
if (document.body.contains(node))
isReady(true);

@@ -27,0 +27,0 @@ node.addEventListener('DOMNodeInserted', () => isReady(true), false);

{
"name": "creepyface",
"version": "5.0.0",
"version": "6.0.0",
"keywords": [

@@ -23,20 +23,14 @@ "face",

"main": "dist/creepyface.umd.js",
"module": "dist/creepyface.js",
"browser": "dist/creepyface.umd.js",
"types": "dist/creepyface.d.ts",
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-proposal-class-properties": "^7.2.3",
"@babel/preset-env": "^7.2.3",
"@types/debounce": "^1.2.0",
"@types/jest": "^23.3.11",
"@types/lodash.throttle": "^4.1.4",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^23.6.0",
"chromedriver": "^2.45.0",
"babel-jest": "^24.9.0",
"coveralls": "^3.0.2",
"eslint": "^5.11.1",
"geckodriver": "^1.14.1",
"geckodriver": "^1.19.1",
"husky": "^1.3.1",
"jest": "^23.6.0",
"jest": "^24.9.0",
"lint-staged": "^8.1.0",

@@ -46,5 +40,6 @@ "lolex": "^3.0.0",

"prettier": "^1.15.3",
"rimraf": "^2.6.3",
"rollup": "^1.0.0",
"rollup-plugin-babel": "^4.2.0",
"rollup-plugin-browsersync": "^1.0.0",
"rollup-plugin-browsersync": "^1.1.0",
"rollup-plugin-commonjs": "^9.2.0",

@@ -54,17 +49,12 @@ "rollup-plugin-node-resolve": "^4.0.0",

"selenium-webdriver": "^4.0.0-alpha.1",
"semantic-release": "^15.13.2",
"simulate-event": "^1.4.0",
"standard": "^12.0.1",
"ts-jest": "^23.10.5",
"ts-jest": "^24.2.0",
"tslint": "^5.12.0",
"tslint-config-prettier": "^1.17.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.2.2"
"typescript": "^3.7.3"
},
"dependencies": {
"data-attrs-to-js": "^1.1.1",
"debounce": "^1.0.2",
"get-element-center": "^1.1.0",
"image-promise": "^5.0.1",
"lodash.throttle": "^4.1.1"
"get-element-center": "^1.1.0"
},

@@ -78,6 +68,6 @@ "lint-staged": {

"scripts": {
"all": "run-s lint build test",
"travis": "run-s lint build test:coverage",
"all": "run-s clean lint build test",
"travis": "run-s clean lint build test:coverage",
"prepublishOnly": "npm run all",
"start": "run-p \"build:* -- -w\"",
"start": "npm run build:ts && run-p \"build:* -- -w\"",
"lint": "tslint --project tsconfig.json",

@@ -87,2 +77,3 @@ "build:ts": "tsc",

"build": "NODE_ENV=production run-s build:*",
"clean": "rimraf dist",
"test": "jest",

@@ -89,0 +80,0 @@ "test:coverage": "jest --coverage && cat ./coverage/lcov.info | coveralls"

# [Creepyface](https://creepyface.io) &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/4lejandrito/creepyface/blob/master/LICENSE) [![npm version](https://img.shields.io/npm/v/creepyface.svg?style=flat)](https://www.npmjs.com/package/creepyface) [![Build Status](https://api.travis-ci.org/4lejandrito/creepyface.svg?branch=master)](https://travis-ci.org/4lejandrito/creepyface) [![Coverage Status](https://coveralls.io/repos/github/4lejandrito/creepyface/badge.svg?branch=master)](https://coveralls.io/github/4lejandrito/creepyface?branch=master)
Creepyface is a little JavaScript tool (<4K minified & gzipped) that makes your face look at the mouse (or fingers). It is ideal for resumes, team presentation sites, etc...
Creepyface is a little JavaScript tool that makes your face look at the pointer (or a [firefly](https://github.com/4lejandrito/creepyface-firefly)). It is ideal for resumes, team presentation sites, etc...

@@ -23,3 +23,3 @@ [Demo](https://creepyface.io)

<img
data-creepy
data-creepyface
src="img/face/serious.jpg"

@@ -43,8 +43,8 @@ data-src-hover="img/face/crazy.jpg"

```html
<script type="text/javascript" src="creepyface.umd.js"></script>
<script src="https://creepyface.io/creepyface.js"></script>
```
Creepyface will automatically detect your image (thanks to the `data-creepy` attribute) and make it look at the mouse or fingers depending on which device you are using.
Creepyface will automatically detect your image (thanks to the `data-creepyface` attribute) and make it look at the mouse or fingers depending on which device you are using.
You can add as many Creepyfaces as you want as long as they all have the `data-creepy` attribute.
You can add as many Creepyfaces as you want as long as they all have the `data-creepyface` attribute.

@@ -90,2 +90,81 @@ If you want to stop Creepyface on a given image:

## Super advanced usage
Creepyface will look at the pointer by default, however custom point sources can be defined (see [firefly](https://github.com/4lejandrito/creepyface-firefly) for a real world implementation).
For example, to make your face look at a random point every half a second you need to register an observable:
```js
import creepyface from 'creepyface'
creepyface.registerObservable('random', observer => {
const interval = setInterval(
() =>
observer([
Math.random() * window.innerWidth,
Math.random() * window.innerHeight
]),
500
)
return () => {
clearInterval(interval)
}
})
```
and consume it from the data-attribute API using the `data-points` attribute:
```html
<img
data-creepyface
data-points="random"
src="img/face/serious.jpg"
data-src-hover="img/face/crazy.jpg"
data-src-look-0="img/face/north.jpg"
data-src-look-45="img/face/north-east.jpg"
data-src-look-90="img/face/east.jpg"
data-src-look-135="img/face/south-east.jpg"
data-src-look-180="img/face/south.jpg"
data-src-look-225="img/face/south-west.jpg"
data-src-look-270="img/face/west.jpg"
data-src-look-315="img/face/north-west.jpg"
/>
```
or pass it programmatically:
```js
const img = document.querySelector('img#face')
creepyface(img, {
// An observable that provides the points to look at
points: observer => {
const interval = setInterval(
() =>
observer([
Math.random() * window.innerWidth,
Math.random() * window.innerHeight
]),
500
)
return () => {
clearInterval(interval)
}
},
// Image URL to display on hover
hover: 'img/face/crazy.jpg',
// Each of the images looking at a given direction
looks: [
{ angle: 0, src: 'img/face/north.jpg' },
{ angle: 45, src: 'img/face/north-east.jpg' },
{ angle: 90, src: 'img/face/east.jpg' },
{ angle: 135, src: 'img/face/south-east.jpg' },
{ angle: 180, src: 'img/face/south.jpg' },
{ angle: 225, src: 'img/face/south-west.jpg' },
{ angle: 270, src: 'img/face/west.jpg' },
{ angle: 315, src: 'img/face/north-west.jpg' }
]
})
```
## Developing

@@ -104,1 +183,7 @@

MIT, see [LICENSE](https://github.com/4lejandrito/creepyface/blob/master/LICENSE) for details.
## Big Thanks
Cross-browser Testing Platform and Open Source ❤️ provided by [Sauce Labs][homepage].
[homepage]: https://saucelabs.com