├── .gitignore ├── examples ├── background.png ├── background2.jpg ├── main.js ├── no-component │ ├── example.js │ └── index.html ├── priorities │ └── index.html ├── timeouts │ └── index.html └── index.html ├── tests ├── index.test.js ├── karma.conf.js ├── __init.test.js └── helpers.js ├── browser.js ├── LICENSE ├── package.json ├── dist ├── aframe-asset-layz-load.min.js └── aframe-asset-layz-load.js ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .sw[ponm] 2 | examples/build.js 3 | examples/node_modules/ 4 | gh-pages 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /examples/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youmustfight/aframe-asset-lazy-load/HEAD/examples/background.png -------------------------------------------------------------------------------- /examples/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youmustfight/aframe-asset-lazy-load/HEAD/examples/background2.jpg -------------------------------------------------------------------------------- /examples/main.js: -------------------------------------------------------------------------------- 1 | var AFRAME = require('aframe-core'); 2 | var assetLazyLoad = require('../index.js').component; 3 | AFRAME.registerComponent('lazy-load', assetLazyLoad); -------------------------------------------------------------------------------- /tests/index.test.js: -------------------------------------------------------------------------------- 1 | var Aframe = require('aframe-core'); 2 | var example = require('../index.js').component; 3 | var entityFactory = require('./helpers').entityFactory; 4 | 5 | Aframe.registerComponent('example', example); 6 | 7 | describe('example', function () { 8 | beforeEach(function (done) { 9 | this.el = entityFactory(); 10 | this.el.addEventListener('loaded', function () { 11 | done(); 12 | }); 13 | }); 14 | 15 | describe('example property', function () { 16 | it('is good', function () { 17 | assert.equal(1, 1); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /browser.js: -------------------------------------------------------------------------------- 1 | // Browser distribution of the A-Frame component. 2 | (function () { 3 | if (typeof AFRAME === 'undefined') { 4 | console.error('Component attempted to register before AFRAME was available.'); 5 | return; 6 | } 7 | 8 | // Register all components here. 9 | var components = { 10 | assetLazyLoad: require('./index').component 11 | }; 12 | 13 | Object.keys(components).forEach(function (name) { 14 | if (AFRAME.aframeCore) { 15 | AFRAME.aframeCore.registerComponent(name, components[name]); 16 | } else { 17 | AFRAME.registerComponent(name, components[name]); 18 | } 19 | }); 20 | })(); 21 | -------------------------------------------------------------------------------- /tests/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function (config) { 3 | config.set({ 4 | basePath: '../', 5 | browserify: { 6 | paths: ['./'] 7 | }, 8 | browsers: ['firefox_latest'], 9 | customLaunchers: { 10 | firefox_latest: { 11 | base: 'FirefoxNightly', 12 | prefs: { /* empty */ } 13 | } 14 | }, 15 | client: { 16 | captureConsole: true, 17 | mocha: {ui: 'bdd'} 18 | }, 19 | envPreprocessor: [ 20 | 'TEST_ENV' 21 | ], 22 | files: [ 23 | 'tests/**/*.test.js', 24 | ], 25 | frameworks: ['mocha', 'sinon-chai', 'chai-shallow-deep-equal', 'browserify'], 26 | preprocessors: { 27 | 'tests/**/*.js': ['browserify'] 28 | }, 29 | reporters: ['mocha'] 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /tests/__init.test.js: -------------------------------------------------------------------------------- 1 | /* global sinon, setup, teardown */ 2 | 3 | /** 4 | * __init.test.js is run before every test case. 5 | */ 6 | window.debug = true; 7 | 8 | var AScene = require('aframe-core').AScene; 9 | 10 | beforeEach(function () { 11 | this.sinon = sinon.sandbox.create(); 12 | // Stub to not create a WebGL context since Travis CI runs headless. 13 | this.sinon.stub(AScene.prototype, 'attachedCallback'); 14 | }); 15 | 16 | afterEach(function () { 17 | // Clean up any attached elements. 18 | ['canvas', 'a-assets', 'a-scene'].forEach(function (tagName) { 19 | var els = document.querySelectorAll(tagName); 20 | for (var i = 0; i < els.length; i++) { 21 | els[i].parentNode.removeChild(els[i]); 22 | } 23 | }); 24 | AScene.scene = null; 25 | 26 | this.sinon.restore(); 27 | }); 28 | -------------------------------------------------------------------------------- /examples/no-component/example.js: -------------------------------------------------------------------------------- 1 | var assets = $("a-assets"); 2 | var sphere1 = $('.sphere-1'); 3 | var sphere1 = $('.sphere-2'); 4 | 5 | // Example Sphere 1 6 | setTimeout(function(){ 7 | // Append Img Element to Assets - Immediately starting load of content 8 | assets.prepend(''); 9 | // Upon Image Load being Done - Update Skybox Entity 10 | $('#example-sphere-1').on('load', function(){ 11 | $('a-entity.sphere-1').attr("material","src: #example-sphere-1"); 12 | }); 13 | }); 14 | 15 | // Example Sphere 2 16 | setTimeout(function(){ 17 | assets.prepend(''); 18 | $('#example-sphere-2').on('load', function(){ 19 | $('a-entity.sphere-2').attr("material","src: #example-sphere-2"); 20 | }); 21 | }, 1550); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kevin Ngo 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 | 23 | -------------------------------------------------------------------------------- /examples/no-component/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /examples/priorities/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 17 | 27 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/timeouts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 17 | 27 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/helpers.js: -------------------------------------------------------------------------------- 1 | /* global suite */ 2 | 3 | /** 4 | * Helper method to create a scene, create an entity, add entity to scene, 5 | * add scene to document. 6 | * 7 | * @returns {object} An `` element. 8 | */ 9 | module.exports.entityFactory = function () { 10 | var scene = document.createElement('a-scene'); 11 | var entity = document.createElement('a-entity'); 12 | scene.appendChild(entity); 13 | document.body.appendChild(scene); 14 | return entity; 15 | }; 16 | 17 | /** 18 | * Creates and attaches a mixin element (and an `` element if necessary). 19 | * 20 | * @param {string} id - ID of mixin. 21 | * @param {object} obj - Map of component names to attribute values. 22 | * @returns {object} An attached `` element. 23 | */ 24 | module.exports.mixinFactory = function (id, obj) { 25 | var mixinEl = document.createElement('a-mixin'); 26 | mixinEl.setAttribute('id', id); 27 | Object.keys(obj).forEach(function (componentName) { 28 | mixinEl.setAttribute(componentName, obj[componentName]); 29 | }); 30 | 31 | var assetsEl = document.querySelector('a-assets'); 32 | if (!assetsEl) { 33 | assetsEl = document.createElement('a-assets'); 34 | document.body.appendChild(assetsEl); 35 | } 36 | assetsEl.appendChild(mixinEl); 37 | 38 | return mixinEl; 39 | }; 40 | 41 | /** 42 | * Test that is only run locally and is skipped on CI. 43 | */ 44 | module.exports.getSkipCISuite = function () { 45 | if (window.__env__.TEST_ENV === 'ci') { 46 | return suite.skip; 47 | } else { 48 | return suite; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-asset-lazy-load", 3 | "version": "1.0.0", 4 | "description": "Aframe component for delaying and prioritizing loading of assets.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "browserify examples/main.js -o examples/build.js", 8 | "dev": "budo examples/main.js:build.js --dir examples --port 8000 --live --open", 9 | "dist": "webpack browser.js dist/aframe-asset-layz-load.js && webpack -p browser.js dist/aframe-asset-layz-load.min.js", 10 | "postpublish": "npm run dist", 11 | "preghpages": "npm run build && rm -rf gh-pages && cp -r examples gh-pages", 12 | "ghpages": "npm run preghpages && ghpages -p gh-pages", 13 | "test": "karma start ./tests/karma.conf.js" 14 | }, 15 | "keywords": [ 16 | "aframe", 17 | "aframe-component", 18 | "layout", 19 | "aframe-vr", 20 | "vr", 21 | "aframe-layout", 22 | "mozvr", 23 | "webvr" 24 | ], 25 | "contributors": [ 26 | "Kevin Ngo ", 27 | "Mark Hansen " 28 | ], 29 | "license": "MIT", 30 | "devDependencies": { 31 | "aframe-core": "^0.1.0", 32 | "browserify": "^12.0.1", 33 | "browserify-css": "^0.8.3", 34 | "budo": "^7.1.0", 35 | "chai": "^3.4.1", 36 | "chai-shallow-deep-equal": "^1.3.0", 37 | "ghpages": "0.0.3", 38 | "jquery": "^2.2.0", 39 | "karma": "^0.13.15", 40 | "karma-browserify": "^4.4.2", 41 | "karma-chai-shallow-deep-equal": "0.0.4", 42 | "karma-firefox-launcher": "^0.1.7", 43 | "karma-mocha": "^0.2.1", 44 | "karma-mocha-reporter": "^1.1.3", 45 | "karma-sinon-chai": "^1.1.0", 46 | "mocha": "^2.3.4", 47 | "webpack": "^1.12.9" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dist/aframe-asset-layz-load.min.js: -------------------------------------------------------------------------------- 1 | !function(t){function a(e){if(o[e])return o[e].exports;var n=o[e]={exports:{},id:e,loaded:!1};return t[e].call(n.exports,n,n.exports,a),n.loaded=!0,n.exports}var o={};return a.m=t,a.c=o,a.p="",a(0)}([function(t,a,o){!function(){if("undefined"==typeof AFRAME)return void console.error("Component attempted to register before AFRAME was available.");var t={assetLazyLoad:o(1).component};Object.keys(t).forEach(function(a){AFRAME.aframeCore?AFRAME.aframeCore.registerComponent(a,t[a]):AFRAME.registerComponent(a,t[a])})}()},function(t,a){t.exports.component={schema:{delay:{"default":0,min:0},chunk:{min:0},src:{},id:{}},init:function(){n||(n=!0,null==document.querySelector("a-assets")&&(o=$("a-scene"),e=document.createElement("a-assets"),o.prepend(e),e=$("a-assets"))),r||(r=!0,l($("[lazy-load]")))},update:function(t){},remove:function(){}};var o,e,n=!1,r=!1,i=[],l=function(t){console.log("~~~Setting Up Lazy Loading~~~"),setTimeout(function(){t.each(function(a){var o=$(t[a]);if(void 0==o.attr("lazy-load").chunk&&void 0!=o.attr("lazy-load").delay&&c(o),void 0!=o.attr("lazy-load").chunk){var e=o.attr("lazy-load").chunk;void 0==i[e]&&(i[e]=[[],[]]),o.attr("lazy-load").src?i[e][0].push(o):i[e][1].push(o)}}),console.log("~~~Lazy Loading~~~"),console.log(i),d(0,0,i.length)})},d=function(t,a,o){var e=t,n=a;if(!(e>o)){if(void 0==i[e])return void d(e+1,0,o);var r=i[e][n].length,l=0;if(0==i[e][n].length)return 0==n?void d(e,1,o):void d(e+1,0,o);for(var s in i[e][n])0==n?c(i[e][n][s],function(){l++,l==r&&d(e,1,o)}):(i[e][n][s].attr("material","src:#"+i[t][a][s].attr("lazy-load").id),l++,l==r&&d(e+1,0,o))}},c=function(t,a){setTimeout(function(){if(t.attr("lazy-load").src)e.prepend("'),$("#"+t.attr("lazy-load").id).on("load",function(){return $(t).attr("material","src:#"+t.attr("lazy-load").id),a?a():void 0});else if($(t).attr("material","src:#"+t.attr("lazy-load").id),a)return a()},t.attr("lazy-load").delay||0)}}]); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## aframe-asset-lazy-load-component 2 | 3 | An a-entity component to assign asset loading order and delays 4 | 5 | ### Usage 6 | 7 | Install (or directly include the [browser files](dist)). 8 | 9 | ```bash 10 | npm install --save aframe-asset-lazy-load 11 | ``` 12 | 13 | Register 14 | 15 | ```js 16 | require('aframe'); 17 | var layout = require('aframe-layout').Component; 18 | AFRAME.registerComponent('layout', layout); 19 | ``` 20 | 21 | Use with delays or chunks. 22 | 23 | ```html 24 | 29 | 34 | 39 | 44 | ``` 45 | 46 | Chunking is simply a way to block asset loading. For example, Let's say you have a game with a cinematic opening. Currently, you have to load all your assets at the start, meaning textures for the game are taking up bandwith you might want to use to get a user in the door. With chunking, you can set what is to be loaded immediately, via chunk 1, and what is to then be loaded upon those being completed, via chunk 2. This lets you spread out asset loading to make the immediate experience smoother. 47 | 48 | ### Attributes 49 | 50 | | Attribute | Description | Default Value | 51 | | --------- | ----------- | ------------- | 52 | | delay | Milliseconds waited until an image is appened to a-assets. | 0 | 53 | | chunk | Slot an asset is placed in for loading. Multiple assets can be assigned to the same chunk. Over-rides delays | | 54 | | src | Path to the image being loaded | | 55 | | id | The ID being associated with the entity's material property and element in a-assets. | | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | A-Frame Asset-Lazy-Load Component 4 | 5 | 26 | 27 | 28 |

A-Frame Asset-Lazy-Load Component

29 | No Component - Using Jquery Timeouts and Onloads 30 |

Using jQuery to individually add images to the assets element, and upon load, update the ID on the relevant entity.

31 |

Cons: 1) Hides assets in javascript code 2) Requires loading individually 3) Can't reliably assign IDs to assets sharing that image

32 | Using AssetLazyLoad - Timeouts 33 |

Using the Asset-Lazy-Load Component to handle delays.

34 |

Pros: 1) Keeps asset descriptions in a-frame code 2) Removes the need to repeatedly write code for loading to assets and assigning IDs upon load.

35 |

Cons: Misjudging delays when assigning IDs can cause streams of warnings and temporary mismatching of assets

36 | Using AssetLazyLoad - Chunking 37 |

Ussing the Asset-Lazy-Load Component, via chunking. This is a hybrid of blocking/non-blocking loading of assets. For example, you may have a game with a cinematic opening. Rather than loading all image assets right at the start, you can prioritize assets for your cinematic opening in 'chunk: 0', and the rest of your game assets in 'chunk: 1'. This method requires that all assets in chunk 0 finish downloading before moving on.

38 |

Pros: 1) Keeps asset descriptions in a-frame code, 2) No need to juggle loading assets in javascript and assigning IDs appropriately 3) No need to guess with timeouts or delays

