├── .gitignore ├── LICENSE ├── README.md ├── comcastify.js └── example ├── baby-sloth.jpg ├── example-progressivejpeg.html ├── example-random.html ├── example-randompause.html ├── example.html ├── sloth-close-up.jpg ├── sloth-hanging.jpg └── sloth.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 The Onion 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FART OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComcastifyJS 2 | With all this internet going around, sometimes you just want to experience the thrill of a long page load. Give your users the chance to enjoy a little slice of the future by slow loading your website's images with ComcastifyJS! 3 | 4 | ## Lets slow things down! 5 | 1. Include comcastify.js on your page, or use the latest version from our CDN: 6 | 7 | ```html 8 | 9 | ``` 10 | 11 | 2. Prepare the images on your page on document ready (so images don't show up before the box): 12 | 13 | ```js 14 | comcastifyjs.letsPrepareTheseImages(); 15 | ``` 16 | 17 | 3. Initialize comcastify on window load (so image sizes are properly calculated): 18 | 19 | ```js 20 | comcastifyjs.fixMyImagesLoadingSoFast({ 21 | boxColor: '#123456', 22 | loadMaxPercent: 0.75, 23 | loadSpeed: 100, 24 | loadIncrement: 5 25 | }); 26 | ``` 27 | 4. Switch up parameters to change your experience: 28 | * **elements** : A list of DOM elements to limit comcastification to. 29 | * **boxColor** : The hex color for the box placed over images. 30 | * **loadMaxPercent** : The max percentage of image to load. (0 to 1) 31 | * **loadSpeed** : Time required to load your images to their max in ms. 32 | * **loadIncrement** : Number of pixels to load each time the loadSpeed timer ticks. 33 | * **randLoadIncrement**: Set to true to make load increment random, loadIncrement ignored in this case. 34 | * **randomPause** : Probability of skipping a pass each time the loadSpeed timer ticks. (0 to 1) 35 | * **progressiveJPEG** Set to true to enable progressive JPEG emulation 36 | 37 | ## See it in action! 38 | See an example on the project's site at: http://theonion.github.io/comcastifyjs/ 39 | 40 | Or, see it modeled by [these koalas!](http://www.clickhole.com/article/these-koalas-are-refusing-load-support-net-neutral-967) 41 | 42 | ## That's it! 43 | Now grab a coffee and enjoy the load times! 44 | -------------------------------------------------------------------------------- /comcastify.js: -------------------------------------------------------------------------------- 1 | var comcastifyjs = (function () { 2 | 3 | // setup slowload modifier callback, structure avoids some annoying timer/closure problems 4 | var slowloadModiferCallback = function (slowloadDiv, args) { 5 | return function () { 6 | (function (slowloadDiv, args) { 7 | // calculate new height for box based on args 8 | var img = slowloadDiv.slothifyData.img; 9 | var newTopClip = slowloadDiv.slothifyData.imageTopClip + args.loadIncrement; 10 | var progressiveJPEGInProgress = false; 11 | if (args.randomPause === 0.0 || Math.random() > args.randomPause) { 12 | slowloadDiv.style.width = img.offsetWidth + 'px'; 13 | slowloadDiv.style.height = img.offsetHeight + 'px'; 14 | slowloadDiv.style.top = img.offsetTop + 'px'; 15 | slowloadDiv.style.left = img.offsetLeft + 'px'; 16 | 17 | // update slowload div 18 | slowloadDiv.style.clip = 'rect(' + newTopClip + 'px auto auto auto)'; 19 | } 20 | 21 | // check stopping conditions 22 | var maxImageHeight = img.height * args.loadMaxPercent; 23 | 24 | //process progressive JPEG unblurring 25 | if (args.progressiveJPEG && newTopClip >= maxImageHeight) { 26 | var newTopClipBlur = slowloadDiv.slothifyData.blurImageTopClip + args.loadIncrement; 27 | 28 | //continue to honor the randomPause setting 29 | if (args.randomPause === 0.0 || Math.random() > args.randomPause) { 30 | slowloadDiv.slothifyData.blurImg.style.width = img.offsetWidth + 'px'; 31 | slowloadDiv.slothifyData.blurImg.style.height = img.offsetHeight + 'px'; 32 | slowloadDiv.slothifyData.blurImg.style.top = img.offsetTop + 'px'; 33 | slowloadDiv.slothifyData.blurImg.style.left = img.offsetLeft + 'px'; 34 | 35 | // update slowload div 36 | slowloadDiv.slothifyData.blurImg.style.clip = 'rect(' + newTopClipBlur + 'px auto auto auto)'; 37 | 38 | slowloadDiv.slothifyData.blurImageTopClip = newTopClipBlur; 39 | } 40 | 41 | // check stopping conditions 42 | var maxImageHeightBlur = img.height * args.loadMaxPercent; 43 | 44 | if (newTopClipBlur < maxImageHeightBlur) { 45 | progressiveJPEGInProgress = true; 46 | } 47 | } 48 | 49 | if (!img.complete) { 50 | setTimeout(slowloadModiferCallback(slowloadDiv, args), args.loadSpeed); 51 | } else if (typeof img.naturalHeight !== "undefined" && img.naturalWidth === 0) { 52 | setTimeout(slowloadModiferCallback(slowloadDiv, args), args.loadSpeed); 53 | } else if (!maxImageHeight || maxImageHeight === 0 || newTopClip < maxImageHeight || progressiveJPEGInProgress) { 54 | // create new update timeout 55 | slowloadDiv.slothifyData.imageTopClip = newTopClip; 56 | setTimeout(slowloadModiferCallback(slowloadDiv, args), args.loadSpeed); 57 | } 58 | })(slowloadDiv, args); 59 | }; 60 | }; 61 | 62 | var prepare = function () { 63 | // hide images so image doesn't show up before box 64 | var imgs = document.getElementsByTagName('img'); 65 | for(var i = 0; i < imgs.length; i++) { 66 | var img = imgs[i]; 67 | img.style.visibility = 'hidden'; 68 | } 69 | }; 70 | 71 | var slowImages = function (args) { 72 | return function () { 73 | 74 | var params = { 75 | // elements affected 76 | elements: args.elements || document.querySelectorAll('img:not([class="progressiveJPEGemulator"])'), 77 | boxColor: args.boxColor || '#000000', // color of box overlay 78 | loadMaxPercent: args.loadMaxPercent || 0.0, // max percentage to load images 79 | loadSpeed: args.loadSpeed || 500, // how often in ms to pass 80 | randLoadIncrement: args.randLoadIncrement || false, // true to randomize load increment 81 | loadIncrement: args.loadIncrement || 1, // pixels to load per pass 82 | randomPause: args.randomPause || 0.0, // probability of skipping a pass 83 | progressiveJPEG: args.progressiveJPEG || false // enable progressive JPEG emulation 84 | }; 85 | 86 | // make 'em load slow 87 | for(var i = 0; i < params.elements.length; i++) { 88 | // get some things we need 89 | var img = params.elements[i], 90 | parent = img.parentNode, 91 | slowload = document.createElement('DIV'); 92 | 93 | // set up initial state of box 94 | slowload.style.backgroundColor = params.boxColor; 95 | slowload.style.width = img.offsetWidth + 'px'; 96 | slowload.style.height = img.offsetHeight + 'px'; 97 | slowload.style.position = 'absolute'; 98 | slowload.style.top = img.offsetTop + 'px'; 99 | slowload.style.left = img.offsetLeft + 'px'; 100 | slowload.style.clip = 'rect(0 auto auto auto)'; 101 | 102 | // remember what the max height should be for later calculation 103 | slowload.slothifyData = { 104 | img: img, 105 | imageTopClip: 0, 106 | maxImageHeight: img.height * params.loadMaxPercent 107 | }; 108 | 109 | // setup the blurred image for progressive JPEG if needed 110 | if (params.progressiveJPEG === true) { 111 | var progressiveJPEGdiv = document.createElement('DIV'); 112 | progressiveJPEGdiv.style.backgroundColor = params.boxColor; 113 | progressiveJPEGdiv.style.width = img.offsetWidth + 'px'; 114 | progressiveJPEGdiv.style.height = img.offsetHeight + 'px'; 115 | progressiveJPEGdiv.style.position = 'absolute'; 116 | progressiveJPEGdiv.style.top = img.offsetTop + 'px'; 117 | progressiveJPEGdiv.style.left = img.offsetLeft + 'px'; 118 | progressiveJPEGdiv.style.clip = 'rect(0 auto auto auto)'; 119 | progressiveJPEGdiv.style.overflow = 'hidden'; 120 | 121 | var progressiveJPEGimg = document.createElement('IMG'); 122 | progressiveJPEGimg.setAttribute('class','progressiveJPEGemulator'); 123 | progressiveJPEGimg.setAttribute('src',img.src); 124 | progressiveJPEGimg.setAttribute('style','margin: -2px 0 0 0; -webkit-filter: blur(5px); -moz-filter: blur(5px); -o-filter: blur(5px); -ms-filter: blur(5px); filter: blur(5px);'); 125 | progressiveJPEGimg.setAttribute('width', progressiveJPEGdiv.style.width); 126 | progressiveJPEGimg.setAttribute('height', progressiveJPEGdiv.style.height); 127 | progressiveJPEGdiv.appendChild(progressiveJPEGimg); 128 | parent.appendChild(progressiveJPEGdiv); 129 | 130 | slowload.slothifyData.blurImg = progressiveJPEGdiv; 131 | slowload.slothifyData.blurImageTopClip = 0; 132 | } 133 | 134 | // put box over image 135 | parent.appendChild(slowload); 136 | 137 | // show image again 138 | img.style.visibility = 'visible'; 139 | 140 | if (params.loadMaxPercent > 0.0) { 141 | 142 | // allow for some changing of params per image 143 | var modParamPerImg = Object.create(params); 144 | if(modParamPerImg.randLoadIncrement) { 145 | // randomize load increment 146 | modParamPerImg.loadIncrement = Math.floor((Math.random() * 20) + 1); 147 | } 148 | 149 | // slowload using timeout since this is nicer to the browser :) 150 | setTimeout(slowloadModiferCallback(slowload, modParamPerImg), params.loadSpeed); 151 | } 152 | } 153 | }; 154 | }; 155 | 156 | return { 157 | letsPrepareTheseImages: prepare, 158 | fixMyImagesLoadingSoFast: slowImages 159 | }; 160 | 161 | })(); 162 | -------------------------------------------------------------------------------- /example/baby-sloth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theonion/comcastifyjs/369b5a36306c577ab6fce0789286e06a79c5d3e5/example/baby-sloth.jpg -------------------------------------------------------------------------------- /example/example-progressivejpeg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | comcastify.js - Sometimes images just load too damned fast! 5 | 6 | 7 | 8 | 9 | 10 |
11 | http://violetadams.deviantart.com/art/Baby-sloth-385183627 12 |
13 | 14 |
15 | http://mashable.com/2013/07/20/sloth-makeover/ 16 |
17 | 18 |
19 | http://mashable.com/2013/07/20/sloth-makeover/ 20 |
21 | 22 |
23 | http://www.wisegeek.com/what-are-the-main-components-of-a-sloth-diet.htm#sloth-in-tree-showing-claws 24 |
25 | 26 | 27 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/example-random.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | comcastify.js - Sometimes images just load too damned fast! 5 | 6 | 7 | 8 | 9 | 10 |
11 | http://violetadams.deviantart.com/art/Baby-sloth-385183627 12 |
13 | 14 |
15 | http://mashable.com/2013/07/20/sloth-makeover/ 16 |
17 | 18 |
19 | http://mashable.com/2013/07/20/sloth-makeover/ 20 |
21 | 22 |
23 | http://www.wisegeek.com/what-are-the-main-components-of-a-sloth-diet.htm#sloth-in-tree-showing-claws 24 |
25 | 26 | 27 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example/example-randompause.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | comcastify.js - Sometimes images just load too damned fast! 5 | 6 | 7 | 8 | 9 | 10 |
11 | http://violetadams.deviantart.com/art/Baby-sloth-385183627 12 |
13 | 14 |
15 | http://mashable.com/2013/07/20/sloth-makeover/ 16 |
17 | 18 |
19 | http://mashable.com/2013/07/20/sloth-makeover/ 20 |
21 | 22 |
23 | http://www.wisegeek.com/what-are-the-main-components-of-a-sloth-diet.htm#sloth-in-tree-showing-claws 24 |
25 | 26 | 27 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | comcastify.js - Sometimes images just load too damned fast! 5 | 6 | 7 | 8 | 9 | 10 |
11 | http://violetadams.deviantart.com/art/Baby-sloth-385183627 12 |
13 | 14 |
15 | http://mashable.com/2013/07/20/sloth-makeover/ 16 |
17 | 18 |
19 | http://mashable.com/2013/07/20/sloth-makeover/ 20 |
21 | 22 |
23 | http://www.wisegeek.com/what-are-the-main-components-of-a-sloth-diet.htm#sloth-in-tree-showing-claws 24 |
25 | 26 | 27 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example/sloth-close-up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theonion/comcastifyjs/369b5a36306c577ab6fce0789286e06a79c5d3e5/example/sloth-close-up.jpg -------------------------------------------------------------------------------- /example/sloth-hanging.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theonion/comcastifyjs/369b5a36306c577ab6fce0789286e06a79c5d3e5/example/sloth-hanging.jpg -------------------------------------------------------------------------------- /example/sloth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theonion/comcastifyjs/369b5a36306c577ab6fce0789286e06a79c5d3e5/example/sloth.jpg --------------------------------------------------------------------------------