diff --git a/README.md b/README.md index 57255f8..b8b942c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A dependency free script that let elements follow your cursor without a huge ove ## Usage 1. Include the `follow.min.js` script to your project 2. Add the `data-follow` attribute to the `position: absolute` elements which you want to follow the cursor -3. Set the factor on how big they should follow like so `data-follow="100"` (higher equals more movement, if you +3. Set the factor on how big they should follow like so `data-follow="100"` (higher equals less movement, if you leave it empty, it is set to 10. ## Include Script @@ -13,7 +13,7 @@ leave it empty, it is set to 10. 2. `` ### unpkg -1. `` +1. `` ## Options ### Dynamically add new elements @@ -35,4 +35,4 @@ In the current state, the script wont work properly with a transition on the ele Have a look in the `examples` folder to see some magic. ## Contribute -Feel free to open a Pullrequest or create a Issue on this project. \ No newline at end of file +Feel free to open a Pull request or create a Issue on this project. \ No newline at end of file diff --git a/dist/follow.min.js b/dist/follow.min.js index 384cafe..3321af9 100644 --- a/dist/follow.min.js +++ b/dist/follow.min.js @@ -1 +1 @@ -!function(t){var o={};function e(l){if(o[l])return o[l].exports;var r=o[l]={i:l,l:!1,exports:{}};return t[l].call(r.exports,r,r.exports,e),r.l=!0,r.exports}e.m=t,e.c=o,e.d=function(t,o,l){e.o(t,o)||Object.defineProperty(t,o,{enumerable:!0,get:l})},e.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},e.t=function(t,o){if(1&o&&(t=e(t)),8&o)return t;if(4&o&&"object"==typeof t&&t&&t.__esModule)return t;var l=Object.create(null);if(e.r(l),Object.defineProperty(l,"default",{enumerable:!0,value:t}),2&o&&"string"!=typeof t)for(var r in t)e.d(l,r,function(o){return t[o]}.bind(null,r));return l},e.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(o,"a",o),o},e.o=function(t,o){return Object.prototype.hasOwnProperty.call(t,o)},e.p="",e(e.s=0)}([function(t,o){window.follow={debug:!1,elements:[],attribute:"data-follow",defaultFactor:10,init:void 0,animate:void 0,log:void 0},follow.init=()=>{let t=document.querySelectorAll(`[${follow.attribute}]`);follow.log("targets",t);for(let o of t){let t={factor:o.getAttribute(follow.attribute)?o.getAttribute(follow.attribute):follow.defaultFactor,target:o,x:0,y:0,startPosition:{x:0,y:0}};t.startPosition.x=t.target.offsetLeft,t.startPosition.y=t.target.offsetTop,follow.elements.push(t)}follow.log("elements",follow.elements)},follow.animate=t=>{let o=t.clientX,e=t.clientY;follow.log("mouseX",o),follow.log("mouseY",e);for(let t of follow.elements){follow.log("element",t),t.x=t.target.offsetLeft,t.y=t.target.offsetTop;let l=(o-t.x)/t.factor,r=(e-t.y)/t.factor;follow.log("future position x",l),follow.log("future position y",r),t.target.style.left=t.startPosition.x+l+"px",t.target.style.top=t.startPosition.y+r+"px"}},follow.log=(t,o)=>{follow.debug&&(o?console.log(t,o):console.log(t))},follow.init(),document.addEventListener("mousemove",follow.animate)}]); \ No newline at end of file +!function(t){var e={};function o(i){if(e[i])return e[i].exports;var n=e[i]={i:i,l:!1,exports:{}};return t[i].call(n.exports,n,n.exports,o),n.l=!0,n.exports}o.m=t,o.c=e,o.d=function(t,e,i){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__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 i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)o.d(i,n,function(e){return t[e]}.bind(null,n));return i},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=0)}([function(t,e,o){"use strict";function i(t,e,o="red",i=3e3){if(follow.debug.dot){let n=document.createElement("i");n.style.position="absolute",n.style.height="1px",n.style.width="1px",n.style.backgroundColor=o,n.style.zIndex="100",n.style.left=t+"px",n.style.top=e+"px",document.body.append(n),setTimeout(()=>{n.remove()},i)}}function n(t,e){follow.debug.log&&(e?console.log(t,e):console.log(t))}o.r(e),window.follow={debug:{log:!1,dot:!1},elements:[],attribute:"data-follow",defaultFactor:10,init:void 0,animate:void 0},follow.init=()=>{let t=document.querySelectorAll(`[${follow.attribute}]`);n("targets",t);for(let e of t){let t={factor:e.getAttribute(follow.attribute)?e.getAttribute(follow.attribute):follow.defaultFactor,target:e,x:0,y:0,dimensions:{height:0,width:0},initialPosition:{x:0,y:0}};t.dimensions.height=t.target.offsetHeight,t.dimensions.width=t.target.offsetWidth,t.initialPosition.x=t.target.offsetLeft+t.dimensions.width/2,t.initialPosition.y=t.target.offsetTop+t.dimensions.height/2,i(t.initialPosition.x,t.initialPosition.y,"red",1e4),follow.elements.push(t)}n("elements",follow.elements)},follow.animate=t=>{let e=t.clientX,o=t.clientY;-1!==navigator.userAgent.search("Firefox")&&(e+=9,o+=15),i&&i(e,o,"blue"),n("mouseX",e),n("mouseY",o);for(let t of follow.elements){n("element",t);let l=(e-t.initialPosition.x)/t.factor,r=(o-t.initialPosition.y)/t.factor,s=t.initialPosition.x+l-t.dimensions.width/2,f=t.initialPosition.y+r-t.dimensions.height/2;t.target.style.left=s+"px",t.target.style.top=f+"px",i&&i(s,f,"green"),n("future position x",s),n("future position y",f)}},follow.init(),document.addEventListener("mousemove",follow.animate)}]); \ No newline at end of file diff --git a/examples/basic.html b/examples/basic.html index 7ec84ab..3d5aa92 100644 --- a/examples/basic.html +++ b/examples/basic.html @@ -1,35 +1,35 @@ - - Basic Example - index.js + + Basic Example - follow.js - + div:nth-child(3) { + top: 30%; + left: 100px; + background: yellow; + } +
diff --git a/examples/exact.html b/examples/exact.html new file mode 100644 index 0000000..d62256b --- /dev/null +++ b/examples/exact.html @@ -0,0 +1,40 @@ + + + + + Exact Example - follow.js + + + + +
+
+ + + + \ No newline at end of file diff --git a/src/helper.js b/src/helper.js new file mode 100644 index 0000000..a489f2f --- /dev/null +++ b/src/helper.js @@ -0,0 +1,30 @@ +// adds a dot to the given position if enabled +export function dot (x, y, color = 'red', timeout = 3000) { + if (follow.debug.dot) { + let dot = document.createElement('i') + dot.style.position = 'absolute' + dot.style.height = '1px' + dot.style.width = '1px' + dot.style.backgroundColor = color + dot.style.zIndex = '100' + dot.style.left = x + 'px' + dot.style.top = y + 'px' + document.body.append(dot) + + // because of performance issues remove the dot after the timeout + setTimeout(() => { + dot.remove() + }, timeout) + } +} + +// log if enabled +export function log (string, object = undefined) { + if (follow.debug.log) { + if (object) { + console.log(string, object) + } else { + console.log(string) + } + } +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index 913ab9c..648e495 100644 --- a/src/index.js +++ b/src/index.js @@ -1,87 +1,104 @@ +import * as helper from './helper' + window.follow = { - debug: false, - elements: [], - attribute: 'data-follow', - defaultFactor: 10, - init: undefined, - animate: undefined, - log: undefined + debug: { + log: false, + dot: false + }, + elements: [], + attribute: 'data-follow', + defaultFactor: 10, + init: undefined, + animate: undefined } follow.init = () => { - // get all targets with attribute - let targets = document.querySelectorAll(`[${follow.attribute}]`) - - // debug - follow.log('targets', targets) - - for (let target of targets) { - // set the specified or the default factor - let factor = target.getAttribute(follow.attribute) ? target.getAttribute(follow.attribute) : follow.defaultFactor - - // create element object - let element = { - factor: factor, - target: target, - x: 0, - y: 0, - startPosition: { - x: 0, - y: 0 - } - } - - // define start position of element to calculate correctly - element.startPosition.x = element.target.offsetLeft - element.startPosition.y = element.target.offsetTop + // get all targets with attribute + let targets = document.querySelectorAll(`[${follow.attribute}]`) - // push element to array - follow.elements.push(element) - } + // debug + helper.log('targets', targets) + + for (let target of targets) { + // set the specified or the default factor + let factor = target.getAttribute(follow.attribute) ? target.getAttribute(follow.attribute) : follow.defaultFactor + + // create element object + let element = { + factor: factor, + target: target, + x: 0, + y: 0, + dimensions: { + height: 0, + width: 0 + }, + initialPosition: { + x: 0, + y: 0 + }, + } + + // define dimensions of the element + element.dimensions.height = element.target.offsetHeight + element.dimensions.width = element.target.offsetWidth + + // define the center of the element as initial position + element.initialPosition.x = element.target.offsetLeft + (element.dimensions.width / 2) + element.initialPosition.y = element.target.offsetTop + (element.dimensions.height / 2) + + // if center helper is wanted + helper.dot(element.initialPosition.x, element.initialPosition.y, 'red', 10000) + + // push element to array + follow.elements.push(element) + } - // debug - follow.log('elements', follow.elements) + // debug + helper.log('elements', follow.elements) } follow.animate = (event) => { - // define mouse position - let mouseX = event.clientX - let mouseY = event.clientY + // define mouse position + let mouseX = event.clientX + let mouseY = event.clientY + + // firefox fallback because mouse is offset by y 15 and x 9 pixel + if (navigator.userAgent.search("Firefox") !== -1) { + mouseX += 9 + mouseY += 15 + } - // debug - follow.log('mouseX', mouseX) - follow.log('mouseY', mouseY) + // add dot for mouse + helper.dot && helper.dot(mouseX, mouseY, 'blue') - for (let element of follow.elements) { // debug - follow.log('element', element) + helper.log('mouseX', mouseX) + helper.log('mouseY', mouseY) - // get current position of element - element.x = element.target.offsetLeft - element.y = element.target.offsetTop + for (let element of follow.elements) { + // debug + helper.log('element', element) - // calculate future position - let positionX = (mouseX - element.x) / element.factor - let positionY = (mouseY - element.y) / element.factor + // calculate additional pixels + let additionalX = (mouseX - element.initialPosition.x) / element.factor + let additionalY = (mouseY - element.initialPosition.y) / element.factor - // debug - follow.log('future position x', positionX) - follow.log('future position y', positionY) + // calculate future position + let futureX = (element.initialPosition.x + additionalX) - (element.dimensions.width / 2) + let futureY = (element.initialPosition.y + additionalY) - (element.dimensions.height / 2) - // set future position - element.target.style.left = element.startPosition.x + positionX + 'px' - element.target.style.top = element.startPosition.y + positionY + 'px' - } -} + // set future position + element.target.style.left = futureX + 'px' + element.target.style.top = futureY + 'px' + + // add helper dot if wanted + helper.dot && helper.dot(futureX, futureY, 'green') -follow.log = (string, object = undefined) => { - if (follow.debug) { - if (object) { - console.log(string, object) - } else { - console.log(string) + // debug + helper.log('future position x', futureX) + helper.log('future position y', futureY) } - } } follow.init() diff --git a/webpack.config.js b/webpack.config.js index f409924..df45aeb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,4 +7,5 @@ module.exports = { filename: 'follow.min.js' }, mode: 'production', + watch: true } \ No newline at end of file