├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .eslintignore ├── .browserslistrc ├── src ├── utils │ ├── getCoordinates.js │ ├── isTouch.js │ ├── clamp.js │ ├── getCenter.js │ ├── orientationElement.js │ ├── inViewport.js │ ├── scrollMovement.js │ ├── mouseMovement.js │ ├── elementMovement.js │ ├── cyclicMovement.js │ └── throttle.js ├── mixins │ ├── perspective_mixin.js │ ├── base_mixin.js │ ├── motion_mixin.js │ ├── container_events.js │ ├── transform_mixin.js │ └── audio_mixin.js ├── components │ ├── index.js │ ├── kinesis-audio.vue │ ├── kinesis-scroll.vue │ ├── kinesis-element.vue │ ├── kinesis-distance.vue │ └── kinesis-container.vue └── entry.js ├── .editorconfig ├── babel.config.js ├── .gitignore ├── .jsconfig.json ├── LICENSE ├── .eslintrc.js ├── package.json ├── README.md └── dist ├── vue-kinesis.min.js ├── vue-kinesis.esm.js └── vue-kinesis.ssr.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [aminerman] 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | 3 | democomponents/* 4 | 5 | App.vue -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | current node 2 | last 2 versions and > 2% 3 | ie > 10 4 | -------------------------------------------------------------------------------- /src/utils/getCoordinates.js: -------------------------------------------------------------------------------- 1 | export default function (x, y) { 2 | return { x, y, } 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/isTouch.js: -------------------------------------------------------------------------------- 1 | export default function isTouch() { 2 | try { 3 | return /Mobi|Android/i.test(navigator.userAgent); 4 | } catch (e) { 5 | return true; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/clamp.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-nested-ternary */ 2 | export default function (value, min, max) { 3 | return max && value > max ? max : min && value < min ? min : value; 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | max_line_length = 100 8 | quote_type = single -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const devPresets = ['@vue/babel-preset-app']; 2 | const buildPresets = ['@babel/preset-env']; 3 | module.exports = { 4 | presets: (process.env.NODE_ENV === 'development' ? devPresets : buildPresets), 5 | }; 6 | -------------------------------------------------------------------------------- /src/utils/getCenter.js: -------------------------------------------------------------------------------- 1 | import getCoordinates from './getCoordinates'; 2 | 3 | export default function (element) { 4 | return getCoordinates( 5 | element ? element.width / 2 : 0, 6 | element ? element.height / 2 : 0, 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /src/mixins/perspective_mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | perspective: { 4 | type: Number, 5 | default: 1000, 6 | }, 7 | }, 8 | computed: { 9 | style() { 10 | return { perspective: `${this.perspective}px` }; 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/utils/orientationElement.js: -------------------------------------------------------------------------------- 1 | import getCoordinates from './getCoordinates'; 2 | 3 | export default function (action) { 4 | const { event, target } = action; 5 | const x = event.gamma / 45; 6 | const y = event.beta / 90; 7 | 8 | return { 9 | ...getCoordinates(x, y), 10 | target, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Log files 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.sw? 21 | 22 | publish.txt 23 | 24 | # JEST unit test 25 | coverage 26 | -------------------------------------------------------------------------------- /src/utils/inViewport.js: -------------------------------------------------------------------------------- 1 | export default function inViewport(element) { 2 | const isInViewport = element.bottom >= 0 3 | && element.right >= 0 4 | && element.top 5 | <= (window.innerHeight || document.documentElement.clientHeight) 6 | && element.left <= (window.innerWidth || document.documentElement.clientWidth); 7 | 8 | return isInViewport; 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/scrollMovement.js: -------------------------------------------------------------------------------- 1 | import getCoordinates from './getCoordinates' 2 | 3 | export default function (shape) { 4 | const { target, } = shape 5 | const x = (target.left - window.innerWidth) / (target.width + window.innerWidth) 6 | const y = (target.top - window.innerHeight) / (target.height + window.innerHeight) 7 | return { ...getCoordinates(x, y), target, } 8 | } 9 | -------------------------------------------------------------------------------- /.jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "./src/**/*.js", 4 | "./src/**/*.vue" 5 | ], 6 | "compilerOptions": { 7 | "baseUrl": "./", 8 | "paths": { 9 | "@/*": [ 10 | "src/*" 11 | ], 12 | "@dev/*": [ 13 | "dev/*" 14 | ] 15 | } 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | "dist" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/mixins/base_mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | active: { 4 | type: Boolean, 5 | default: true, 6 | }, 7 | duration: { 8 | type: Number, 9 | default: 1000, 10 | }, 11 | easing: { 12 | type: String, 13 | default: 'cubic-bezier(0.23, 1, 0.32, 1)', 14 | }, 15 | tag: { 16 | type: String, 17 | default: 'div', 18 | }, 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /src/utils/mouseMovement.js: -------------------------------------------------------------------------------- 1 | import getCoordinates from './getCoordinates'; 2 | import getCenter from './getCenter'; 3 | 4 | export default function (action) { 5 | const { target, event } = action; 6 | const x = event.clientX; 7 | const y = event.clientY; 8 | 9 | const relativeX = x - target.left; 10 | const relativeY = y - target.top; 11 | 12 | const center = getCenter(target); 13 | 14 | const mouseMovementX = relativeX / center.x; 15 | const mouseMovementY = relativeY / center.y; 16 | 17 | return { 18 | ...getCoordinates(mouseMovementX, mouseMovementY), 19 | target, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **vue-kinesis and Vue.js versions 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/utils/elementMovement.js: -------------------------------------------------------------------------------- 1 | import getCoordinates from './getCoordinates' 2 | import clamp from './clamp' 3 | 4 | export default function (action) { 5 | const { 6 | y, x, target, originX = 50, strength = 10, event = null, minX, minY, maxX, maxY, 7 | } = action 8 | 9 | let { originY = 50, } = action 10 | 11 | if (event === 'scroll') { 12 | originY = -originY / 2 13 | } 14 | 15 | const movementX = clamp( 16 | (x - originX / 50) * strength, 17 | minX, 18 | maxX 19 | ) 20 | const movementY = clamp( 21 | (y - originY / 50) * strength, 22 | minY, 23 | maxY 24 | ) 25 | 26 | return { 27 | ...getCoordinates(movementX, movementY), 28 | target, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/cyclicMovement.js: -------------------------------------------------------------------------------- 1 | import getCoordinates from './getCoordinates' 2 | 3 | export default function (cycleData) { 4 | const { 5 | referencePosition, 6 | shape, 7 | event, 8 | cycles, 9 | strength, 10 | } = cycleData 11 | 12 | const spanningRangeX = event === 'scroll' ? window.innerWidth : shape.width 13 | const spanningRangeY = event === 'scroll' ? window.innerHeight : shape.height 14 | 15 | const radialPositionX = ((referencePosition.x - shape.left) * (Math.PI * 2)) / spanningRangeX 16 | const radialPositionY = ((referencePosition.y - shape.top) * (Math.PI * 2)) / spanningRangeY 17 | 18 | const cycleX = spanningRangeX * Math.sin(radialPositionX * cycles) 19 | const cycleY = spanningRangeY * Math.sin(radialPositionY * cycles) 20 | 21 | return getCoordinates( 22 | (cycleX * strength) / (spanningRangeX / 2), 23 | (cycleY * strength) / (spanningRangeY / 2) 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/throttle.js: -------------------------------------------------------------------------------- 1 | export default function throttle(callback, delay, type) { 2 | let last 3 | let timer 4 | // eslint-disable-next-line func-names 5 | return function () { 6 | const context = this 7 | let newDelay 8 | if (type === 'scroll') { 9 | newDelay = delay 10 | } else { 11 | newDelay = context.duration > 1000 ? delay : context.duration / 10 12 | } 13 | 14 | const now = +new Date() 15 | // eslint-disable-next-line prefer-rest-params 16 | const args = arguments 17 | if (last && now < last + newDelay) { 18 | clearTimeout(timer) 19 | timer = setTimeout(() => { 20 | requestAnimationFrame(() => { 21 | last = now 22 | callback.apply(context, args) 23 | }) 24 | }, newDelay) 25 | } else { 26 | requestAnimationFrame(() => { 27 | last = now 28 | callback.apply(context, args) 29 | }) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | import KinesisAudio from './kinesis-audio.vue' 2 | import KinesisContainer from './kinesis-container.vue' 3 | import KinesisDistance from './kinesis-distance.vue' 4 | import KinesisElement from './kinesis-element.vue' 5 | import KinesisScroll from './kinesis-scroll.vue' 6 | 7 | const Plugin = { 8 | install(vue) { 9 | vue.component(KinesisAudio.name, KinesisAudio) 10 | vue.component(KinesisContainer.name, KinesisContainer) 11 | vue.component(KinesisDistance.name, KinesisDistance) 12 | vue.component(KinesisElement.name, KinesisElement) 13 | vue.component(KinesisScroll.name, KinesisScroll) 14 | }, 15 | } 16 | 17 | let GlobalVue = null 18 | 19 | if (typeof window !== 'undefined') { 20 | GlobalVue = window.vue 21 | } else if (typeof global !== 'undefined') { 22 | GlobalVue = global.vue 23 | } 24 | 25 | if (GlobalVue) { 26 | GlobalVue.use(Plugin) 27 | } 28 | 29 | export default Plugin 30 | 31 | export { 32 | KinesisAudio, 33 | KinesisContainer, 34 | KinesisDistance, 35 | KinesisElement, 36 | KinesisScroll, 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Amine Bouyarmane 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/mixins/motion_mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | type: { 4 | type: String, 5 | default: 'translate', // translate, rotate, scale, scaleX, scaleY, depth, depth_inv, custom 6 | }, 7 | transformOrigin: { 8 | type: String, 9 | default: 'center', 10 | }, 11 | originX: { 12 | type: Number, 13 | default: 50, 14 | }, 15 | originY: { 16 | type: Number, 17 | default: 50, 18 | }, 19 | strength: { 20 | type: Number, 21 | default: 10, 22 | }, 23 | audioIndex: { 24 | type: Number, 25 | default: 50, 26 | }, 27 | axis: { 28 | type: String, 29 | default: null, 30 | }, 31 | maxX: { 32 | type: Number, 33 | default: null, 34 | }, 35 | maxY: { 36 | type: Number, 37 | default: null, 38 | }, 39 | minX: { 40 | type: Number, 41 | default: null, 42 | }, 43 | minY: { 44 | type: Number, 45 | default: null, 46 | }, 47 | cycle: { 48 | type: Number, 49 | default: 0, 50 | }, 51 | }, 52 | methods: { 53 | strengthManager() { 54 | return this.type === 'depth' || this.type === 'depth_inv' 55 | ? Math.abs(this.strength) 56 | : this.strength 57 | }, 58 | }, 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/entry.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import KinesisContainer from './components/kinesis-container.vue'; 3 | import KinesisElement from './components/kinesis-element.vue'; 4 | import KinesisAudio from './components/kinesis-audio.vue'; 5 | import KinesisScroll from './components/kinesis-scroll.vue'; 6 | import KinesisDistance from './components/kinesis-distance.vue'; 7 | 8 | import * as components from './components/index'; 9 | 10 | const install = function (vue) { 11 | if (install.installed) { 12 | return; 13 | } 14 | install.installed = true; 15 | 16 | for (const name in components) { 17 | vue.use(components[name]); 18 | } 19 | 20 | vue.component('kinesis-container', KinesisContainer); 21 | vue.component('kinesis-element', KinesisElement); 22 | vue.component('kinesis-audio', KinesisAudio); 23 | vue.component('kinesis-scroll', KinesisScroll); 24 | vue.component('kinesis-distance', KinesisDistance); 25 | }; 26 | 27 | const Plugin = { install }; 28 | 29 | let GlobalVue = null; 30 | 31 | if (typeof window !== 'undefined') { 32 | GlobalVue = window.vue; 33 | } else if (typeof global !== 'undefined') { 34 | GlobalVue = global.vue; 35 | } 36 | 37 | if (GlobalVue) { 38 | GlobalVue.use(Plugin); 39 | } 40 | 41 | export default Plugin; 42 | 43 | export { 44 | KinesisContainer, KinesisElement, KinesisScroll, KinesisAudio, KinesisDistance, 45 | }; 46 | -------------------------------------------------------------------------------- /src/mixins/container_events.js: -------------------------------------------------------------------------------- 1 | import isTouch from '../utils/isTouch' 2 | 3 | export default { 4 | props: { 5 | event: { 6 | type: String, 7 | default: 'move', // move, scroll 8 | }, 9 | }, 10 | data() { 11 | return { 12 | eventMap: { 13 | orientation: 'deviceorientation', 14 | scroll: 'scroll', 15 | move: isTouch() ? 'deviceorientation' : null, 16 | }, 17 | } 18 | }, 19 | methods: { 20 | addEvents() { 21 | if (this.eventMap[this.event]) { 22 | window.addEventListener( 23 | this.eventMap[this.event], 24 | this.handleMovement, 25 | true, 26 | ) 27 | } 28 | }, 29 | removeEvents() { 30 | if (this.eventMap[this.event]) { 31 | window.removeEventListener( 32 | this.eventMap[this.event], 33 | this.handleMovement, 34 | true, 35 | ) 36 | } 37 | }, 38 | }, 39 | watch: { 40 | event(newVal, oldVal) { 41 | if (this.eventMap[newVal]) { 42 | window.addEventListener( 43 | this.eventMap[newVal], 44 | this.handleMovement, 45 | true, 46 | ) 47 | } 48 | if (this.eventMap[oldVal]) { 49 | window.addEventListener( 50 | this.eventMap[oldVal], 51 | this.handleMovement, 52 | true, 53 | ) 54 | } 55 | }, 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/recommended', 8 | '@vue/airbnb' 9 | ], 10 | parserOptions: { 11 | parser: 'babel-eslint' 12 | }, 13 | rules: { 14 | "linebreak-style": ["error", (process.platform === "win32" ? "windows" : "unix")], 15 | "comma-dangle": [1, { 16 | "objects": "always", 17 | "arrays": "ignore", 18 | "imports": "ignore", 19 | "exports": "ignore", 20 | "functions": "ignore" 21 | }], 22 | 'max-len': ['warn', { 23 | code: 100, 24 | ignoreComments: true, 25 | ignoreStrings: true, 26 | // fix for svg icons 27 | ignorePattern: 'd=([s]*?)', 28 | }], 29 | semi: ['error', 'never'], 30 | quotes: ['error', 'single'], 31 | 'no-multiple-empty-lines': ['error', { 32 | max: 1, 33 | maxBOF: 1 34 | }], 35 | 'no-param-reassign': 'off', 36 | 'max-classes-per-file': 'off', 37 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 38 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 39 | 'no-unused-vars': 'warn', 40 | "consistent-return": "off", 41 | 'vue/no-unused-vars': 'off', 42 | 'vue/require-default-prop': 'off', 43 | 'import/prefer-default-export': 'off', 44 | 'import/no-extraneous-dependencies': ['error', { 45 | devDependencies: true 46 | }], 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /src/mixins/transform_mixin.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable default-case */ 2 | export default { 3 | methods: { 4 | transformSwitch(type, x, y, s) { 5 | type = type === 'scaleX' || type === 'scaleY' ? 'scale' : type 6 | let transform 7 | switch (type) { 8 | case 'translate': 9 | transform = this.translateMovement(x, y) 10 | break 11 | case 'rotate': 12 | transform = this.rotateMovement(x, y) 13 | break 14 | case 'depth': 15 | transform = this.depthMovement(x, y, s) 16 | break 17 | case 'depth_inv': 18 | transform = this.depthMovement(-x, -y, s) 19 | break 20 | case 'scale': 21 | transform = this.scaleMovement(x, y) 22 | break 23 | } 24 | return transform 25 | }, 26 | translateMovement(x, y) { 27 | return `translate3d(${-x}px, ${-y}px, 0)` 28 | }, 29 | rotateMovement(x, y) { 30 | let movement 31 | if (!this.axis) { 32 | movement = x + y 33 | } else if (this.axis === 'x') { 34 | movement = 2 * x 35 | } else if (this.axis === 'y') { 36 | movement = 2 * y 37 | } 38 | return `rotate3d(0,0,1,${movement}deg)` 39 | }, 40 | depthMovement(x, y, s) { 41 | return `rotateX(${-y}deg) rotateY(${x}deg) translate3d(0,0,${s * 2}px)` 42 | }, 43 | scaleMovement(x, y) { 44 | const { type, } = this 45 | const movement = (Math.sign(this.strength) * (Math.abs(x) + Math.abs(y))) / 10 + 1 46 | return `scale3d(${type === 'scaleX' || type === 'scale' ? movement : 1}, 47 | ${type === 'scaleY' || type === 'scale' ? movement : 1}, 48 | 1)` 49 | }, 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /src/mixins/audio_mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | audio: { 4 | type: String, 5 | required: false, 6 | }, 7 | playAudio: { 8 | type: Boolean, 9 | default: false, 10 | }, 11 | }, 12 | data() { 13 | return { 14 | analyser: null, 15 | audioArray: null, 16 | audioData: null, 17 | audioRef: null, 18 | wasPlayed: false, 19 | isPlaying: false, 20 | } 21 | }, 22 | watch: { 23 | audio() { 24 | this.wasPlayed = false 25 | this.isPlaying = false 26 | }, 27 | playAudio(play) { 28 | if (play) { 29 | this.play() 30 | } else { 31 | this.stop() 32 | } 33 | }, 34 | }, 35 | methods: { 36 | play() { 37 | if (!this.active) return 38 | if (!this.wasPlayed) { 39 | this.handleAudio() 40 | this.wasPlayed = true 41 | } 42 | this.isPlaying = true 43 | this.audioRef.play() 44 | this.getSongData() 45 | }, 46 | stop() { 47 | this.isPlaying = false 48 | this.audioRef.pause() 49 | }, 50 | handleAudio() { 51 | const { audio, } = this.$refs 52 | this.audioRef = audio 53 | const context = new AudioContext() 54 | const src = context.createMediaElementSource(audio) 55 | const analyser = context.createAnalyser() 56 | src.connect(analyser) 57 | analyser.connect(context.destination) 58 | analyser.fftSize = 256 59 | const bufferLength = analyser.frequencyBinCount 60 | const audioArray = new Uint8Array(bufferLength) 61 | this.audioArray = audioArray 62 | this.analyser = analyser 63 | }, 64 | getSongData() { 65 | if (this.isPlaying) { 66 | this.analyser.getByteFrequencyData(this.audioArray) 67 | 68 | this.audioData = new Array(this.audioArray) // @Todo reactivity issue 69 | 70 | requestAnimationFrame(this.getSongData) 71 | } 72 | }, 73 | }, 74 | } 75 | -------------------------------------------------------------------------------- /src/components/kinesis-audio.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-kinesis", 3 | "version": "1.3.3", 4 | "description": "Easily create complexe interactive animations with Vue.js", 5 | "author": { 6 | "name": "Amine Bouyarmane", 7 | "email": "amine.bouyarmane@gmail.com" 8 | }, 9 | "scripts": { 10 | "serve": "vue-cli-service serve dev/serve.js", 11 | "build": "cross-env NODE_ENV=production rollup --config build/rollup.config.js", 12 | "lint": "vue-cli-service lint", 13 | "build:es": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format es", 14 | "build:ssr": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format cjs", 15 | "build:unpkg": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format iife" 16 | }, 17 | "main": "dist/vue-kinesis.ssr.js", 18 | "module": "dist/vue-kinesis.esm.js", 19 | "browser": "dist/vue-kinesis.esm.js", 20 | "unpkg": "dist/vue-kinesis.min.js", 21 | "files": [ 22 | "dist/*", 23 | "src/**/*.vue" 24 | ], 25 | "dependencies": {}, 26 | "devDependencies": { 27 | "@babel/core": "^7.14.5", 28 | "@babel/preset-env": "^7.14.5", 29 | "@rollup/plugin-alias": "^2.2.0", 30 | "@rollup/plugin-commonjs": "^11.1.0", 31 | "@rollup/plugin-replace": "^2.4.2", 32 | "@vue/cli-plugin-babel": "^4.5.13", 33 | "@vue/cli-plugin-eslint": "^4.5.13", 34 | "@vue/cli-service": "^4.5.13", 35 | "@vue/eslint-config-airbnb": "^5.0.2", 36 | "babel-eslint": "^10.1.0", 37 | "cross-env": "^7.0.2", 38 | "eslint": "^6.7.2", 39 | "eslint-plugin-import": "^2.23.4", 40 | "eslint-plugin-vue": "^6.2.2", 41 | "lint-staged": "^9.5.0", 42 | "minimist": "^1.2.5", 43 | "rollup": "^2.51.2", 44 | "rollup-plugin-babel": "^4.4.0", 45 | "rollup-plugin-terser": "^5.3.0", 46 | "rollup-plugin-vue": "^5.1.9", 47 | "vue": "^2.6.14", 48 | "vue-template-compiler": "^2.6.14" 49 | }, 50 | "peerDependencies": { 51 | "vue": "^2.6.11" 52 | }, 53 | "engines": { 54 | "node": ">=10" 55 | }, 56 | "gitHooks": { 57 | "pre-commit": "lint-staged" 58 | }, 59 | "keywords": [ 60 | "frontend", 61 | "animation", 62 | "interaction", 63 | "vue", 64 | "vue.js", 65 | "parallax", 66 | "mouse", 67 | "hover", 68 | "scroll", 69 | "gyroscope", 70 | "audio" 71 | ], 72 | "licence": "MIT", 73 | "lint-staged": { 74 | "*.{js,jsx,vue}": [ 75 | "vue-cli-service lint", 76 | "git add" 77 | ] 78 | }, 79 | "repository": { 80 | "type": "git", 81 | "url": "https://github.com/Aminerman/vue-kinesis" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/components/kinesis-scroll.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 125 | -------------------------------------------------------------------------------- /src/components/kinesis-element.vue: -------------------------------------------------------------------------------- 1 | 146 | -------------------------------------------------------------------------------- /src/components/kinesis-distance.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 172 | -------------------------------------------------------------------------------- /src/components/kinesis-container.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # October 2024: A full TS version is now available [KinesisJS](https://kinesisjs.com). You can use it in your vue projects if you need any of the new features. It works with Vue but a dedicated Vue version is in the works. 2 | # March 2024: The project has been on standby for a while now. But good news! I'm working on a brand new version, more robust, with better documentation and more features! 3 | What's in preparation: 4 | - Rewriting everything in TS 5 | - New interactions 6 | - A detailed documentation 7 | - A vanilla TS version 8 | 9 | # vue-kinesis 10 | 11 | [![npm](https://img.shields.io/npm/v/vue-kinesis.svg)](https://img.shields.io/npm/v/vue-kinesis.svg) 12 | [![vue2](https://img.shields.io/badge/vue-2.x-brightgreen.svg)](https://vuejs.org/) 13 | [![vue2](https://img.shields.io/badge/vue-3.x-brightgreen.svg)](https://vuejs.org/) 14 | 15 | Easy to use Vue.js components for creating interactive animations 16 | 17 | ## Demo 18 | 19 | [Kinesis Demo](https://aminerman.com/kinesis/) 20 | 21 | ## Tutorials 22 | 23 | - [LogRocket - Top 5 Vue Animation Libraries](https://blog.logrocket.com/top-5-vue-animation-libraries-compared/) 24 | - [LogRocket - Interactive Vue Animations with Kinesis](https://blog.logrocket.com/interactive-vue-animations-with-kinesis/) 25 | - [Leonardo Gruppelli - Kinesis Animation for Nuxt](https://medium.com/@leonardo.gruppelli/kinesis-awesome-animations-for-your-vue-nuxt-applications-8c16ae701e92) 26 | - [Coliss - 便利なのが登場!Vue.jsでインタラクティブなアニメーションを簡単に実装できる軽量コンポーネント -Kinesis](https://coliss.com/articles/build-websites/operation/javascript/interactive-animations-with-vue-js-kinesis.html) 27 | - [Kabanoki - コイツ動くぞ?!的なアニメーションが付けられる「vue-kinesis」](https://www.kabanoki.net/5792/) 28 | - [Mebee - Nuxt.js vue-kinesisを使用してアニメーションをかける](https://mebee.info/2020/05/18/post-6592/) 29 | - ... Feel free to open a PR if you want to suggest a tutorial link 🙏 30 | 31 | 32 | # Vue3 - Installation 33 | 34 | ``` 35 | npm install --save vue-kinesis@next 36 | ``` 37 | 38 | ## Vue3 - Default import 39 | 40 | Install all the components: 41 | 42 | ```javascript 43 | import { createApp } from "vue"; 44 | import App from "./App.vue"; 45 | import VueKinesis from "vue-kinesis"; 46 | 47 | const app = createApp(App); 48 | app.use(VueKinesis); 49 | 50 | app.mount("#app"); 51 | ``` 52 | 53 | # Vue2 - Installation 54 | 55 | ``` 56 | npm install --save vue-kinesis 57 | ``` 58 | 59 | ## Vue2 - Default import 60 | 61 | Install all the components: 62 | 63 | ```javascript 64 | import Vue from 'vue' 65 | import VueKinesis from 'vue-kinesis' 66 | 67 | Vue.use(VueKinesis) 68 | ``` 69 | 70 | Use specific components: 71 | 72 | ```javascript 73 | import Vue from 'vue' 74 | import { KinesisContainer, KinesisElement } from 'vue-kinesis' 75 | 76 | Vue.component('kinesis-container', KinesisContainer) 77 | Vue.component('kinesis-element', KinesisElement) 78 | ``` 79 | 80 | ## Browser 81 | 82 | ```html 83 | 84 | 85 | ``` 86 | 87 | 88 | # Usage 89 | 90 | [How to use](https://aminerman.com/kinesis/) 91 | 92 | 93 | ## Props 94 | 95 | ### kinesis-container 96 | 97 | | Prop | Type | Default Value | Description 98 | |----------|:-------------:|------|------| 99 | | active | Boolean | true | To enable or disable the interactions | 100 | | duration | Number | 1000 | Speed of the parallax animation in ms | 101 | | easing | String | "cubic-bezier(0.23, 1, 0.32, 1)" | Easing of the parallax animation | 102 | | tag | String | div | Takes any valid html tag | 103 | | event | String | "move" | Event to which the container will react. Possible values are "move" and "scroll" | 104 | | perspective | Number | 1000 | Effective for the 'depth' parallax type | 105 | | audio | String | | Path towards an audio file | 106 | | playAudio | Boolean | | Start/Stop the attached audio file | 107 | 108 | ### kinesis-element 109 | | Prop | Type | Default Value | Description 110 | |----------|:-------------:|------|------| 111 | | strength | Number | 10 | Strength of the motion effect | 112 | | type | String | "translate" | translate - rotate - scale - scaleX - scaleY - depth - depth_inv | 113 | | tag | String | "div" | Takes any valid html tag | 114 | | transformOrigin | String | "center" | Similar to the CSS transform-origin property | 115 | | originX | Number | 50 | The motion's origin relative to the container, on the X axis. 50 being the center of the container, 0 the left side, 100 the right side. | 116 | | originY | Number | 50 | The motion's origin relative to the container, on the Y axis. 50 being the center of the container, 0 the top side, 100 the bottom side. | 117 | | axis | String | null | Constrain the movement to one axis. Possible values: "x" - "y" | 118 | | maxX | Number | null | Limit the maximum range of the movement on the X axis | 119 | | maxY | Number | null | Limit the maximum range of the movement on the Y axis | 120 | | minX | Number | null | Limit the minimum range of the movement on the X axis | 121 | | minY | Number | null | Limit the minimum range of the movement on the Y axis | 122 | | cycle | Number | 0 | How many times the movement will repeat | 123 | 124 | ### kinesis-audio 125 | | Prop | Type | Default Value | Description 126 | |----------|:-------------:|------|------| 127 | | audioIndex | Number | 50 | To which frequency to react, on a range of integer values that goes from 0 to 127. | 128 | | strength | Number | 10 | Strength of the motion effect | 129 | | type | String | "translate" | translate - rotate - scale - scaleX - scaleY - depth - depth_inv | 130 | | tag | String | "div" | Takes any valid html tag | 131 | | transformOrigin | String | "center" | Similar to the CSS transform-origin property | 132 | | originX | Number | 50 | The motion's origin relative to the container, on the X axis. 50 being the center of the container, 0 the left side, 100 the right side. | 133 | | originY | Number | 50 | The motion's origin relative to the container, on the Y axis. 50 being the center of the container, 0 the top side, 100 the bottom side. | 134 | | axis | String | null | Constrain the movement to one axis. Possible values: "x" - "y" | 135 | | maxX | Number | null | Limit the maximum range of the movement on the X axis | 136 | | maxY | Number | null | Limit the maximum range of the movement on the Y axis | 137 | | minX | Number | null | Limit the minimum range of the movement on the X axis | 138 | | minY | Number | null | Limit the minimum range of the movement on the Y axis | 139 | | cycle | Number | 0 | How many times the movement will repeat | 140 | 141 | ## Migrating from vue-mouse-parallax 142 | Migration from vue-mouse-parallax is quite easy: 143 | 144 | ### Components 145 | - parallax-container -> kinesis-container 146 | - parallax-element -> kinesis-element 147 | 148 | ### Props 149 | - parallaxStrength -> strength 150 | - animationDuration -> duration 151 | 152 | ### Prop values 153 | - translation -> translate 154 | - rotation -> rotate 155 | 156 | ## License 157 | 158 | [MIT](http://opensource.org/licenses/MIT) 159 | -------------------------------------------------------------------------------- /dist/vue-kinesis.min.js: -------------------------------------------------------------------------------- 1 | var VueKinesis=function(t){"use strict";function e(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,i)}return n}function n(t){for(var n=1;n=0&&t.right>=0&&t.top<=(window.innerHeight||document.documentElement.clientHeight)&&t.left<=(window.innerWidth||document.documentElement.clientWidth)}function u(){try{return/Mobi|Android/i.test(navigator.userAgent)}catch(t){return!0}}function h(t,e,n){var i,r;return function(){var a,o=this;a="scroll"===n||o.duration>1e3?e:o.duration/10;var s=+new Date,c=arguments;i&&sn?n:e&&t0&&(t="x"===this.axis?g:0,e="y"===this.axis?y:0),{transform:this.transformSwitch(this.type,t,e,this.strength)}},strengthManager:function(){return"depth"===this.type||"depth_inv"===this.type?Math.abs(this.strength):this.strength}},render:function(t){return t(this.tag,{style:n(n({},this.transform),this.transformParameters)},this.$slots.default)}},void 0,void 0,void 0,!1,void 0,void 0,void 0),p={props:{type:{type:String,default:"translate"},transformOrigin:{type:String,default:"center"},originX:{type:Number,default:50},originY:{type:Number,default:50},strength:{type:Number,default:10},audioIndex:{type:Number,default:50},axis:{type:String,default:null},maxX:{type:Number,default:null},maxY:{type:Number,default:null},minX:{type:Number,default:null},minY:{type:Number,default:null},cycle:{type:Number,default:0}},methods:{strengthManager:function(){return"depth"===this.type||"depth_inv"===this.type?Math.abs(this.strength):this.strength}}},g=l({render:function(){var t=this.$createElement;return(this._self._c||t)(this.tag,{tag:"component",style:Object.assign({},this.transform,this.transformParameters)},[this._t("default")],2)},staticRenderFns:[]},void 0,{name:"KinesisAudio",inject:["context"],mixins:[p],props:{tag:{type:String,default:"div"},audioIndex:{type:Number,default:50}},computed:{transform:function(){return this.transformAudio()},transformParameters:function(){return{transitionProperty:"transform",transitionDuration:this.transitionDuration,transformOrigin:this.transformOrigin,transitionTimingFunction:this.transitionTimingFunction}},transitionDuration:function(){var t=this.context.duration;return"".concat(t,"ms")},transitionTimingFunction:function(){return this.context.easing}},methods:{transformAudio:function(){var t=this.context.audioData;if(t){var e,n,i=this.type,r=this.strength;switch(i){case"translate":e=t?t[0][this.audioIndex]:0,n="translate3d(".concat(e*r,"px, 0, 0)");break;case"rotate":e=t?t[0][this.audioIndex]:0,n="rotate3d(0,0,1,".concat(e*r/10,"deg)");break;case"scale":e=t?t[0][this.audioIndex]/r<1?1:t[0][this.audioIndex]/(2*r):1,n="scale(".concat(e,")")}return{transform:n}}}}},void 0,!1,void 0,!1,void 0,void 0,void 0),y=l({render:function(){var t=this.$createElement;return(this._self._c||t)(this.tag,{tag:"component",style:Object.assign({},this.transform,this.transformParameters)},[this._t("default")],2)},staticRenderFns:[]},void 0,{name:"KinesisScroll",mixins:[{props:{active:{type:Boolean,default:!0},duration:{type:Number,default:1e3},easing:{type:String,default:"cubic-bezier(0.23, 1, 0.32, 1)"},tag:{type:String,default:"div"}}},{props:{perspective:{type:Number,default:1e3}},computed:{style:function(){return{perspective:"".concat(this.perspective,"px")}}}},p,m],data:function(){return{transform:{}}},computed:{transformParameters:function(){return{transitionProperty:"transform",transitionDuration:this.transitionDuration,transformOrigin:this.transformOrigin,transitionTimingFunction:this.easing}},transitionDuration:function(){return"".concat(this.duration,"ms")}},mounted:function(){window.addEventListener("scroll",this.handleScroll,{passive:!0})},beforeDestroy:function(){window.removeEventListener("scroll",this.handleScroll,{passive:!0})},methods:{getCycleMovement:function(t,e,n,i,r){var a=(t-r.left)*(2*Math.PI)/n,o=(e-r.top)*(2*Math.PI)/i;this.cycleMovement={x:a,y:o,width:n,height:i}},handleScroll:h((function(){if(this.active){var t=this.$el.getBoundingClientRect();c(t)&&t.height&&this.transformBehavior(t)}}),19,"scroll"),transformBehavior:function(t){var e,n,i=(t.top-window.innerHeight)/(t.height+window.innerHeight);if(this.cycle<=0){var r=i*this.strength;e="x"===this.axis?r:0,n="y"!==this.axis&&this.axis?0:r,this.maxX&&(e=Math.min(e,this.maxX)),this.minX&&(e=Math.max(e,this.minX)),this.maxY&&(n=Math.min(n,this.maxY)),this.minY&&(n=Math.max(n,this.minY))}else if(this.cycle>0){var a=this.getCycleMovement(0,0,window.innerWidth,window.innerHeight,t),o=a.x,s=a.y,c=a.width,u=a.height,h=c*Math.sin(o*this.cycle),l=u*Math.sin(s*this.cycle);e="x"===this.axis?h/(c/2)*this.strength:0,n="y"!==this.axis&&this.axis?0:l/(u/2)*this.strength}var d=this.type;d="scaleX"===d||"scaleY"===d?"scale":d;var f=this.transformSwitch(d,e,n,this.strength);this.transform={transform:f}}}},void 0,!1,void 0,!1,void 0,void 0,void 0),b=l({render:function(){var t=this.$createElement;return(this._self._c||t)(this.tag,{tag:"component",style:Object.assign({},this.transform,this.transformParameters)},[this._t("default")],2)},staticRenderFns:[]},void 0,{name:"KinesisDistance",props:{tag:{type:String,default:"div"},type:{type:String,default:"translate"},transformOrigin:{type:String,default:"center"},originX:{type:Number,default:50},originY:{type:Number,default:50},strength:{type:Number,default:10},axis:{type:String,default:null},maxX:{type:Number,default:null},maxY:{type:Number,default:null},minX:{type:Number,default:null},minY:{type:Number,default:null},distance:{type:Number,default:100},cycle:{type:Number,default:0},active:{type:Boolean,default:!0},duration:{type:Number,default:1001},easing:{type:String,default:"cubic-bezier(0.23, 1, 0.32, 1)"},perspective:{type:Number,default:1e3}},data:function(){return{pointer:{x:0,y:0},transform:{},component:"kidistance",throttle:500}},computed:{style:function(){return{perspective:"".concat(this.perspective,"px")}},transformParameters:function(){return{position:"relative",transitionProperty:"transform",transitionDuration:this.transitionDuration,transformOrigin:this.transformOrigin,transitionTimingFunction:this.easing}},transitionDuration:function(){return"".concat(this.duration,"ms")}},mounted:function(){window.addEventListener("scroll",this.handleMovement)},beforeDestroy:function(){window.removeEventListener("scroll",this.handleMovement)},methods:{getCoordinates:function(t,e){var n=this.$el.getBoundingClientRect();return{x:t+n.left,y:e+n.top}},getDistance:function(t,e,n,i){return Math.floor(Math.hypot(e-t,i-n))},handleMovement:h((function(t){window.addEventListener("mousemove",this.handleMovement);var e=this.pointer;e.x=t.clientX,e.y=t.clientY,this.transformBehavior()}),50),transformBehavior:function(){var t=this.$el.getBoundingClientRect(),e=this.getCoordinates(t.width/2,t.height/2),n=this.getDistance(this.pointer.x,e.x,this.pointer.y,e.y);if(n>this.distance)return this.transform={},void(this.throttle=500);this.throttle=50;var i="scale(".concat(n/this.distance,")");this.transform={transform:i}},scaleMovement:function(t,e){var n=this.type,i=Math.sign(this.strength)*(Math.abs(t)+Math.abs(e))/10+1;return"scale3d(".concat("scaleX"===n||"scale"===n?i:1,",\n ").concat("scaleY"===n||"scale"===n?i:1,",\n 1)")}}},void 0,!1,void 0,!1,void 0,void 0,void 0),x={install:function(t){t.component(g.name,g),t.component(d.name,d),t.component(b.name,b),t.component(v.name,v),t.component(y.name,y)}},w=null;"undefined"!=typeof window?w=window.vue:"undefined"!=typeof global&&(w=global.vue),w&&w.use(x);var M=Object.freeze({__proto__:null,default:x,KinesisAudio:g,KinesisContainer:d,KinesisDistance:b,KinesisElement:v,KinesisScroll:y}),S={install:function t(e){if(!t.installed){for(var n in t.installed=!0,M)e.use(M[n]);e.component("kinesis-container",d),e.component("kinesis-element",v),e.component("kinesis-audio",g),e.component("kinesis-scroll",y),e.component("kinesis-distance",b)}}},O=null;return"undefined"!=typeof window?O=window.vue:"undefined"!=typeof global&&(O=global.vue),O&&O.use(S),t.KinesisAudio=g,t.KinesisContainer=d,t.KinesisDistance=b,t.KinesisElement=v,t.KinesisScroll=y,t.default=S,Object.defineProperty(t,"__esModule",{value:!0}),t}({}); -------------------------------------------------------------------------------- /dist/vue-kinesis.esm.js: -------------------------------------------------------------------------------- 1 | function getCoordinates (x, y) { 2 | return { 3 | x, 4 | y 5 | }; 6 | } 7 | 8 | function getCenter (element) { 9 | return getCoordinates(element ? element.width / 2 : 0, element ? element.height / 2 : 0); 10 | } 11 | 12 | function mouseMovement (action) { 13 | const { 14 | target, 15 | event 16 | } = action; 17 | const x = event.clientX; 18 | const y = event.clientY; 19 | const relativeX = x - target.left; 20 | const relativeY = y - target.top; 21 | const center = getCenter(target); 22 | const mouseMovementX = relativeX / center.x; 23 | const mouseMovementY = relativeY / center.y; 24 | return { ...getCoordinates(mouseMovementX, mouseMovementY), 25 | target 26 | }; 27 | } 28 | 29 | function scrollMovement (shape) { 30 | const { 31 | target 32 | } = shape; 33 | const x = (target.left - window.innerWidth) / (target.width + window.innerWidth); 34 | const y = (target.top - window.innerHeight) / (target.height + window.innerHeight); 35 | return { ...getCoordinates(x, y), 36 | target 37 | }; 38 | } 39 | 40 | function orientationElement (action) { 41 | const { 42 | event, 43 | target 44 | } = action; 45 | const x = event.gamma / 45; 46 | const y = event.beta / 90; 47 | return { ...getCoordinates(x, y), 48 | target 49 | }; 50 | } 51 | 52 | function inViewport(element) { 53 | const isInViewport = element.bottom >= 0 && element.right >= 0 && element.top <= (window.innerHeight || document.documentElement.clientHeight) && element.left <= (window.innerWidth || document.documentElement.clientWidth); 54 | return isInViewport; 55 | } 56 | 57 | function isTouch() { 58 | try { 59 | return /Mobi|Android/i.test(navigator.userAgent); 60 | } catch (e) { 61 | return true; 62 | } 63 | } 64 | 65 | function throttle(callback, delay, type) { 66 | let last; 67 | let timer; // eslint-disable-next-line func-names 68 | 69 | return function () { 70 | const context = this; 71 | let newDelay; 72 | 73 | if (type === 'scroll') { 74 | newDelay = delay; 75 | } else { 76 | newDelay = context.duration > 1000 ? delay : context.duration / 10; 77 | } 78 | 79 | const now = +new Date(); // eslint-disable-next-line prefer-rest-params 80 | 81 | const args = arguments; 82 | 83 | if (last && now < last + newDelay) { 84 | clearTimeout(timer); 85 | timer = setTimeout(() => { 86 | requestAnimationFrame(() => { 87 | last = now; 88 | callback.apply(context, args); 89 | }); 90 | }, newDelay); 91 | } else { 92 | requestAnimationFrame(() => { 93 | last = now; 94 | callback.apply(context, args); 95 | }); 96 | } 97 | }; 98 | } 99 | 100 | var audioMixin = { 101 | props: { 102 | audio: { 103 | type: String, 104 | required: false 105 | }, 106 | playAudio: { 107 | type: Boolean, 108 | default: false 109 | } 110 | }, 111 | 112 | data() { 113 | return { 114 | analyser: null, 115 | audioArray: null, 116 | audioData: null, 117 | audioRef: null, 118 | wasPlayed: false, 119 | isPlaying: false 120 | }; 121 | }, 122 | 123 | watch: { 124 | audio() { 125 | this.wasPlayed = false; 126 | this.isPlaying = false; 127 | }, 128 | 129 | playAudio(play) { 130 | if (play) { 131 | this.play(); 132 | } else { 133 | this.stop(); 134 | } 135 | } 136 | 137 | }, 138 | methods: { 139 | play() { 140 | if (!this.active) return; 141 | 142 | if (!this.wasPlayed) { 143 | this.handleAudio(); 144 | this.wasPlayed = true; 145 | } 146 | 147 | this.isPlaying = true; 148 | this.audioRef.play(); 149 | this.getSongData(); 150 | }, 151 | 152 | stop() { 153 | this.isPlaying = false; 154 | this.audioRef.pause(); 155 | }, 156 | 157 | handleAudio() { 158 | const { 159 | audio 160 | } = this.$refs; 161 | this.audioRef = audio; 162 | const context = new AudioContext(); 163 | const src = context.createMediaElementSource(audio); 164 | const analyser = context.createAnalyser(); 165 | src.connect(analyser); 166 | analyser.connect(context.destination); 167 | analyser.fftSize = 256; 168 | const bufferLength = analyser.frequencyBinCount; 169 | const audioArray = new Uint8Array(bufferLength); 170 | this.audioArray = audioArray; 171 | this.analyser = analyser; 172 | }, 173 | 174 | getSongData() { 175 | if (this.isPlaying) { 176 | this.analyser.getByteFrequencyData(this.audioArray); 177 | this.audioData = new Array(this.audioArray); // @Todo reactivity issue 178 | 179 | requestAnimationFrame(this.getSongData); 180 | } 181 | } 182 | 183 | } 184 | }; 185 | 186 | // 187 | var script$4 = { 188 | name: 'KinesisContainer', 189 | mixins: [audioMixin], 190 | props: { 191 | tag: { 192 | type: String, 193 | default: 'div' 194 | }, 195 | event: { 196 | type: String, 197 | default: 'move' 198 | }, 199 | active: { 200 | type: Boolean, 201 | default: true 202 | }, 203 | duration: { 204 | type: Number, 205 | default: 1000 206 | }, 207 | easing: { 208 | type: String, 209 | default: 'cubic-bezier(0.23, 1, 0.32, 1)' 210 | }, 211 | perspective: { 212 | type: Number, 213 | default: 1000 214 | } 215 | }, 216 | 217 | provide() { 218 | const context = {}; 219 | const providedProps = ['audioData', 'duration', 'easing', 'event', 'eventData', 'isMoving', 'movement', 'shape']; 220 | providedProps.forEach(prop => Object.defineProperty(context, prop, { 221 | enumerable: true, 222 | get: () => this[prop] 223 | })); 224 | return { 225 | context 226 | }; 227 | }, 228 | 229 | data() { 230 | var _this$$el; 231 | 232 | return { 233 | shape: (_this$$el = this.$el) === null || _this$$el === void 0 ? void 0 : _this$$el.getBoundingClientRect(), 234 | isMoving: false, 235 | leftOnce: false, 236 | movement: { 237 | x: 0, 238 | y: 0 239 | }, 240 | eventMap: { 241 | orientation: 'deviceorientation', 242 | scroll: 'scroll', 243 | move: isTouch() ? 'deviceorientation' : null 244 | } 245 | }; 246 | }, 247 | 248 | computed: { 249 | eventActions() { 250 | var _this$shape; 251 | 252 | return { 253 | move: { 254 | action: mouseMovement, 255 | condition: this.isMoving && !isTouch(), 256 | type: isTouch() ? 'deviceorientation' : null 257 | }, 258 | scroll: { 259 | action: scrollMovement, 260 | condition: !!((_this$shape = this.shape) !== null && _this$shape !== void 0 && _this$shape.height), 261 | type: 'scroll' 262 | }, 263 | orientation: { 264 | action: orientationElement, 265 | condition: this.event === 'move' && isTouch(), 266 | type: 'deviceorientation' 267 | } 268 | }; 269 | }, 270 | 271 | style() { 272 | return { 273 | perspective: `${this.perspective}px` 274 | }; 275 | } 276 | 277 | }, 278 | 279 | mounted() { 280 | this.addEvents(); 281 | }, 282 | 283 | beforeDestroy() { 284 | this.removeEvents(); 285 | }, 286 | 287 | methods: { 288 | handleMovementStart() { 289 | if (!this.active) return; 290 | this.isMoving = true; 291 | }, 292 | 293 | handleMovementStop() { 294 | if (!this.active) return; // fixes the specific case when mouseenter didn't trigger on page refresh 295 | 296 | this.leftOnce = true; 297 | this.isMoving = false; 298 | }, 299 | 300 | // eslint-disable-next-line func-names 301 | handleMovement: throttle(function (event) { 302 | if (!this.active) return; 303 | 304 | if (!this.isMoving && !this.leftOnce) { 305 | // fixes the specific case when mouseenter didn't trigger on page refresh 306 | this.handleMovementStart(); 307 | } 308 | 309 | this.shape = this.$el.getBoundingClientRect(); 310 | const isInViewport = inViewport(this.shape); 311 | const eventCondition = this.eventActions[this.event].condition; 312 | const eventAction = this.eventActions[this.event].action; 313 | 314 | if (isInViewport && eventCondition) { 315 | this.movement = eventAction({ 316 | target: this.shape, 317 | event 318 | }); 319 | this.eventData = getCoordinates(event.clientX, event.clientY); 320 | } 321 | }, 100), 322 | 323 | addEvents() { 324 | if (this.eventMap[this.event]) { 325 | window.addEventListener(this.eventMap[this.event], this.handleMovement, true); 326 | } 327 | }, 328 | 329 | removeEvents() { 330 | if (this.eventMap[this.event]) { 331 | window.removeEventListener(this.eventMap[this.event], this.handleMovement, true); 332 | } 333 | } 334 | 335 | } 336 | }; 337 | 338 | function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { 339 | if (typeof shadowMode !== 'boolean') { 340 | createInjectorSSR = createInjector; 341 | createInjector = shadowMode; 342 | shadowMode = false; 343 | } 344 | // Vue.extend constructor export interop. 345 | const options = typeof script === 'function' ? script.options : script; 346 | // render functions 347 | if (template && template.render) { 348 | options.render = template.render; 349 | options.staticRenderFns = template.staticRenderFns; 350 | options._compiled = true; 351 | // functional template 352 | if (isFunctionalTemplate) { 353 | options.functional = true; 354 | } 355 | } 356 | // scopedId 357 | if (scopeId) { 358 | options._scopeId = scopeId; 359 | } 360 | let hook; 361 | if (moduleIdentifier) { 362 | // server build 363 | hook = function (context) { 364 | // 2.3 injection 365 | context = 366 | context || // cached call 367 | (this.$vnode && this.$vnode.ssrContext) || // stateful 368 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional 369 | // 2.2 with runInNewContext: true 370 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { 371 | context = __VUE_SSR_CONTEXT__; 372 | } 373 | // inject component styles 374 | if (style) { 375 | style.call(this, createInjectorSSR(context)); 376 | } 377 | // register component module identifier for async chunk inference 378 | if (context && context._registeredComponents) { 379 | context._registeredComponents.add(moduleIdentifier); 380 | } 381 | }; 382 | // used by ssr in case component is cached and beforeCreate 383 | // never gets called 384 | options._ssrRegister = hook; 385 | } 386 | else if (style) { 387 | hook = shadowMode 388 | ? function (context) { 389 | style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); 390 | } 391 | : function (context) { 392 | style.call(this, createInjector(context)); 393 | }; 394 | } 395 | if (hook) { 396 | if (options.functional) { 397 | // register for functional component in vue file 398 | const originalRender = options.render; 399 | options.render = function renderWithStyleInjection(h, context) { 400 | hook.call(context); 401 | return originalRender(h, context); 402 | }; 403 | } 404 | else { 405 | // inject component registration as beforeCreate hook 406 | const existing = options.beforeCreate; 407 | options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; 408 | } 409 | } 410 | return script; 411 | } 412 | 413 | /* script */ 414 | const __vue_script__$4 = script$4; 415 | /* template */ 416 | 417 | var __vue_render__$3 = function () { 418 | var _vm = this; 419 | 420 | var _h = _vm.$createElement; 421 | 422 | var _c = _vm._self._c || _h; 423 | 424 | return _c(_vm.tag, { 425 | tag: "component", 426 | style: _vm.style, 427 | on: { 428 | "mousemove": _vm.handleMovement, 429 | "mouseenter": _vm.handleMovementStart, 430 | "mouseleave": _vm.handleMovementStop 431 | } 432 | }, [_vm._t("default"), _vm._v(" "), _vm.audio ? _c('audio', { 433 | ref: "audio", 434 | attrs: { 435 | "type": "audio/mpeg" 436 | }, 437 | on: { 438 | "ended": _vm.stop 439 | } 440 | }, [_c('source', { 441 | attrs: { 442 | "src": _vm.audio 443 | } 444 | })]) : _vm._e()], 2); 445 | }; 446 | 447 | var __vue_staticRenderFns__$3 = []; 448 | /* style */ 449 | 450 | const __vue_inject_styles__$4 = undefined; 451 | /* scoped */ 452 | 453 | const __vue_scope_id__$4 = undefined; 454 | /* module identifier */ 455 | 456 | const __vue_module_identifier__$4 = undefined; 457 | /* functional template */ 458 | 459 | const __vue_is_functional_template__$4 = false; 460 | /* style inject */ 461 | 462 | /* style inject SSR */ 463 | 464 | /* style inject shadow dom */ 465 | 466 | const __vue_component__$4 = /*#__PURE__*/normalizeComponent({ 467 | render: __vue_render__$3, 468 | staticRenderFns: __vue_staticRenderFns__$3 469 | }, __vue_inject_styles__$4, __vue_script__$4, __vue_scope_id__$4, __vue_is_functional_template__$4, __vue_module_identifier__$4, false, undefined, undefined, undefined); 470 | 471 | /* eslint-disable no-nested-ternary */ 472 | function clamp (value, min, max) { 473 | return max && value > max ? max : min && value < min ? min : value; 474 | } 475 | 476 | function elementMovement (action) { 477 | const { 478 | y, 479 | x, 480 | target, 481 | originX = 50, 482 | strength = 10, 483 | event = null, 484 | minX, 485 | minY, 486 | maxX, 487 | maxY 488 | } = action; 489 | let { 490 | originY = 50 491 | } = action; 492 | 493 | if (event === 'scroll') { 494 | originY = -originY / 2; 495 | } 496 | 497 | const movementX = clamp((x - originX / 50) * strength, minX, maxX); 498 | const movementY = clamp((y - originY / 50) * strength, minY, maxY); 499 | return { ...getCoordinates(movementX, movementY), 500 | target 501 | }; 502 | } 503 | 504 | /* eslint-disable default-case */ 505 | var transformMixin = { 506 | methods: { 507 | transformSwitch(type, x, y, s) { 508 | type = type === 'scaleX' || type === 'scaleY' ? 'scale' : type; 509 | let transform; 510 | 511 | switch (type) { 512 | case 'translate': 513 | transform = this.translateMovement(x, y); 514 | break; 515 | 516 | case 'rotate': 517 | transform = this.rotateMovement(x, y); 518 | break; 519 | 520 | case 'depth': 521 | transform = this.depthMovement(x, y, s); 522 | break; 523 | 524 | case 'depth_inv': 525 | transform = this.depthMovement(-x, -y, s); 526 | break; 527 | 528 | case 'scale': 529 | transform = this.scaleMovement(x, y); 530 | break; 531 | } 532 | 533 | return transform; 534 | }, 535 | 536 | translateMovement(x, y) { 537 | return `translate3d(${-x}px, ${-y}px, 0)`; 538 | }, 539 | 540 | rotateMovement(x, y) { 541 | let movement; 542 | 543 | if (!this.axis) { 544 | movement = x + y; 545 | } else if (this.axis === 'x') { 546 | movement = 2 * x; 547 | } else if (this.axis === 'y') { 548 | movement = 2 * y; 549 | } 550 | 551 | return `rotate3d(0,0,1,${movement}deg)`; 552 | }, 553 | 554 | depthMovement(x, y, s) { 555 | return `rotateX(${-y}deg) rotateY(${x}deg) translate3d(0,0,${s * 2}px)`; 556 | }, 557 | 558 | scaleMovement(x, y) { 559 | const { 560 | type 561 | } = this; 562 | const movement = Math.sign(this.strength) * (Math.abs(x) + Math.abs(y)) / 10 + 1; 563 | return `scale3d(${type === 'scaleX' || type === 'scale' ? movement : 1}, 564 | ${type === 'scaleY' || type === 'scale' ? movement : 1}, 565 | 1)`; 566 | } 567 | 568 | } 569 | }; 570 | 571 | function cyclicMovement (cycleData) { 572 | const { 573 | referencePosition, 574 | shape, 575 | event, 576 | cycles, 577 | strength 578 | } = cycleData; 579 | const spanningRangeX = event === 'scroll' ? window.innerWidth : shape.width; 580 | const spanningRangeY = event === 'scroll' ? window.innerHeight : shape.height; 581 | const radialPositionX = (referencePosition.x - shape.left) * (Math.PI * 2) / spanningRangeX; 582 | const radialPositionY = (referencePosition.y - shape.top) * (Math.PI * 2) / spanningRangeY; 583 | const cycleX = spanningRangeX * Math.sin(radialPositionX * cycles); 584 | const cycleY = spanningRangeY * Math.sin(radialPositionY * cycles); 585 | return getCoordinates(cycleX * strength / (spanningRangeX / 2), cycleY * strength / (spanningRangeY / 2)); 586 | } 587 | 588 | var script$3 = { 589 | name: 'KinesisElement', 590 | mixins: [transformMixin], 591 | props: { 592 | tag: { 593 | type: String, 594 | default: 'div' 595 | }, 596 | type: { 597 | type: String, 598 | default: 'translate' // translate, rotate, scale, scaleX, scaleY, depth, depth_inv, custom 599 | 600 | }, 601 | transformOrigin: { 602 | type: String, 603 | default: 'center' 604 | }, 605 | originX: { 606 | type: Number, 607 | default: 50 608 | }, 609 | originY: { 610 | type: Number, 611 | default: 50 612 | }, 613 | strength: { 614 | type: Number, 615 | default: 10 616 | }, 617 | axis: { 618 | type: String, 619 | default: null 620 | }, 621 | maxX: { 622 | type: Number, 623 | default: null 624 | }, 625 | maxY: { 626 | type: Number, 627 | default: null 628 | }, 629 | minX: { 630 | type: Number, 631 | default: null 632 | }, 633 | minY: { 634 | type: Number, 635 | default: null 636 | }, 637 | cycle: { 638 | type: Number, 639 | default: 0 640 | } 641 | }, 642 | inject: ['context'], 643 | computed: { 644 | transform() { 645 | return this.transformCalculation(); 646 | }, 647 | 648 | transformParameters() { 649 | return { 650 | transitionProperty: 'transform', 651 | transitionDuration: this.transitionDuration, 652 | transformOrigin: this.transformOrigin, 653 | transitionTimingFunction: this.transitionTimingFunction 654 | }; 655 | }, 656 | 657 | transitionDuration() { 658 | const { 659 | duration 660 | } = this.context; 661 | return `${duration}ms`; 662 | }, 663 | 664 | transitionTimingFunction() { 665 | return this.context.easing; 666 | } 667 | 668 | }, 669 | methods: { 670 | transformCalculation() { 671 | const { 672 | context 673 | } = this; 674 | if (!context.shape || !context.isMoving && context.event === 'move') return {}; 675 | let movementX; 676 | let movementY; 677 | const { 678 | x, 679 | y 680 | } = this.cycle < 1 ? elementMovement({ ...context.movement, 681 | originX: this.originX, 682 | originY: this.originY, 683 | strength: this.strengthManager(), 684 | event: context.event, 685 | minX: this.minX, 686 | minY: this.minY, 687 | maxX: this.maxX, 688 | maxY: this.maxY 689 | }) : cyclicMovement({ 690 | referencePosition: context.event === 'scroll' ? { 691 | x: 0, 692 | y: 0 693 | } : context.eventData, 694 | shape: context.shape, 695 | event: context.event, 696 | cycles: this.cycle, 697 | strength: this.strengthManager() 698 | }); 699 | 700 | if (context.event !== 'scroll') { 701 | movementX = this.axis === 'y' ? 0 : x; 702 | movementY = this.axis === 'x' ? 0 : y; 703 | } else if (context.event === 'scroll') { 704 | movementX = this.axis === 'x' ? y : 0; 705 | movementY = this.axis === 'y' || !this.axis ? y : 0; 706 | } else if (this.cycle > 0) { 707 | movementX = this.axis === 'x' ? x : 0; 708 | movementY = this.axis === 'y' ? y : 0; 709 | } 710 | 711 | return { 712 | transform: this.transformSwitch(this.type, movementX, movementY, this.strength) 713 | }; 714 | }, 715 | 716 | strengthManager() { 717 | return this.type === 'depth' || this.type === 'depth_inv' ? Math.abs(this.strength) : this.strength; 718 | } 719 | 720 | }, 721 | 722 | render(createElement) { 723 | const context = this; 724 | return createElement(context.tag, { 725 | style: { ...context.transform, 726 | ...context.transformParameters 727 | } 728 | }, context.$slots.default); 729 | } 730 | 731 | }; 732 | 733 | /* script */ 734 | const __vue_script__$3 = script$3; 735 | /* template */ 736 | 737 | /* style */ 738 | 739 | const __vue_inject_styles__$3 = undefined; 740 | /* scoped */ 741 | 742 | const __vue_scope_id__$3 = undefined; 743 | /* module identifier */ 744 | 745 | const __vue_module_identifier__$3 = undefined; 746 | /* functional template */ 747 | 748 | const __vue_is_functional_template__$3 = undefined; 749 | /* style inject */ 750 | 751 | /* style inject SSR */ 752 | 753 | /* style inject shadow dom */ 754 | 755 | const __vue_component__$3 = /*#__PURE__*/normalizeComponent({}, __vue_inject_styles__$3, __vue_script__$3, __vue_scope_id__$3, __vue_is_functional_template__$3, __vue_module_identifier__$3, false, undefined, undefined, undefined); 756 | 757 | var motionMixin = { 758 | props: { 759 | type: { 760 | type: String, 761 | default: 'translate' // translate, rotate, scale, scaleX, scaleY, depth, depth_inv, custom 762 | 763 | }, 764 | transformOrigin: { 765 | type: String, 766 | default: 'center' 767 | }, 768 | originX: { 769 | type: Number, 770 | default: 50 771 | }, 772 | originY: { 773 | type: Number, 774 | default: 50 775 | }, 776 | strength: { 777 | type: Number, 778 | default: 10 779 | }, 780 | audioIndex: { 781 | type: Number, 782 | default: 50 783 | }, 784 | axis: { 785 | type: String, 786 | default: null 787 | }, 788 | maxX: { 789 | type: Number, 790 | default: null 791 | }, 792 | maxY: { 793 | type: Number, 794 | default: null 795 | }, 796 | minX: { 797 | type: Number, 798 | default: null 799 | }, 800 | minY: { 801 | type: Number, 802 | default: null 803 | }, 804 | cycle: { 805 | type: Number, 806 | default: 0 807 | } 808 | }, 809 | methods: { 810 | strengthManager() { 811 | return this.type === 'depth' || this.type === 'depth_inv' ? Math.abs(this.strength) : this.strength; 812 | } 813 | 814 | } 815 | }; 816 | 817 | // 818 | var script$2 = { 819 | name: 'KinesisAudio', 820 | inject: ['context'], 821 | mixins: [motionMixin], 822 | props: { 823 | tag: { 824 | type: String, 825 | default: 'div' 826 | }, 827 | audioIndex: { 828 | type: Number, 829 | default: 50 830 | } 831 | }, 832 | computed: { 833 | transform() { 834 | return this.transformAudio(); 835 | }, 836 | 837 | transformParameters() { 838 | return { 839 | transitionProperty: 'transform', 840 | transitionDuration: this.transitionDuration, 841 | transformOrigin: this.transformOrigin, 842 | transitionTimingFunction: this.transitionTimingFunction 843 | }; 844 | }, 845 | 846 | transitionDuration() { 847 | const { 848 | duration 849 | } = this.context; 850 | return `${duration}ms`; 851 | }, 852 | 853 | transitionTimingFunction() { 854 | return this.context.easing; 855 | } 856 | 857 | }, 858 | methods: { 859 | transformAudio() { 860 | const { 861 | audioData 862 | } = this.context; 863 | if (!audioData) return; 864 | const transformType = this.type; 865 | const { 866 | strength 867 | } = this; 868 | let amplitude; 869 | let transform; // eslint-disable-next-line default-case 870 | 871 | switch (transformType) { 872 | case 'translate': 873 | amplitude = audioData ? audioData[0][this.audioIndex] : 0; 874 | transform = `translate3d(${amplitude * strength}px, 0, 0)`; 875 | break; 876 | 877 | case 'rotate': 878 | amplitude = audioData ? audioData[0][this.audioIndex] : 0; 879 | transform = `rotate3d(0,0,1,${amplitude * strength / 10}deg)`; 880 | break; 881 | 882 | case 'scale': 883 | // eslint-disable-next-line no-nested-ternary 884 | amplitude = audioData ? audioData[0][this.audioIndex] / strength < 1 ? 1 : audioData[0][this.audioIndex] / (strength * 2) : 1; 885 | transform = `scale(${amplitude})`; 886 | break; 887 | } // eslint-disable-next-line consistent-return 888 | 889 | 890 | return { 891 | transform 892 | }; 893 | } 894 | 895 | } 896 | }; 897 | 898 | /* script */ 899 | const __vue_script__$2 = script$2; 900 | /* template */ 901 | 902 | var __vue_render__$2 = function () { 903 | var _vm = this; 904 | 905 | var _h = _vm.$createElement; 906 | 907 | var _c = _vm._self._c || _h; 908 | 909 | return _c(_vm.tag, { 910 | tag: "component", 911 | style: Object.assign({}, _vm.transform, _vm.transformParameters) 912 | }, [_vm._t("default")], 2); 913 | }; 914 | 915 | var __vue_staticRenderFns__$2 = []; 916 | /* style */ 917 | 918 | const __vue_inject_styles__$2 = undefined; 919 | /* scoped */ 920 | 921 | const __vue_scope_id__$2 = undefined; 922 | /* module identifier */ 923 | 924 | const __vue_module_identifier__$2 = undefined; 925 | /* functional template */ 926 | 927 | const __vue_is_functional_template__$2 = false; 928 | /* style inject */ 929 | 930 | /* style inject SSR */ 931 | 932 | /* style inject shadow dom */ 933 | 934 | const __vue_component__$2 = /*#__PURE__*/normalizeComponent({ 935 | render: __vue_render__$2, 936 | staticRenderFns: __vue_staticRenderFns__$2 937 | }, __vue_inject_styles__$2, __vue_script__$2, __vue_scope_id__$2, __vue_is_functional_template__$2, __vue_module_identifier__$2, false, undefined, undefined, undefined); 938 | 939 | var baseMixin = { 940 | props: { 941 | active: { 942 | type: Boolean, 943 | default: true 944 | }, 945 | duration: { 946 | type: Number, 947 | default: 1000 948 | }, 949 | easing: { 950 | type: String, 951 | default: 'cubic-bezier(0.23, 1, 0.32, 1)' 952 | }, 953 | tag: { 954 | type: String, 955 | default: 'div' 956 | } 957 | } 958 | }; 959 | 960 | var perspectiveMixin = { 961 | props: { 962 | perspective: { 963 | type: Number, 964 | default: 1000 965 | } 966 | }, 967 | computed: { 968 | style() { 969 | return { 970 | perspective: `${this.perspective}px` 971 | }; 972 | } 973 | 974 | } 975 | }; 976 | 977 | // 978 | var script$1 = { 979 | name: 'KinesisScroll', 980 | mixins: [baseMixin, perspectiveMixin, motionMixin, transformMixin], 981 | 982 | data() { 983 | return { 984 | transform: {} 985 | }; 986 | }, 987 | 988 | computed: { 989 | transformParameters() { 990 | return { 991 | transitionProperty: 'transform', 992 | transitionDuration: this.transitionDuration, 993 | transformOrigin: this.transformOrigin, 994 | transitionTimingFunction: this.easing 995 | }; 996 | }, 997 | 998 | transitionDuration() { 999 | return `${this.duration}ms`; 1000 | } 1001 | 1002 | }, 1003 | 1004 | mounted() { 1005 | window.addEventListener('scroll', this.handleScroll, { 1006 | passive: true 1007 | }); 1008 | }, 1009 | 1010 | beforeDestroy() { 1011 | window.removeEventListener('scroll', this.handleScroll, { 1012 | passive: true 1013 | }); 1014 | }, 1015 | 1016 | methods: { 1017 | getCycleMovement(xPos, yPos, width, height, shape) { 1018 | const x = (xPos - shape.left) * (Math.PI * 2) / width; 1019 | const y = (yPos - shape.top) * (Math.PI * 2) / height; 1020 | this.cycleMovement = { 1021 | x, 1022 | y, 1023 | width, 1024 | height 1025 | }; 1026 | }, 1027 | 1028 | handleScroll: throttle( // eslint-disable-next-line func-names 1029 | function () { 1030 | if (!this.active) return; 1031 | const shape = this.$el.getBoundingClientRect(); 1032 | const isInViewport = inViewport(shape); 1033 | 1034 | if (isInViewport && !!shape.height) { 1035 | this.transformBehavior(shape); 1036 | } 1037 | }, 19, 'scroll'), 1038 | 1039 | transformBehavior(shape) { 1040 | let movementX; 1041 | let movementY; 1042 | const scrollPosition = (shape.top - window.innerHeight) / (shape.height + window.innerHeight); 1043 | 1044 | if (this.cycle <= 0) { 1045 | const scrollMovement = scrollPosition * this.strength; 1046 | movementX = this.axis === 'x' ? scrollMovement : 0; 1047 | movementY = this.axis === 'y' || !this.axis ? scrollMovement : 0; 1048 | 1049 | if (this.maxX) { 1050 | movementX = Math.min(movementX, this.maxX); 1051 | } 1052 | 1053 | if (this.minX) { 1054 | movementX = Math.max(movementX, this.minX); 1055 | } 1056 | 1057 | if (this.maxY) { 1058 | movementY = Math.min(movementY, this.maxY); 1059 | } 1060 | 1061 | if (this.minY) { 1062 | movementY = Math.max(movementY, this.minY); 1063 | } 1064 | } else if (this.cycle > 0) { 1065 | const { 1066 | x, 1067 | y, 1068 | width, 1069 | height 1070 | } = this.getCycleMovement(0, 0, window.innerWidth, window.innerHeight, shape); 1071 | const cycleX = width * Math.sin(x * this.cycle); 1072 | const cycleY = height * Math.sin(y * this.cycle); 1073 | movementX = this.axis === 'x' ? cycleX / (width / 2) * this.strength : 0; 1074 | movementY = this.axis === 'y' || !this.axis ? cycleY / (height / 2) * this.strength : 0; 1075 | } 1076 | 1077 | let transformType = this.type; 1078 | transformType = transformType === 'scaleX' || transformType === 'scaleY' ? 'scale' : transformType; 1079 | const transform = this.transformSwitch(transformType, movementX, movementY, this.strength); 1080 | this.transform = { 1081 | transform 1082 | }; 1083 | } 1084 | 1085 | } 1086 | }; 1087 | 1088 | /* script */ 1089 | const __vue_script__$1 = script$1; 1090 | /* template */ 1091 | 1092 | var __vue_render__$1 = function () { 1093 | var _vm = this; 1094 | 1095 | var _h = _vm.$createElement; 1096 | 1097 | var _c = _vm._self._c || _h; 1098 | 1099 | return _c(_vm.tag, { 1100 | tag: "component", 1101 | style: Object.assign({}, _vm.transform, _vm.transformParameters) 1102 | }, [_vm._t("default")], 2); 1103 | }; 1104 | 1105 | var __vue_staticRenderFns__$1 = []; 1106 | /* style */ 1107 | 1108 | const __vue_inject_styles__$1 = undefined; 1109 | /* scoped */ 1110 | 1111 | const __vue_scope_id__$1 = undefined; 1112 | /* module identifier */ 1113 | 1114 | const __vue_module_identifier__$1 = undefined; 1115 | /* functional template */ 1116 | 1117 | const __vue_is_functional_template__$1 = false; 1118 | /* style inject */ 1119 | 1120 | /* style inject SSR */ 1121 | 1122 | /* style inject shadow dom */ 1123 | 1124 | const __vue_component__$1 = /*#__PURE__*/normalizeComponent({ 1125 | render: __vue_render__$1, 1126 | staticRenderFns: __vue_staticRenderFns__$1 1127 | }, __vue_inject_styles__$1, __vue_script__$1, __vue_scope_id__$1, __vue_is_functional_template__$1, __vue_module_identifier__$1, false, undefined, undefined, undefined); 1128 | 1129 | // 1130 | var script = { 1131 | name: 'KinesisDistance', 1132 | props: { 1133 | tag: { 1134 | type: String, 1135 | default: 'div' 1136 | }, 1137 | type: { 1138 | type: String, 1139 | default: 'translate' // translate, rotate, scale, scaleX, scaleY, depth, custom 1140 | 1141 | }, 1142 | transformOrigin: { 1143 | type: String, 1144 | default: 'center' 1145 | }, 1146 | originX: { 1147 | type: Number, 1148 | default: 50 1149 | }, 1150 | originY: { 1151 | type: Number, 1152 | default: 50 1153 | }, 1154 | strength: { 1155 | type: Number, 1156 | default: 10 1157 | }, 1158 | axis: { 1159 | type: String, 1160 | default: null 1161 | }, 1162 | maxX: { 1163 | type: Number, 1164 | default: null 1165 | }, 1166 | maxY: { 1167 | type: Number, 1168 | default: null 1169 | }, 1170 | minX: { 1171 | type: Number, 1172 | default: null 1173 | }, 1174 | minY: { 1175 | type: Number, 1176 | default: null 1177 | }, 1178 | distance: { 1179 | type: Number, 1180 | default: 100 1181 | }, 1182 | cycle: { 1183 | type: Number, 1184 | default: 0 1185 | }, 1186 | active: { 1187 | type: Boolean, 1188 | default: true 1189 | }, 1190 | duration: { 1191 | type: Number, 1192 | default: 1001 1193 | }, 1194 | easing: { 1195 | type: String, 1196 | default: 'cubic-bezier(0.23, 1, 0.32, 1)' 1197 | }, 1198 | perspective: { 1199 | type: Number, 1200 | default: 1000 1201 | } 1202 | }, 1203 | 1204 | data() { 1205 | return { 1206 | pointer: { 1207 | x: 0, 1208 | y: 0 1209 | }, 1210 | transform: {}, 1211 | component: 'kidistance', 1212 | throttle: 500 1213 | }; 1214 | }, 1215 | 1216 | computed: { 1217 | style() { 1218 | return { 1219 | perspective: `${this.perspective}px` 1220 | }; 1221 | }, 1222 | 1223 | transformParameters() { 1224 | return { 1225 | position: 'relative', 1226 | transitionProperty: 'transform', 1227 | transitionDuration: this.transitionDuration, 1228 | transformOrigin: this.transformOrigin, 1229 | transitionTimingFunction: this.easing 1230 | }; 1231 | }, 1232 | 1233 | transitionDuration() { 1234 | return `${this.duration}ms`; 1235 | } 1236 | 1237 | }, 1238 | 1239 | mounted() { 1240 | window.addEventListener('scroll', this.handleMovement); 1241 | }, 1242 | 1243 | beforeDestroy() { 1244 | window.removeEventListener('scroll', this.handleMovement); 1245 | }, 1246 | 1247 | methods: { 1248 | getCoordinates(x, y) { 1249 | const shape = this.$el.getBoundingClientRect(); 1250 | return { 1251 | x: x + shape.left, 1252 | y: y + shape.top 1253 | }; 1254 | }, 1255 | 1256 | getDistance(x1, x2, y1, y2) { 1257 | return Math.floor(Math.hypot(x2 - x1, y2 - y1)); 1258 | }, 1259 | 1260 | // eslint-disable-next-line func-names 1261 | handleMovement: throttle(function (event) { 1262 | window.addEventListener('mousemove', this.handleMovement); 1263 | const { 1264 | pointer 1265 | } = this; 1266 | pointer.x = event.clientX; 1267 | pointer.y = event.clientY; 1268 | this.transformBehavior(); 1269 | }, 50), 1270 | 1271 | transformBehavior() { 1272 | const shape = this.$el.getBoundingClientRect(); 1273 | const center = this.getCoordinates(shape.width / 2, shape.height / 2); 1274 | const distance = this.getDistance(this.pointer.x, center.x, this.pointer.y, center.y); 1275 | 1276 | if (distance > this.distance) { 1277 | this.transform = {}; 1278 | this.throttle = 500; 1279 | return; 1280 | } 1281 | 1282 | this.throttle = 50; 1283 | const transform = `scale(${distance / this.distance})`; // Add radius from which the transfrom will start 1284 | 1285 | this.transform = { 1286 | transform 1287 | }; 1288 | }, 1289 | 1290 | scaleMovement(x, y) { 1291 | const { 1292 | type 1293 | } = this; 1294 | const movement = Math.sign(this.strength) * (Math.abs(x) + Math.abs(y)) / 10 + 1; 1295 | return `scale3d(${type === 'scaleX' || type === 'scale' ? movement : 1}, 1296 | ${type === 'scaleY' || type === 'scale' ? movement : 1}, 1297 | 1)`; 1298 | } 1299 | 1300 | } 1301 | }; 1302 | 1303 | /* script */ 1304 | const __vue_script__ = script; 1305 | /* template */ 1306 | 1307 | var __vue_render__ = function () { 1308 | var _vm = this; 1309 | 1310 | var _h = _vm.$createElement; 1311 | 1312 | var _c = _vm._self._c || _h; 1313 | 1314 | return _c(_vm.tag, { 1315 | tag: "component", 1316 | style: Object.assign({}, _vm.transform, _vm.transformParameters) 1317 | }, [_vm._t("default")], 2); 1318 | }; 1319 | 1320 | var __vue_staticRenderFns__ = []; 1321 | /* style */ 1322 | 1323 | const __vue_inject_styles__ = undefined; 1324 | /* scoped */ 1325 | 1326 | const __vue_scope_id__ = undefined; 1327 | /* module identifier */ 1328 | 1329 | const __vue_module_identifier__ = undefined; 1330 | /* functional template */ 1331 | 1332 | const __vue_is_functional_template__ = false; 1333 | /* style inject */ 1334 | 1335 | /* style inject SSR */ 1336 | 1337 | /* style inject shadow dom */ 1338 | 1339 | const __vue_component__ = /*#__PURE__*/normalizeComponent({ 1340 | render: __vue_render__, 1341 | staticRenderFns: __vue_staticRenderFns__ 1342 | }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, undefined, undefined, undefined); 1343 | 1344 | const Plugin$1 = { 1345 | install(vue) { 1346 | vue.component(__vue_component__$2.name, __vue_component__$2); 1347 | vue.component(__vue_component__$4.name, __vue_component__$4); 1348 | vue.component(__vue_component__.name, __vue_component__); 1349 | vue.component(__vue_component__$3.name, __vue_component__$3); 1350 | vue.component(__vue_component__$1.name, __vue_component__$1); 1351 | } 1352 | 1353 | }; 1354 | let GlobalVue$1 = null; 1355 | 1356 | if (typeof window !== 'undefined') { 1357 | GlobalVue$1 = window.vue; 1358 | } else if (typeof global !== 'undefined') { 1359 | GlobalVue$1 = global.vue; 1360 | } 1361 | 1362 | if (GlobalVue$1) { 1363 | GlobalVue$1.use(Plugin$1); 1364 | } 1365 | 1366 | var components = /*#__PURE__*/Object.freeze({ 1367 | __proto__: null, 1368 | 'default': Plugin$1, 1369 | KinesisAudio: __vue_component__$2, 1370 | KinesisContainer: __vue_component__$4, 1371 | KinesisDistance: __vue_component__, 1372 | KinesisElement: __vue_component__$3, 1373 | KinesisScroll: __vue_component__$1 1374 | }); 1375 | 1376 | /* eslint-disable */ 1377 | 1378 | const install = function (vue) { 1379 | if (install.installed) { 1380 | return; 1381 | } 1382 | 1383 | install.installed = true; 1384 | 1385 | for (const name in components) { 1386 | vue.use(components[name]); 1387 | } 1388 | 1389 | vue.component('kinesis-container', __vue_component__$4); 1390 | vue.component('kinesis-element', __vue_component__$3); 1391 | vue.component('kinesis-audio', __vue_component__$2); 1392 | vue.component('kinesis-scroll', __vue_component__$1); 1393 | vue.component('kinesis-distance', __vue_component__); 1394 | }; 1395 | 1396 | const Plugin = { 1397 | install 1398 | }; 1399 | let GlobalVue = null; 1400 | 1401 | if (typeof window !== 'undefined') { 1402 | GlobalVue = window.vue; 1403 | } else if (typeof global !== 'undefined') { 1404 | GlobalVue = global.vue; 1405 | } 1406 | 1407 | if (GlobalVue) { 1408 | GlobalVue.use(Plugin); 1409 | } 1410 | 1411 | export default Plugin; 1412 | export { __vue_component__$2 as KinesisAudio, __vue_component__$4 as KinesisContainer, __vue_component__ as KinesisDistance, __vue_component__$3 as KinesisElement, __vue_component__$1 as KinesisScroll }; 1413 | -------------------------------------------------------------------------------- /dist/vue-kinesis.ssr.js: -------------------------------------------------------------------------------- 1 | 'use strict';Object.defineProperty(exports,'__esModule',{value:true});function ownKeys(object, enumerableOnly) { 2 | var keys = Object.keys(object); 3 | 4 | if (Object.getOwnPropertySymbols) { 5 | var symbols = Object.getOwnPropertySymbols(object); 6 | 7 | if (enumerableOnly) { 8 | symbols = symbols.filter(function (sym) { 9 | return Object.getOwnPropertyDescriptor(object, sym).enumerable; 10 | }); 11 | } 12 | 13 | keys.push.apply(keys, symbols); 14 | } 15 | 16 | return keys; 17 | } 18 | 19 | function _objectSpread2(target) { 20 | for (var i = 1; i < arguments.length; i++) { 21 | var source = arguments[i] != null ? arguments[i] : {}; 22 | 23 | if (i % 2) { 24 | ownKeys(Object(source), true).forEach(function (key) { 25 | _defineProperty(target, key, source[key]); 26 | }); 27 | } else if (Object.getOwnPropertyDescriptors) { 28 | Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); 29 | } else { 30 | ownKeys(Object(source)).forEach(function (key) { 31 | Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); 32 | }); 33 | } 34 | } 35 | 36 | return target; 37 | } 38 | 39 | function _defineProperty(obj, key, value) { 40 | if (key in obj) { 41 | Object.defineProperty(obj, key, { 42 | value: value, 43 | enumerable: true, 44 | configurable: true, 45 | writable: true 46 | }); 47 | } else { 48 | obj[key] = value; 49 | } 50 | 51 | return obj; 52 | }function getCoordinates (x, y) { 53 | return { 54 | x: x, 55 | y: y 56 | }; 57 | }function getCenter (element) { 58 | return getCoordinates(element ? element.width / 2 : 0, element ? element.height / 2 : 0); 59 | }function mouseMovement (action) { 60 | var target = action.target, 61 | event = action.event; 62 | var x = event.clientX; 63 | var y = event.clientY; 64 | var relativeX = x - target.left; 65 | var relativeY = y - target.top; 66 | var center = getCenter(target); 67 | var mouseMovementX = relativeX / center.x; 68 | var mouseMovementY = relativeY / center.y; 69 | return _objectSpread2(_objectSpread2({}, getCoordinates(mouseMovementX, mouseMovementY)), {}, { 70 | target: target 71 | }); 72 | }function scrollMovement (shape) { 73 | var target = shape.target; 74 | var x = (target.left - window.innerWidth) / (target.width + window.innerWidth); 75 | var y = (target.top - window.innerHeight) / (target.height + window.innerHeight); 76 | return _objectSpread2(_objectSpread2({}, getCoordinates(x, y)), {}, { 77 | target: target 78 | }); 79 | }function orientationElement (action) { 80 | var event = action.event, 81 | target = action.target; 82 | var x = event.gamma / 45; 83 | var y = event.beta / 90; 84 | return _objectSpread2(_objectSpread2({}, getCoordinates(x, y)), {}, { 85 | target: target 86 | }); 87 | }function inViewport(element) { 88 | var isInViewport = element.bottom >= 0 && element.right >= 0 && element.top <= (window.innerHeight || document.documentElement.clientHeight) && element.left <= (window.innerWidth || document.documentElement.clientWidth); 89 | return isInViewport; 90 | }function isTouch() { 91 | try { 92 | return /Mobi|Android/i.test(navigator.userAgent); 93 | } catch (e) { 94 | return true; 95 | } 96 | }function throttle(callback, delay, type) { 97 | var last; 98 | var timer; // eslint-disable-next-line func-names 99 | 100 | return function () { 101 | var context = this; 102 | var newDelay; 103 | 104 | if (type === 'scroll') { 105 | newDelay = delay; 106 | } else { 107 | newDelay = context.duration > 1000 ? delay : context.duration / 10; 108 | } 109 | 110 | var now = +new Date(); // eslint-disable-next-line prefer-rest-params 111 | 112 | var args = arguments; 113 | 114 | if (last && now < last + newDelay) { 115 | clearTimeout(timer); 116 | timer = setTimeout(function () { 117 | requestAnimationFrame(function () { 118 | last = now; 119 | callback.apply(context, args); 120 | }); 121 | }, newDelay); 122 | } else { 123 | requestAnimationFrame(function () { 124 | last = now; 125 | callback.apply(context, args); 126 | }); 127 | } 128 | }; 129 | }var audioMixin = { 130 | props: { 131 | audio: { 132 | type: String, 133 | required: false 134 | }, 135 | playAudio: { 136 | type: Boolean, 137 | default: false 138 | } 139 | }, 140 | data: function data() { 141 | return { 142 | analyser: null, 143 | audioArray: null, 144 | audioData: null, 145 | audioRef: null, 146 | wasPlayed: false, 147 | isPlaying: false 148 | }; 149 | }, 150 | watch: { 151 | audio: function audio() { 152 | this.wasPlayed = false; 153 | this.isPlaying = false; 154 | }, 155 | playAudio: function playAudio(play) { 156 | if (play) { 157 | this.play(); 158 | } else { 159 | this.stop(); 160 | } 161 | } 162 | }, 163 | methods: { 164 | play: function play() { 165 | if (!this.active) return; 166 | 167 | if (!this.wasPlayed) { 168 | this.handleAudio(); 169 | this.wasPlayed = true; 170 | } 171 | 172 | this.isPlaying = true; 173 | this.audioRef.play(); 174 | this.getSongData(); 175 | }, 176 | stop: function stop() { 177 | this.isPlaying = false; 178 | this.audioRef.pause(); 179 | }, 180 | handleAudio: function handleAudio() { 181 | var audio = this.$refs.audio; 182 | this.audioRef = audio; 183 | var context = new AudioContext(); 184 | var src = context.createMediaElementSource(audio); 185 | var analyser = context.createAnalyser(); 186 | src.connect(analyser); 187 | analyser.connect(context.destination); 188 | analyser.fftSize = 256; 189 | var bufferLength = analyser.frequencyBinCount; 190 | var audioArray = new Uint8Array(bufferLength); 191 | this.audioArray = audioArray; 192 | this.analyser = analyser; 193 | }, 194 | getSongData: function getSongData() { 195 | if (this.isPlaying) { 196 | this.analyser.getByteFrequencyData(this.audioArray); 197 | this.audioData = new Array(this.audioArray); // @Todo reactivity issue 198 | 199 | requestAnimationFrame(this.getSongData); 200 | } 201 | } 202 | } 203 | };// 204 | var script$4 = { 205 | name: 'KinesisContainer', 206 | mixins: [audioMixin], 207 | props: { 208 | tag: { 209 | type: String, 210 | default: 'div' 211 | }, 212 | event: { 213 | type: String, 214 | default: 'move' 215 | }, 216 | active: { 217 | type: Boolean, 218 | default: true 219 | }, 220 | duration: { 221 | type: Number, 222 | default: 1000 223 | }, 224 | easing: { 225 | type: String, 226 | default: 'cubic-bezier(0.23, 1, 0.32, 1)' 227 | }, 228 | perspective: { 229 | type: Number, 230 | default: 1000 231 | } 232 | }, 233 | provide: function provide() { 234 | var _this = this; 235 | 236 | var context = {}; 237 | var providedProps = ['audioData', 'duration', 'easing', 'event', 'eventData', 'isMoving', 'movement', 'shape']; 238 | providedProps.forEach(function (prop) { 239 | return Object.defineProperty(context, prop, { 240 | enumerable: true, 241 | get: function get() { 242 | return _this[prop]; 243 | } 244 | }); 245 | }); 246 | return { 247 | context: context 248 | }; 249 | }, 250 | data: function data() { 251 | var _this$$el; 252 | 253 | return { 254 | shape: (_this$$el = this.$el) === null || _this$$el === void 0 ? void 0 : _this$$el.getBoundingClientRect(), 255 | isMoving: false, 256 | leftOnce: false, 257 | movement: { 258 | x: 0, 259 | y: 0 260 | }, 261 | eventMap: { 262 | orientation: 'deviceorientation', 263 | scroll: 'scroll', 264 | move: isTouch() ? 'deviceorientation' : null 265 | } 266 | }; 267 | }, 268 | computed: { 269 | eventActions: function eventActions() { 270 | var _this$shape; 271 | 272 | return { 273 | move: { 274 | action: mouseMovement, 275 | condition: this.isMoving && !isTouch(), 276 | type: isTouch() ? 'deviceorientation' : null 277 | }, 278 | scroll: { 279 | action: scrollMovement, 280 | condition: !!((_this$shape = this.shape) !== null && _this$shape !== void 0 && _this$shape.height), 281 | type: 'scroll' 282 | }, 283 | orientation: { 284 | action: orientationElement, 285 | condition: this.event === 'move' && isTouch(), 286 | type: 'deviceorientation' 287 | } 288 | }; 289 | }, 290 | style: function style() { 291 | return { 292 | perspective: "".concat(this.perspective, "px") 293 | }; 294 | } 295 | }, 296 | mounted: function mounted() { 297 | this.addEvents(); 298 | }, 299 | beforeDestroy: function beforeDestroy() { 300 | this.removeEvents(); 301 | }, 302 | methods: { 303 | handleMovementStart: function handleMovementStart() { 304 | if (!this.active) return; 305 | this.isMoving = true; 306 | }, 307 | handleMovementStop: function handleMovementStop() { 308 | if (!this.active) return; // fixes the specific case when mouseenter didn't trigger on page refresh 309 | 310 | this.leftOnce = true; 311 | this.isMoving = false; 312 | }, 313 | // eslint-disable-next-line func-names 314 | handleMovement: throttle(function (event) { 315 | if (!this.active) return; 316 | 317 | if (!this.isMoving && !this.leftOnce) { 318 | // fixes the specific case when mouseenter didn't trigger on page refresh 319 | this.handleMovementStart(); 320 | } 321 | 322 | this.shape = this.$el.getBoundingClientRect(); 323 | var isInViewport = inViewport(this.shape); 324 | var eventCondition = this.eventActions[this.event].condition; 325 | var eventAction = this.eventActions[this.event].action; 326 | 327 | if (isInViewport && eventCondition) { 328 | this.movement = eventAction({ 329 | target: this.shape, 330 | event: event 331 | }); 332 | this.eventData = getCoordinates(event.clientX, event.clientY); 333 | } 334 | }, 100), 335 | addEvents: function addEvents() { 336 | if (this.eventMap[this.event]) { 337 | window.addEventListener(this.eventMap[this.event], this.handleMovement, true); 338 | } 339 | }, 340 | removeEvents: function removeEvents() { 341 | if (this.eventMap[this.event]) { 342 | window.removeEventListener(this.eventMap[this.event], this.handleMovement, true); 343 | } 344 | } 345 | } 346 | };function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { 347 | if (typeof shadowMode !== 'boolean') { 348 | createInjectorSSR = createInjector; 349 | createInjector = shadowMode; 350 | shadowMode = false; 351 | } 352 | // Vue.extend constructor export interop. 353 | const options = typeof script === 'function' ? script.options : script; 354 | // render functions 355 | if (template && template.render) { 356 | options.render = template.render; 357 | options.staticRenderFns = template.staticRenderFns; 358 | options._compiled = true; 359 | // functional template 360 | if (isFunctionalTemplate) { 361 | options.functional = true; 362 | } 363 | } 364 | // scopedId 365 | if (scopeId) { 366 | options._scopeId = scopeId; 367 | } 368 | let hook; 369 | if (moduleIdentifier) { 370 | // server build 371 | hook = function (context) { 372 | // 2.3 injection 373 | context = 374 | context || // cached call 375 | (this.$vnode && this.$vnode.ssrContext) || // stateful 376 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional 377 | // 2.2 with runInNewContext: true 378 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { 379 | context = __VUE_SSR_CONTEXT__; 380 | } 381 | // inject component styles 382 | if (style) { 383 | style.call(this, createInjectorSSR(context)); 384 | } 385 | // register component module identifier for async chunk inference 386 | if (context && context._registeredComponents) { 387 | context._registeredComponents.add(moduleIdentifier); 388 | } 389 | }; 390 | // used by ssr in case component is cached and beforeCreate 391 | // never gets called 392 | options._ssrRegister = hook; 393 | } 394 | else if (style) { 395 | hook = shadowMode 396 | ? function (context) { 397 | style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); 398 | } 399 | : function (context) { 400 | style.call(this, createInjector(context)); 401 | }; 402 | } 403 | if (hook) { 404 | if (options.functional) { 405 | // register for functional component in vue file 406 | const originalRender = options.render; 407 | options.render = function renderWithStyleInjection(h, context) { 408 | hook.call(context); 409 | return originalRender(h, context); 410 | }; 411 | } 412 | else { 413 | // inject component registration as beforeCreate hook 414 | const existing = options.beforeCreate; 415 | options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; 416 | } 417 | } 418 | return script; 419 | }/* script */ 420 | var __vue_script__$4 = script$4; 421 | /* template */ 422 | 423 | var __vue_render__$3 = function __vue_render__() { 424 | var _vm = this; 425 | 426 | var _h = _vm.$createElement; 427 | 428 | var _c = _vm._self._c || _h; 429 | 430 | return _c(_vm.tag, { 431 | tag: "component", 432 | style: _vm.style, 433 | on: { 434 | "mousemove": _vm.handleMovement, 435 | "mouseenter": _vm.handleMovementStart, 436 | "mouseleave": _vm.handleMovementStop 437 | } 438 | }, [_vm._t("default"), _vm._v(" "), _vm.audio ? _c('audio', { 439 | ref: "audio", 440 | attrs: { 441 | "type": "audio/mpeg" 442 | }, 443 | on: { 444 | "ended": _vm.stop 445 | } 446 | }, [_c('source', { 447 | attrs: { 448 | "src": _vm.audio 449 | } 450 | })]) : _vm._e()], 2); 451 | }; 452 | 453 | var __vue_staticRenderFns__$3 = []; 454 | /* style */ 455 | 456 | var __vue_inject_styles__$4 = undefined; 457 | /* scoped */ 458 | 459 | var __vue_scope_id__$4 = undefined; 460 | /* module identifier */ 461 | 462 | var __vue_module_identifier__$4 = "data-v-5b4afee6"; 463 | /* functional template */ 464 | 465 | var __vue_is_functional_template__$4 = false; 466 | /* style inject */ 467 | 468 | /* style inject SSR */ 469 | 470 | /* style inject shadow dom */ 471 | 472 | var __vue_component__$4 = /*#__PURE__*/normalizeComponent({ 473 | render: __vue_render__$3, 474 | staticRenderFns: __vue_staticRenderFns__$3 475 | }, __vue_inject_styles__$4, __vue_script__$4, __vue_scope_id__$4, __vue_is_functional_template__$4, __vue_module_identifier__$4, false, undefined, undefined, undefined);/* eslint-disable no-nested-ternary */ 476 | function clamp (value, min, max) { 477 | return max && value > max ? max : min && value < min ? min : value; 478 | }function elementMovement (action) { 479 | var y = action.y, 480 | x = action.x, 481 | target = action.target, 482 | _action$originX = action.originX, 483 | originX = _action$originX === void 0 ? 50 : _action$originX, 484 | _action$strength = action.strength, 485 | strength = _action$strength === void 0 ? 10 : _action$strength, 486 | _action$event = action.event, 487 | event = _action$event === void 0 ? null : _action$event, 488 | minX = action.minX, 489 | minY = action.minY, 490 | maxX = action.maxX, 491 | maxY = action.maxY; 492 | var _action$originY = action.originY, 493 | originY = _action$originY === void 0 ? 50 : _action$originY; 494 | 495 | if (event === 'scroll') { 496 | originY = -originY / 2; 497 | } 498 | 499 | var movementX = clamp((x - originX / 50) * strength, minX, maxX); 500 | var movementY = clamp((y - originY / 50) * strength, minY, maxY); 501 | return _objectSpread2(_objectSpread2({}, getCoordinates(movementX, movementY)), {}, { 502 | target: target 503 | }); 504 | }/* eslint-disable default-case */ 505 | var transformMixin = { 506 | methods: { 507 | transformSwitch: function transformSwitch(type, x, y, s) { 508 | type = type === 'scaleX' || type === 'scaleY' ? 'scale' : type; 509 | var transform; 510 | 511 | switch (type) { 512 | case 'translate': 513 | transform = this.translateMovement(x, y); 514 | break; 515 | 516 | case 'rotate': 517 | transform = this.rotateMovement(x, y); 518 | break; 519 | 520 | case 'depth': 521 | transform = this.depthMovement(x, y, s); 522 | break; 523 | 524 | case 'depth_inv': 525 | transform = this.depthMovement(-x, -y, s); 526 | break; 527 | 528 | case 'scale': 529 | transform = this.scaleMovement(x, y); 530 | break; 531 | } 532 | 533 | return transform; 534 | }, 535 | translateMovement: function translateMovement(x, y) { 536 | return "translate3d(".concat(-x, "px, ").concat(-y, "px, 0)"); 537 | }, 538 | rotateMovement: function rotateMovement(x, y) { 539 | var movement; 540 | 541 | if (!this.axis) { 542 | movement = x + y; 543 | } else if (this.axis === 'x') { 544 | movement = 2 * x; 545 | } else if (this.axis === 'y') { 546 | movement = 2 * y; 547 | } 548 | 549 | return "rotate3d(0,0,1,".concat(movement, "deg)"); 550 | }, 551 | depthMovement: function depthMovement(x, y, s) { 552 | return "rotateX(".concat(-y, "deg) rotateY(").concat(x, "deg) translate3d(0,0,").concat(s * 2, "px)"); 553 | }, 554 | scaleMovement: function scaleMovement(x, y) { 555 | var type = this.type; 556 | var movement = Math.sign(this.strength) * (Math.abs(x) + Math.abs(y)) / 10 + 1; 557 | return "scale3d(".concat(type === 'scaleX' || type === 'scale' ? movement : 1, ",\n ").concat(type === 'scaleY' || type === 'scale' ? movement : 1, ",\n 1)"); 558 | } 559 | } 560 | };function cyclicMovement (cycleData) { 561 | var referencePosition = cycleData.referencePosition, 562 | shape = cycleData.shape, 563 | event = cycleData.event, 564 | cycles = cycleData.cycles, 565 | strength = cycleData.strength; 566 | var spanningRangeX = event === 'scroll' ? window.innerWidth : shape.width; 567 | var spanningRangeY = event === 'scroll' ? window.innerHeight : shape.height; 568 | var radialPositionX = (referencePosition.x - shape.left) * (Math.PI * 2) / spanningRangeX; 569 | var radialPositionY = (referencePosition.y - shape.top) * (Math.PI * 2) / spanningRangeY; 570 | var cycleX = spanningRangeX * Math.sin(radialPositionX * cycles); 571 | var cycleY = spanningRangeY * Math.sin(radialPositionY * cycles); 572 | return getCoordinates(cycleX * strength / (spanningRangeX / 2), cycleY * strength / (spanningRangeY / 2)); 573 | }var script$3 = { 574 | name: 'KinesisElement', 575 | mixins: [transformMixin], 576 | props: { 577 | tag: { 578 | type: String, 579 | default: 'div' 580 | }, 581 | type: { 582 | type: String, 583 | default: 'translate' // translate, rotate, scale, scaleX, scaleY, depth, depth_inv, custom 584 | 585 | }, 586 | transformOrigin: { 587 | type: String, 588 | default: 'center' 589 | }, 590 | originX: { 591 | type: Number, 592 | default: 50 593 | }, 594 | originY: { 595 | type: Number, 596 | default: 50 597 | }, 598 | strength: { 599 | type: Number, 600 | default: 10 601 | }, 602 | axis: { 603 | type: String, 604 | default: null 605 | }, 606 | maxX: { 607 | type: Number, 608 | default: null 609 | }, 610 | maxY: { 611 | type: Number, 612 | default: null 613 | }, 614 | minX: { 615 | type: Number, 616 | default: null 617 | }, 618 | minY: { 619 | type: Number, 620 | default: null 621 | }, 622 | cycle: { 623 | type: Number, 624 | default: 0 625 | } 626 | }, 627 | inject: ['context'], 628 | computed: { 629 | transform: function transform() { 630 | return this.transformCalculation(); 631 | }, 632 | transformParameters: function transformParameters() { 633 | return { 634 | transitionProperty: 'transform', 635 | transitionDuration: this.transitionDuration, 636 | transformOrigin: this.transformOrigin, 637 | transitionTimingFunction: this.transitionTimingFunction 638 | }; 639 | }, 640 | transitionDuration: function transitionDuration() { 641 | var duration = this.context.duration; 642 | return "".concat(duration, "ms"); 643 | }, 644 | transitionTimingFunction: function transitionTimingFunction() { 645 | return this.context.easing; 646 | } 647 | }, 648 | methods: { 649 | transformCalculation: function transformCalculation() { 650 | var context = this.context; 651 | if (!context.shape || !context.isMoving && context.event === 'move') return {}; 652 | var movementX; 653 | var movementY; 654 | 655 | var _ref = this.cycle < 1 ? elementMovement(_objectSpread2(_objectSpread2({}, context.movement), {}, { 656 | originX: this.originX, 657 | originY: this.originY, 658 | strength: this.strengthManager(), 659 | event: context.event, 660 | minX: this.minX, 661 | minY: this.minY, 662 | maxX: this.maxX, 663 | maxY: this.maxY 664 | })) : cyclicMovement({ 665 | referencePosition: context.event === 'scroll' ? { 666 | x: 0, 667 | y: 0 668 | } : context.eventData, 669 | shape: context.shape, 670 | event: context.event, 671 | cycles: this.cycle, 672 | strength: this.strengthManager() 673 | }), 674 | x = _ref.x, 675 | y = _ref.y; 676 | 677 | if (context.event !== 'scroll') { 678 | movementX = this.axis === 'y' ? 0 : x; 679 | movementY = this.axis === 'x' ? 0 : y; 680 | } else if (context.event === 'scroll') { 681 | movementX = this.axis === 'x' ? y : 0; 682 | movementY = this.axis === 'y' || !this.axis ? y : 0; 683 | } else if (this.cycle > 0) { 684 | movementX = this.axis === 'x' ? x : 0; 685 | movementY = this.axis === 'y' ? y : 0; 686 | } 687 | 688 | return { 689 | transform: this.transformSwitch(this.type, movementX, movementY, this.strength) 690 | }; 691 | }, 692 | strengthManager: function strengthManager() { 693 | return this.type === 'depth' || this.type === 'depth_inv' ? Math.abs(this.strength) : this.strength; 694 | } 695 | }, 696 | render: function render(createElement) { 697 | var context = this; 698 | return createElement(context.tag, { 699 | style: _objectSpread2(_objectSpread2({}, context.transform), context.transformParameters) 700 | }, context.$slots.default); 701 | } 702 | };/* script */ 703 | var __vue_script__$3 = script$3; 704 | /* template */ 705 | 706 | /* style */ 707 | 708 | var __vue_inject_styles__$3 = undefined; 709 | /* scoped */ 710 | 711 | var __vue_scope_id__$3 = undefined; 712 | /* module identifier */ 713 | 714 | var __vue_module_identifier__$3 = "data-v-2ae8e75a"; 715 | /* functional template */ 716 | 717 | var __vue_is_functional_template__$3 = undefined; 718 | /* style inject */ 719 | 720 | /* style inject SSR */ 721 | 722 | /* style inject shadow dom */ 723 | 724 | var __vue_component__$3 = /*#__PURE__*/normalizeComponent({}, __vue_inject_styles__$3, __vue_script__$3, __vue_scope_id__$3, __vue_is_functional_template__$3, __vue_module_identifier__$3, false, undefined, undefined, undefined);var motionMixin = { 725 | props: { 726 | type: { 727 | type: String, 728 | default: 'translate' // translate, rotate, scale, scaleX, scaleY, depth, depth_inv, custom 729 | 730 | }, 731 | transformOrigin: { 732 | type: String, 733 | default: 'center' 734 | }, 735 | originX: { 736 | type: Number, 737 | default: 50 738 | }, 739 | originY: { 740 | type: Number, 741 | default: 50 742 | }, 743 | strength: { 744 | type: Number, 745 | default: 10 746 | }, 747 | audioIndex: { 748 | type: Number, 749 | default: 50 750 | }, 751 | axis: { 752 | type: String, 753 | default: null 754 | }, 755 | maxX: { 756 | type: Number, 757 | default: null 758 | }, 759 | maxY: { 760 | type: Number, 761 | default: null 762 | }, 763 | minX: { 764 | type: Number, 765 | default: null 766 | }, 767 | minY: { 768 | type: Number, 769 | default: null 770 | }, 771 | cycle: { 772 | type: Number, 773 | default: 0 774 | } 775 | }, 776 | methods: { 777 | strengthManager: function strengthManager() { 778 | return this.type === 'depth' || this.type === 'depth_inv' ? Math.abs(this.strength) : this.strength; 779 | } 780 | } 781 | };// 782 | var script$2 = { 783 | name: 'KinesisAudio', 784 | inject: ['context'], 785 | mixins: [motionMixin], 786 | props: { 787 | tag: { 788 | type: String, 789 | default: 'div' 790 | }, 791 | audioIndex: { 792 | type: Number, 793 | default: 50 794 | } 795 | }, 796 | computed: { 797 | transform: function transform() { 798 | return this.transformAudio(); 799 | }, 800 | transformParameters: function transformParameters() { 801 | return { 802 | transitionProperty: 'transform', 803 | transitionDuration: this.transitionDuration, 804 | transformOrigin: this.transformOrigin, 805 | transitionTimingFunction: this.transitionTimingFunction 806 | }; 807 | }, 808 | transitionDuration: function transitionDuration() { 809 | var duration = this.context.duration; 810 | return "".concat(duration, "ms"); 811 | }, 812 | transitionTimingFunction: function transitionTimingFunction() { 813 | return this.context.easing; 814 | } 815 | }, 816 | methods: { 817 | transformAudio: function transformAudio() { 818 | var audioData = this.context.audioData; 819 | if (!audioData) return; 820 | var transformType = this.type; 821 | var strength = this.strength; 822 | var amplitude; 823 | var transform; // eslint-disable-next-line default-case 824 | 825 | switch (transformType) { 826 | case 'translate': 827 | amplitude = audioData ? audioData[0][this.audioIndex] : 0; 828 | transform = "translate3d(".concat(amplitude * strength, "px, 0, 0)"); 829 | break; 830 | 831 | case 'rotate': 832 | amplitude = audioData ? audioData[0][this.audioIndex] : 0; 833 | transform = "rotate3d(0,0,1,".concat(amplitude * strength / 10, "deg)"); 834 | break; 835 | 836 | case 'scale': 837 | // eslint-disable-next-line no-nested-ternary 838 | amplitude = audioData ? audioData[0][this.audioIndex] / strength < 1 ? 1 : audioData[0][this.audioIndex] / (strength * 2) : 1; 839 | transform = "scale(".concat(amplitude, ")"); 840 | break; 841 | } // eslint-disable-next-line consistent-return 842 | 843 | 844 | return { 845 | transform: transform 846 | }; 847 | } 848 | } 849 | };/* script */ 850 | var __vue_script__$2 = script$2; 851 | /* template */ 852 | 853 | var __vue_render__$2 = function __vue_render__() { 854 | var _vm = this; 855 | 856 | var _h = _vm.$createElement; 857 | 858 | var _c = _vm._self._c || _h; 859 | 860 | return _c(_vm.tag, { 861 | tag: "component", 862 | style: Object.assign({}, _vm.transform, _vm.transformParameters) 863 | }, [_vm._t("default")], 2); 864 | }; 865 | 866 | var __vue_staticRenderFns__$2 = []; 867 | /* style */ 868 | 869 | var __vue_inject_styles__$2 = undefined; 870 | /* scoped */ 871 | 872 | var __vue_scope_id__$2 = undefined; 873 | /* module identifier */ 874 | 875 | var __vue_module_identifier__$2 = "data-v-32d1a292"; 876 | /* functional template */ 877 | 878 | var __vue_is_functional_template__$2 = false; 879 | /* style inject */ 880 | 881 | /* style inject SSR */ 882 | 883 | /* style inject shadow dom */ 884 | 885 | var __vue_component__$2 = /*#__PURE__*/normalizeComponent({ 886 | render: __vue_render__$2, 887 | staticRenderFns: __vue_staticRenderFns__$2 888 | }, __vue_inject_styles__$2, __vue_script__$2, __vue_scope_id__$2, __vue_is_functional_template__$2, __vue_module_identifier__$2, false, undefined, undefined, undefined);var baseMixin = { 889 | props: { 890 | active: { 891 | type: Boolean, 892 | default: true 893 | }, 894 | duration: { 895 | type: Number, 896 | default: 1000 897 | }, 898 | easing: { 899 | type: String, 900 | default: 'cubic-bezier(0.23, 1, 0.32, 1)' 901 | }, 902 | tag: { 903 | type: String, 904 | default: 'div' 905 | } 906 | } 907 | };var perspectiveMixin = { 908 | props: { 909 | perspective: { 910 | type: Number, 911 | default: 1000 912 | } 913 | }, 914 | computed: { 915 | style: function style() { 916 | return { 917 | perspective: "".concat(this.perspective, "px") 918 | }; 919 | } 920 | } 921 | };// 922 | var script$1 = { 923 | name: 'KinesisScroll', 924 | mixins: [baseMixin, perspectiveMixin, motionMixin, transformMixin], 925 | data: function data() { 926 | return { 927 | transform: {} 928 | }; 929 | }, 930 | computed: { 931 | transformParameters: function transformParameters() { 932 | return { 933 | transitionProperty: 'transform', 934 | transitionDuration: this.transitionDuration, 935 | transformOrigin: this.transformOrigin, 936 | transitionTimingFunction: this.easing 937 | }; 938 | }, 939 | transitionDuration: function transitionDuration() { 940 | return "".concat(this.duration, "ms"); 941 | } 942 | }, 943 | mounted: function mounted() { 944 | window.addEventListener('scroll', this.handleScroll, { 945 | passive: true 946 | }); 947 | }, 948 | beforeDestroy: function beforeDestroy() { 949 | window.removeEventListener('scroll', this.handleScroll, { 950 | passive: true 951 | }); 952 | }, 953 | methods: { 954 | getCycleMovement: function getCycleMovement(xPos, yPos, width, height, shape) { 955 | var x = (xPos - shape.left) * (Math.PI * 2) / width; 956 | var y = (yPos - shape.top) * (Math.PI * 2) / height; 957 | this.cycleMovement = { 958 | x: x, 959 | y: y, 960 | width: width, 961 | height: height 962 | }; 963 | }, 964 | handleScroll: throttle( // eslint-disable-next-line func-names 965 | function () { 966 | if (!this.active) return; 967 | var shape = this.$el.getBoundingClientRect(); 968 | var isInViewport = inViewport(shape); 969 | 970 | if (isInViewport && !!shape.height) { 971 | this.transformBehavior(shape); 972 | } 973 | }, 19, 'scroll'), 974 | transformBehavior: function transformBehavior(shape) { 975 | var movementX; 976 | var movementY; 977 | var scrollPosition = (shape.top - window.innerHeight) / (shape.height + window.innerHeight); 978 | 979 | if (this.cycle <= 0) { 980 | var scrollMovement = scrollPosition * this.strength; 981 | movementX = this.axis === 'x' ? scrollMovement : 0; 982 | movementY = this.axis === 'y' || !this.axis ? scrollMovement : 0; 983 | 984 | if (this.maxX) { 985 | movementX = Math.min(movementX, this.maxX); 986 | } 987 | 988 | if (this.minX) { 989 | movementX = Math.max(movementX, this.minX); 990 | } 991 | 992 | if (this.maxY) { 993 | movementY = Math.min(movementY, this.maxY); 994 | } 995 | 996 | if (this.minY) { 997 | movementY = Math.max(movementY, this.minY); 998 | } 999 | } else if (this.cycle > 0) { 1000 | var _this$getCycleMovemen = this.getCycleMovement(0, 0, window.innerWidth, window.innerHeight, shape), 1001 | x = _this$getCycleMovemen.x, 1002 | y = _this$getCycleMovemen.y, 1003 | width = _this$getCycleMovemen.width, 1004 | height = _this$getCycleMovemen.height; 1005 | 1006 | var cycleX = width * Math.sin(x * this.cycle); 1007 | var cycleY = height * Math.sin(y * this.cycle); 1008 | movementX = this.axis === 'x' ? cycleX / (width / 2) * this.strength : 0; 1009 | movementY = this.axis === 'y' || !this.axis ? cycleY / (height / 2) * this.strength : 0; 1010 | } 1011 | 1012 | var transformType = this.type; 1013 | transformType = transformType === 'scaleX' || transformType === 'scaleY' ? 'scale' : transformType; 1014 | var transform = this.transformSwitch(transformType, movementX, movementY, this.strength); 1015 | this.transform = { 1016 | transform: transform 1017 | }; 1018 | } 1019 | } 1020 | };/* script */ 1021 | var __vue_script__$1 = script$1; 1022 | /* template */ 1023 | 1024 | var __vue_render__$1 = function __vue_render__() { 1025 | var _vm = this; 1026 | 1027 | var _h = _vm.$createElement; 1028 | 1029 | var _c = _vm._self._c || _h; 1030 | 1031 | return _c(_vm.tag, { 1032 | tag: "component", 1033 | style: Object.assign({}, _vm.transform, _vm.transformParameters) 1034 | }, [_vm._t("default")], 2); 1035 | }; 1036 | 1037 | var __vue_staticRenderFns__$1 = []; 1038 | /* style */ 1039 | 1040 | var __vue_inject_styles__$1 = undefined; 1041 | /* scoped */ 1042 | 1043 | var __vue_scope_id__$1 = undefined; 1044 | /* module identifier */ 1045 | 1046 | var __vue_module_identifier__$1 = "data-v-0296bb3c"; 1047 | /* functional template */ 1048 | 1049 | var __vue_is_functional_template__$1 = false; 1050 | /* style inject */ 1051 | 1052 | /* style inject SSR */ 1053 | 1054 | /* style inject shadow dom */ 1055 | 1056 | var __vue_component__$1 = /*#__PURE__*/normalizeComponent({ 1057 | render: __vue_render__$1, 1058 | staticRenderFns: __vue_staticRenderFns__$1 1059 | }, __vue_inject_styles__$1, __vue_script__$1, __vue_scope_id__$1, __vue_is_functional_template__$1, __vue_module_identifier__$1, false, undefined, undefined, undefined);// 1060 | var script = { 1061 | name: 'KinesisDistance', 1062 | props: { 1063 | tag: { 1064 | type: String, 1065 | default: 'div' 1066 | }, 1067 | type: { 1068 | type: String, 1069 | default: 'translate' // translate, rotate, scale, scaleX, scaleY, depth, custom 1070 | 1071 | }, 1072 | transformOrigin: { 1073 | type: String, 1074 | default: 'center' 1075 | }, 1076 | originX: { 1077 | type: Number, 1078 | default: 50 1079 | }, 1080 | originY: { 1081 | type: Number, 1082 | default: 50 1083 | }, 1084 | strength: { 1085 | type: Number, 1086 | default: 10 1087 | }, 1088 | axis: { 1089 | type: String, 1090 | default: null 1091 | }, 1092 | maxX: { 1093 | type: Number, 1094 | default: null 1095 | }, 1096 | maxY: { 1097 | type: Number, 1098 | default: null 1099 | }, 1100 | minX: { 1101 | type: Number, 1102 | default: null 1103 | }, 1104 | minY: { 1105 | type: Number, 1106 | default: null 1107 | }, 1108 | distance: { 1109 | type: Number, 1110 | default: 100 1111 | }, 1112 | cycle: { 1113 | type: Number, 1114 | default: 0 1115 | }, 1116 | active: { 1117 | type: Boolean, 1118 | default: true 1119 | }, 1120 | duration: { 1121 | type: Number, 1122 | default: 1001 1123 | }, 1124 | easing: { 1125 | type: String, 1126 | default: 'cubic-bezier(0.23, 1, 0.32, 1)' 1127 | }, 1128 | perspective: { 1129 | type: Number, 1130 | default: 1000 1131 | } 1132 | }, 1133 | data: function data() { 1134 | return { 1135 | pointer: { 1136 | x: 0, 1137 | y: 0 1138 | }, 1139 | transform: {}, 1140 | component: 'kidistance', 1141 | throttle: 500 1142 | }; 1143 | }, 1144 | computed: { 1145 | style: function style() { 1146 | return { 1147 | perspective: "".concat(this.perspective, "px") 1148 | }; 1149 | }, 1150 | transformParameters: function transformParameters() { 1151 | return { 1152 | position: 'relative', 1153 | transitionProperty: 'transform', 1154 | transitionDuration: this.transitionDuration, 1155 | transformOrigin: this.transformOrigin, 1156 | transitionTimingFunction: this.easing 1157 | }; 1158 | }, 1159 | transitionDuration: function transitionDuration() { 1160 | return "".concat(this.duration, "ms"); 1161 | } 1162 | }, 1163 | mounted: function mounted() { 1164 | window.addEventListener('scroll', this.handleMovement); 1165 | }, 1166 | beforeDestroy: function beforeDestroy() { 1167 | window.removeEventListener('scroll', this.handleMovement); 1168 | }, 1169 | methods: { 1170 | getCoordinates: function getCoordinates(x, y) { 1171 | var shape = this.$el.getBoundingClientRect(); 1172 | return { 1173 | x: x + shape.left, 1174 | y: y + shape.top 1175 | }; 1176 | }, 1177 | getDistance: function getDistance(x1, x2, y1, y2) { 1178 | return Math.floor(Math.hypot(x2 - x1, y2 - y1)); 1179 | }, 1180 | // eslint-disable-next-line func-names 1181 | handleMovement: throttle(function (event) { 1182 | window.addEventListener('mousemove', this.handleMovement); 1183 | var pointer = this.pointer; 1184 | pointer.x = event.clientX; 1185 | pointer.y = event.clientY; 1186 | this.transformBehavior(); 1187 | }, 50), 1188 | transformBehavior: function transformBehavior() { 1189 | var shape = this.$el.getBoundingClientRect(); 1190 | var center = this.getCoordinates(shape.width / 2, shape.height / 2); 1191 | var distance = this.getDistance(this.pointer.x, center.x, this.pointer.y, center.y); 1192 | 1193 | if (distance > this.distance) { 1194 | this.transform = {}; 1195 | this.throttle = 500; 1196 | return; 1197 | } 1198 | 1199 | this.throttle = 50; 1200 | var transform = "scale(".concat(distance / this.distance, ")"); // Add radius from which the transfrom will start 1201 | 1202 | this.transform = { 1203 | transform: transform 1204 | }; 1205 | }, 1206 | scaleMovement: function scaleMovement(x, y) { 1207 | var type = this.type; 1208 | var movement = Math.sign(this.strength) * (Math.abs(x) + Math.abs(y)) / 10 + 1; 1209 | return "scale3d(".concat(type === 'scaleX' || type === 'scale' ? movement : 1, ",\n ").concat(type === 'scaleY' || type === 'scale' ? movement : 1, ",\n 1)"); 1210 | } 1211 | } 1212 | };/* script */ 1213 | var __vue_script__ = script; 1214 | /* template */ 1215 | 1216 | var __vue_render__ = function __vue_render__() { 1217 | var _vm = this; 1218 | 1219 | var _h = _vm.$createElement; 1220 | 1221 | var _c = _vm._self._c || _h; 1222 | 1223 | return _c(_vm.tag, { 1224 | tag: "component", 1225 | style: Object.assign({}, _vm.transform, _vm.transformParameters) 1226 | }, [_vm._t("default")], 2); 1227 | }; 1228 | 1229 | var __vue_staticRenderFns__ = []; 1230 | /* style */ 1231 | 1232 | var __vue_inject_styles__ = undefined; 1233 | /* scoped */ 1234 | 1235 | var __vue_scope_id__ = undefined; 1236 | /* module identifier */ 1237 | 1238 | var __vue_module_identifier__ = "data-v-97bf617a"; 1239 | /* functional template */ 1240 | 1241 | var __vue_is_functional_template__ = false; 1242 | /* style inject */ 1243 | 1244 | /* style inject SSR */ 1245 | 1246 | /* style inject shadow dom */ 1247 | 1248 | var __vue_component__ = /*#__PURE__*/normalizeComponent({ 1249 | render: __vue_render__, 1250 | staticRenderFns: __vue_staticRenderFns__ 1251 | }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, undefined, undefined, undefined);var Plugin$1 = { 1252 | install: function install(vue) { 1253 | vue.component(__vue_component__$2.name, __vue_component__$2); 1254 | vue.component(__vue_component__$4.name, __vue_component__$4); 1255 | vue.component(__vue_component__.name, __vue_component__); 1256 | vue.component(__vue_component__$3.name, __vue_component__$3); 1257 | vue.component(__vue_component__$1.name, __vue_component__$1); 1258 | } 1259 | }; 1260 | var GlobalVue$1 = null; 1261 | 1262 | if (typeof window !== 'undefined') { 1263 | GlobalVue$1 = window.vue; 1264 | } else if (typeof global !== 'undefined') { 1265 | GlobalVue$1 = global.vue; 1266 | } 1267 | 1268 | if (GlobalVue$1) { 1269 | GlobalVue$1.use(Plugin$1); 1270 | }var components=/*#__PURE__*/Object.freeze({__proto__:null,'default': Plugin$1,KinesisAudio: __vue_component__$2,KinesisContainer: __vue_component__$4,KinesisDistance: __vue_component__,KinesisElement: __vue_component__$3,KinesisScroll: __vue_component__$1});/* eslint-disable */ 1271 | 1272 | var install = function install(vue) { 1273 | if (install.installed) { 1274 | return; 1275 | } 1276 | 1277 | install.installed = true; 1278 | 1279 | for (var name in components) { 1280 | vue.use(components[name]); 1281 | } 1282 | 1283 | vue.component('kinesis-container', __vue_component__$4); 1284 | vue.component('kinesis-element', __vue_component__$3); 1285 | vue.component('kinesis-audio', __vue_component__$2); 1286 | vue.component('kinesis-scroll', __vue_component__$1); 1287 | vue.component('kinesis-distance', __vue_component__); 1288 | }; 1289 | 1290 | var Plugin = { 1291 | install: install 1292 | }; 1293 | var GlobalVue = null; 1294 | 1295 | if (typeof window !== 'undefined') { 1296 | GlobalVue = window.vue; 1297 | } else if (typeof global !== 'undefined') { 1298 | GlobalVue = global.vue; 1299 | } 1300 | 1301 | if (GlobalVue) { 1302 | GlobalVue.use(Plugin); 1303 | }exports.KinesisAudio=__vue_component__$2;exports.KinesisContainer=__vue_component__$4;exports.KinesisDistance=__vue_component__;exports.KinesisElement=__vue_component__$3;exports.KinesisScroll=__vue_component__$1;exports.default=Plugin; --------------------------------------------------------------------------------