39 |
40 |
To Dos/Ideas:
41 |
    42 |
  • Could each chunk fire an event or something when they're done loading? That way developers could prevent a user from advancing to a new scene, until all assets are ready?
  • 43 |
  • Would like to have chunks only required for when you define a src. This way a user can define IDs with lazy load, and the assignment of that ID will automatically be put in the appropriate chunk
  • 44 |
  • Would like to expand from images to videos and objects
  • 45 |
  • Would like to have it work for wrappers like 'a-image'
  • 46 |
  • Perhaps re-write chunking idea to be contained in the a-assets, since it might be easier to keep track of things. Then play with entity materials to watch for an asset loading and update when it's done
  • 47 |
48 | 49 |
50 |
51 | Fork me on GitHub 52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asset Lazy Load component for A-Frame. 3 | */ 4 | module.exports.component = { 5 | schema: { 6 | // type: {default: 'timeout', oneOf: ['timeout', 'chunk']}, 7 | delay: {default: 0, min: 0}, 8 | chunk: {min: 0}, 9 | src: {}, 10 | id: {} 11 | }, 12 | 13 | /** 14 | * Called once when component is attached. Generally for initial setup. 15 | */ 16 | init: function () { 17 | // See if a-assets exists 18 | if (!assetsChecked) { 19 | assetsChecked = true; 20 | if(document.querySelector("a-assets") == null){ 21 | aScene = document.querySelector("a-scene"); 22 | aAssets = document.createElement("a-assets"); 23 | aScene.appendChild(aAssets); 24 | aAssets = document.querySelector("a-assets"); 25 | } 26 | } 27 | 28 | // Gather Up Lazy Loads 29 | if (!lazyLoadInitiated) { 30 | lazyLoadInitiated = true; 31 | var entities = document.querySelectorAll('a-entity'); 32 | var entitiesArray = Array.prototype.slice.call(entities); 33 | var lazyLoadEntities = entitiesArray.filter(function(el){ 34 | if(el.hasAttribute('lazy-load')){ 35 | return true; 36 | } 37 | return false; 38 | }); 39 | initLazyLoading(lazyLoadEntities); 40 | } 41 | 42 | }, 43 | update: function (oldData) { }, 44 | remove: function () {} 45 | }; 46 | 47 | // Checking existance of 48 | var assetsChecked = false; 49 | var aScene; 50 | var aAssets; 51 | 52 | // Checking to see if lazy-load initialized 53 | var lazyLoadInitiated = false; 54 | 55 | // Where we're putting all our assets in load order 56 | var lazyLoadManifest = []; 57 | 58 | 59 | var initLazyLoading = function(elements){ 60 | console.log("~~~Setting Up Lazy Loading~~~"); 61 | setTimeout(function(){ 62 | // Build Load Order 63 | elements.forEach(function(el){ 64 | var attributes = el.getAttribute("lazy-load"); 65 | // If has delay, and not concerned with chunk, set off immediately 66 | if(attributes.chunk == undefined && attributes.delay != undefined){ 67 | dispatchLoad(el); 68 | } 69 | // If it has a chunk, add to manifest 70 | if(attributes.chunk != undefined){ 71 | var pos = attributes.chunk; 72 | // If nothing exists at that position, create new set of arrays 73 | if(lazyLoadManifest[pos] == undefined){ 74 | lazyLoadManifest[pos] = [[],[]]; 75 | } 76 | // Prioritize if has src 77 | if(attributes.src){ 78 | // 0 array contains only uploads with srcs 79 | lazyLoadManifest[pos][0].push(el); 80 | } else { 81 | // 1 array contains anything with only an id 82 | lazyLoadManifest[pos][1].push(el); 83 | } 84 | } 85 | }); 86 | 87 | // Start Loading! Set in motion recurssion!!! 88 | console.log("~~~Lazy Loading~~~"); 89 | console.log("Load Order:", lazyLoadManifest); 90 | runLazyLoad(0,0,lazyLoadManifest.length); 91 | }); 92 | } 93 | 94 | var runLazyLoad = function(currentChunk, currentSet, lastChunk){ 95 | var thisChunk = currentChunk; 96 | var thisSet = currentSet; 97 | 98 | // Stop if we're past the last chunk 99 | if(thisChunk > lastChunk){ 100 | return; 101 | } 102 | // Check to see if we're in an undefined chunk 103 | if (lazyLoadManifest[thisChunk] == undefined){ 104 | runLazyLoad((thisChunk+1), 0, lastChunk); 105 | return; 106 | } 107 | // Set Remaining Variables 108 | var assetsToHandle = lazyLoadManifest[thisChunk][thisSet].length; 109 | var assetsHandled = 0; 110 | 111 | // Check to see if we're in an empty chunk 112 | if (lazyLoadManifest[thisChunk][thisSet].length == 0){ 113 | if (thisSet == 0){ 114 | runLazyLoad(thisChunk, 1, lastChunk); 115 | return; 116 | } else { 117 | runLazyLoad((thisChunk+1), 0, lastChunk); 118 | return; 119 | } 120 | } else { 121 | // Run this chunk if not undefined 122 | for (var asset in lazyLoadManifest[thisChunk][thisSet]){ 123 | // For each asset in our SRC set 124 | if (thisSet == 0){ 125 | dispatchLoad(lazyLoadManifest[thisChunk][thisSet][asset], function(){ 126 | assetsHandled++; 127 | if(assetsHandled == assetsToHandle){ 128 | runLazyLoad(thisChunk, 1, lastChunk); 129 | } 130 | }); 131 | } else { 132 | // Set our material srcs, and increment. 133 | lazyLoadManifest[thisChunk][thisSet][asset].setAttribute("material","src:#" + lazyLoadManifest[currentChunk][currentSet][asset].getAttribute("lazy-load").id); 134 | assetsHandled++; 135 | if(assetsHandled == assetsToHandle){ 136 | runLazyLoad((thisChunk+1), 0, lastChunk); 137 | } 138 | } 139 | } 140 | } 141 | 142 | } 143 | 144 | var dispatchLoad = function(el,cb){ 145 | var attributes = el.getAttribute("lazy-load"); 146 | setTimeout(function(){ 147 | // If the asset has a SRC 148 | if(attributes.src){ 149 | // Add to a-assets 150 | var newAsset = document.createElement("img"); 151 | newAsset.id = attributes.id; 152 | newAsset.src = attributes.src; 153 | aAssets.appendChild(newAsset); 154 | // Wait till loaded... 155 | newAsset.addEventListener('load', function(){ 156 | // To update entity's material property 157 | el.setAttribute("material","src:#" + attributes.id); 158 | // Run callback 159 | if (cb) return cb(); 160 | }); 161 | } else { 162 | // Otherwise, just upadte tag 163 | el.setAttribute("material","src:#" + attributes.id); 164 | if (cb) return cb(); 165 | } 166 | }, attributes.delay || 0); 167 | } -------------------------------------------------------------------------------- /dist/aframe-asset-layz-load.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports, __webpack_require__) { 46 | 47 | // Browser distribution of the A-Frame component. 48 | (function () { 49 | if (typeof AFRAME === 'undefined') { 50 | console.error('Component attempted to register before AFRAME was available.'); 51 | return; 52 | } 53 | 54 | // Register all components here. 55 | var components = { 56 | assetLazyLoad: __webpack_require__(1).component 57 | }; 58 | 59 | Object.keys(components).forEach(function (name) { 60 | if (AFRAME.aframeCore) { 61 | AFRAME.aframeCore.registerComponent(name, components[name]); 62 | } else { 63 | AFRAME.registerComponent(name, components[name]); 64 | } 65 | }); 66 | })(); 67 | 68 | 69 | /***/ }, 70 | /* 1 */ 71 | /***/ function(module, exports) { 72 | 73 | /** 74 | * Asset Lazy Load component for A-Frame. 75 | */ 76 | module.exports.component = { 77 | schema: { 78 | // type: {default: 'timeout', oneOf: ['timeout', 'chunk']}, 79 | delay: {default: 0, min: 0}, 80 | chunk: {min: 0}, 81 | src: {}, 82 | id: {} 83 | }, 84 | 85 | /** 86 | * Called once when component is attached. Generally for initial setup. 87 | */ 88 | init: function () { 89 | /** 90 | * Make sure Assets Exists 91 | */ 92 | 93 | if (!assetsChecked) { 94 | assetsChecked = true; 95 | if(document.querySelector("a-assets") == null){ 96 | aScene = $("a-scene"); 97 | aAssets = document.createElement("a-assets"); 98 | aScene.prepend(aAssets); 99 | aAssets = $("a-assets"); 100 | } 101 | } 102 | 103 | // Gather Up Lazy Loads 104 | if (!lazyLoadInitiated) { 105 | lazyLoadInitiated = true; 106 | initLazyLoading($('[lazy-load]')); 107 | } 108 | 109 | }, 110 | 111 | /** 112 | * Called when component is attached and when component data changes. 113 | * Generally modifies the entity based on the data. 114 | */ 115 | update: function (oldData) { 116 | 117 | }, 118 | 119 | /** 120 | * Called when a component is removed (e.g., via removeAttribute). 121 | * Generally undoes all modifications to the entity. 122 | */ 123 | remove: function () { 124 | 125 | } 126 | }; 127 | 128 | // Checking existance of 129 | var assetsChecked = false; 130 | var aScene; 131 | var aAssets; 132 | 133 | // Checking to see if lazy-load initialized 134 | var lazyLoadInitiated = false; 135 | 136 | // Where we're putting all our assets in load order 137 | var lazyLoadManifest = []; 138 | 139 | 140 | var initLazyLoading = function(elements){ 141 | console.log("~~~Setting Up Lazy Loading~~~"); 142 | // Reset Stack for jQuery 143 | setTimeout(function(){ 144 | 145 | // Build Load Order 146 | elements.each(function(i){ 147 | var el = $(elements[i]); 148 | // If has delay, and not concerned with chunk, set off immediately 149 | if(el.attr("lazy-load").chunk == undefined && el.attr("lazy-load").delay != undefined){ 150 | dispatchLoad(el); 151 | } 152 | // If it has a chunk, add to manifest 153 | if(el.attr("lazy-load").chunk != undefined){ 154 | var pos = el.attr("lazy-load").chunk; 155 | // If nothing exists at that position, create new set of arrays 156 | if(lazyLoadManifest[pos] == undefined){ 157 | lazyLoadManifest[pos] = [[],[]]; 158 | } 159 | // Prioritize if has src 160 | if(el.attr("lazy-load").src){ 161 | // 0 array contains only uploads with srcs 162 | lazyLoadManifest[pos][0].push(el); 163 | } else { 164 | // 1 array contains anything with only an id 165 | lazyLoadManifest[pos][1].push(el); 166 | } 167 | } 168 | }); 169 | 170 | // Start Loading! Set in motion recurssion!!! 171 | console.log("~~~Lazy Loading~~~"); 172 | console.log(lazyLoadManifest); 173 | runLazyLoad(0,0,lazyLoadManifest.length); 174 | }); 175 | } 176 | 177 | var runLazyLoad = function(currentChunk, currentSet, lastChunk){ 178 | var thisChunk = currentChunk; 179 | var thisSet = currentSet; 180 | 181 | // Stop if we're past the last chunk 182 | if(thisChunk > lastChunk){ 183 | return; 184 | } 185 | // Check to see if we're in an undefined chunk 186 | if (lazyLoadManifest[thisChunk] == undefined){ 187 | runLazyLoad((thisChunk+1), 0, lastChunk); 188 | return; 189 | } 190 | // Set Remaining Variables 191 | var assetsToHandle = lazyLoadManifest[thisChunk][thisSet].length; 192 | var assetsHandled = 0; 193 | 194 | // Check to see if we're in an empty chunk 195 | if (lazyLoadManifest[thisChunk][thisSet].length == 0){ 196 | if (thisSet == 0){ 197 | runLazyLoad(thisChunk, 1, lastChunk); 198 | return; 199 | } else { 200 | runLazyLoad((thisChunk+1), 0, lastChunk); 201 | return; 202 | } 203 | } else { 204 | // Run this chunk if not undefined 205 | for (var asset in lazyLoadManifest[thisChunk][thisSet]){ 206 | // For each asset in our SRC set 207 | if (thisSet == 0){ 208 | dispatchLoad(lazyLoadManifest[thisChunk][thisSet][asset], function(){ 209 | assetsHandled++; 210 | if(assetsHandled == assetsToHandle){ 211 | runLazyLoad(thisChunk, 1, lastChunk); 212 | } 213 | }); 214 | } else { 215 | // Set our material srcs, and increment. 216 | lazyLoadManifest[thisChunk][thisSet][asset].attr("material","src:#" + lazyLoadManifest[currentChunk][currentSet][asset].attr("lazy-load").id); 217 | assetsHandled++; 218 | if(assetsHandled == assetsToHandle){ 219 | runLazyLoad((thisChunk+1), 0, lastChunk); 220 | } 221 | } 222 | } 223 | } 224 | 225 | } 226 | 227 | var dispatchLoad = function(el,cb){ 228 | setTimeout(function(){ 229 | // If the asset has a SRC 230 | if(el.attr("lazy-load").src){ 231 | // Add to a-assets 232 | aAssets.prepend(''); 233 | // Wait till loaded... 234 | $('#'+ el.attr("lazy-load").id).on('load', function(){ 235 | // To update entity's material property 236 | $(el).attr("material","src:#" + el.attr("lazy-load").id); 237 | // Run callback 238 | if (cb) return cb(); 239 | }); 240 | } else { 241 | // Otherwise, just upadte tag 242 | $(el).attr("material","src:#" + el.attr("lazy-load").id); 243 | if (cb) return cb(); 244 | } 245 | }, el.attr("lazy-load").delay || 0); 246 | } 247 | 248 | /***/ } 249 | /******/ ]); --------------------------------------------------------------------------------