1/** 2 * Background Image v2.0 3 * 4 * Plugin for controlling the display of background images 5 * with content over top. 6 * 7 * Example usage: 8 * $(".bgimg").backgroundimage(); 9 * 10 * Html usage: 11 * <div class="bgimg"> 12 * <img/> 13 * <div></div> 14 * </div> 15 * 16 * Copyright 2017 Josh Tere <[email protected]> 17 * Released under the MIT License 18 * http://www.joshtere.com 19 */ 20 21 22(function($, window, document, undefined) { 23 "use strict"; 24 25 // 26 var pluginName = "backgroundimage"; 27 28 // Debug mode 29 var debugMode = false; 30 31 // 32 function Plugin(element, options) { 33 34 // 35 this.settings = $.extend(true,{},defaults,options); 36 37 // 38 this.element = $(element); 39 this.$elem = $(this.element); 40 41 // 42 this.$window = $(window); 43 44 // 45 var $this = this; 46 47 // 48 function animation_frame() { 49 // 50 if($this.settings.lastPosition === window.pageYOffset) { 51 52 // Avoid overcalculations 53 animateFrame(animation_frame); 54 return false; 55 } 56 else { 57 $this.settings.lastPosition = window.pageYOffset; 58 } 59 60 $this.move($this,false); 61 62 animateFrame(animation_frame); 63 64 //console.log("Animate"); 65 } 66 67 // 68 function move_on_resize() { 69 70 $this.settings.viewportWidth = window.innerWidth; 71 $this.settings.viewportHeight = window.innerHeight; 72 $this.settings.scrollTop = $(window).scrollTop(); 73 74 // Adjust background image sizes 75 $this.resize($this,false); 76 77 // Move background images 78 $this.move($this,false); 79 80 //console.log("Resize"); 81 } 82 83 // 84 function move_on_scroll() { 85 86 $this.move($this,false); 87 88 //console.log("Scroll"); 89 } 90 91 if($.throttle) { 92 // Run functions during resize 93 this.$window.resize($.throttle(250,move_on_resize)); 94 95 // Run functions during scroll 96 this.$window.scroll($.throttle(20,move_on_scroll)); 97 } 98 else { 99 // Run functions during resize 100 this.$window.resize(move_on_resize); 101 102 // Run functions during scroll 103 this.$window.scroll(move_on_scroll); 104 } 105 106 // Start frame animation 107 animation_frame(); 108 109 // 110 this.init(); 111 } 112 113 // Animation frame 114 var animateFrame = window.requestAnimationFrame || 115 window.webkitRequestAnimationFrame || 116 window.mozRequestAnimationFrame || 117 window.msRequestAnimationFrame || 118 window.oRequestAnimationFrame || 119 function(callback){setTimeout(callback,1000/60);}; 120 121 // Set transform property 122 var transformProp = window.transformProp || (function() { 123 var testEl = document.createElement('div'); 124 if(testEl.style.transform === null) { 125 var vendors = ['Webkit', 'Moz', 'ms']; 126 for(var vendor in vendors) { 127 if(testEl.style[ vendors[vendor] + 'Transform' ] !== undefined) { 128 return vendors[vendor] + 'Transform'; 129 } 130 } 131 } 132 return 'transform'; 133 })(); 134 135 // Set item count 136 var itemCount = 0; 137 138 // Default options 139 var defaults = { 140 141 // 142 top : 0, 143 144 // 145 height : 0, 146 147 // Parallax scroll value 148 parallaxSpeed : 0.5, 149 150 // Minumum effects width 151 effectsCutoff : 720, 152 153 // Fade speed 154 fadeSpeed : 10, 155 156 // Scale speed 157 scaleSpeed : 5, 158 159 // Scroll interval 160 scrollInterval : 1, 161 162 // Last scroll position 163 lastPosition : -1, 164 165 // Viewport width and height 166 viewportWidth : window.innerWidth, 167 viewportHeight : window.innerHeight, 168 169 // Distance from top 170 scrollTop : $(window).scrollTop(), 171 172 // Browser 173 browser : browser(), 174 175 // Complete callback 176 complete : function() { 177 178 }, 179 }; 180 181 // 182 Plugin.prototype = { 183 184 // Update backgrounds 185 update: function() { 186 187 // Move background images 188 this.move(this,true); 189 190 // Adjust background image sizes 191 this.resize(this,true); 192 193 //console.log("Updated"); 194 }, 195 196 // Move background 197 move : function(el,setup) { 198 199 // No parallax on edge 200 if(!setup && (this.settings.browser === "IE" || this.settings.browser === "Edge")) { 201 return; 202 } 203 204 // Check for element height 205 if(this.settings.height <= 0) { 206 // 207 this.settings.top = this.$elem.offset().top; 208 this.settings.height = this.$elem.height(); 209 } 210 211 this.settings.scrollTop = this.$window.scrollTop(); 212 213 // Set visible flag to false 214 var visible = false;
215 216 // Check container in viewport 217 if(this.settings.scrollTop+this.settings.viewportHeight+50 > this.settings.top && 218 this.settings.scrollTop <= this.settings.top+this.settings.height) { 219 220 // 221 visible = true; 222 //console.log("Visible"); 223 } 224 225 // If slide, check visible 226 if(this.slide && this.$elem.css('opacity') == 0) { 227 visible = false; 228 } 229 230 // Run all on setup 231 if(setup) {visible = true;} 232 233 // If container is visible 234 if(visible) { 235 236 // Get container top 237 var containerTop = (this.settings.top-this.settings.scrollTop); 238 239 /*var percentageY = (this.settings.scrollTop - this.settings.top / this.settings.viewportHeight)*(this.settings.height - this.settings.viewportHeight); 240 var valueX = (this.settings.parallaxSpeed * (100 * (1 - percentageY))); 241 valueX = Math.round(valueX * 100) / 100; 242 valueX = Math.round((containerTop*this.settings.parallaxSpeed)*-1); // this.settings.parallaxSpeed*/ 243 244 // Move image 245 if(this.$image) { 246 247 /*var yE = containerTop; 248 var hV = this.settings.viewportHeight; 249 var hE = this.settings.height; 250 var hB = this.$image.height(); 251 252 var yB = ((yE)/(hV))*(hE-hB);*/ 253 //console.log(containerTop); 254 //valueX = yB; 255 256 // Get effects
257 var effects = this.imageEffects; 258 effects = (effects === undefined) ? '' : effects; 259 260 if(effects !== '') { 261 262 // Set offset 263 var newOffset = (effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? Math.round((containerTop*this.settings.parallaxSpeed)*-1) : 0; 264 265 // Set opacity 266 var opacity = (effects.indexOf('fade') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? 1-(((containerTop*(this.settings.fadeSpeed/100))/100)*-1) : 1; 267 opacity = (opacity > 1) ? 1 : opacity; 268 269 // Set scale 270 var scale = (effects.indexOf('expand') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? 1+(((containerTop*(this.settings.scaleSpeed/100))/100)*-1) : 1; 271 scale = (scale < 1) ? 1 : scale; 272 273 // Update image 274 this.$image.css(transformProp,"translate3d(0px,"+newOffset+"px,0px) scale("+scale+")"); 275 this.$image.css("opacity",opacity); 276 } 277 } 278 279 // Move content 280 if(this.$content) { 281 282 // Get effects 283 var effects = this.contentEffects; 284 effects = (effects === undefined) ? '' : effects; 285 286 if(effects !== '') { 287 // Set offset 288 var newOffset = (effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? Math.round((containerTop*this.settings.parallaxSpeed)*-1) : 0; 289 newOffset = (containerTop > 0) ? 0 : newOffset; 290 291 // Set opacity 292 opacity = (effects.indexOf('fade') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? 1-(((containerTop*((this.settings.fadeSpeed+5)/100))/100)*-1) : 1; 293 opacity = (opacity > 1) ? 1 : opacity; 294 295 // Update content 296 this.$content.css(transformProp,"translate3d(0px,"+newOffset+"px,0px)"); 297 this.$content.css("opacity",opacity); 298 } 299 } 300 301 if(debugMode) { 302 if(this.$content) { 303 $("#"+this.id+"-top-tag").css('top',this.settings.top+'px'); 304 $("#"+this.id+"-bottom-tag").css('top',this.settings.top+this.settings.height+'px'); 305 } 306 307 if(this.$image) { 308 $("#"+this.id+"-image-top-tag").css('top',this.$image.offset().top+'px'); 309 $("#"+this.id+"-image-bottom-tag").css('top',((this.$image.offset().top+this.$image.height()))+'px'); 310 } 311 } 312 } 313 314 //console.log("Move"); 315 }, 316 317 // Adjust background image sizes 318 resize : function(setup) { 319 320 // Check for element height 321 this.settings.top = this.$elem.offset().top; 322 this.settings.height = this.$elem.height(); 323 324 // Set width and height 325 { 326 // Set is contrained 327 var isConstrained = false; 328 329 // Get effects
330 var effects = this.imageEffects; 331 effects = (effects === undefined) ? '' : effects; 332 333 // If parallax then use full height/width 334 if(effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) { 335 336 var fullWidth = this.$elem.innerWidth(); 337 var fullHeight = this.$elem.innerHeight()*(1+this.settings.parallaxSpeed); 338 339 // Get site full width 340 var siteFullWidth = (this.$elem.innerWidth() > this.settings.viewportWidth) ? this.$elem.innerWidth() : this.settings.viewportWidth; 341 var siteFullHeight = (this.$elem.innerHeight() > this.settings.viewportHeight) ? this.$elem.innerHeight() : this.settings.viewportHeight; 342 343 // Overwrite width with full if needed 344 if(fullWidth+30 > siteFullWidth) {fullWidth = siteFullWidth;} 345 else {isConstrained = true;} 346 //if(fullHeight+30 > siteFullHeight) {fullHeight = siteFullHeight;} 347 } 348 349 // Else use container height/width 350 else { 351 var fullWidth = this.$elem.innerWidth();
352 var fullHeight = this.$elem.innerHeight(); 353 } 354 } 355 356 // Set dimensions 357 { 358 // Dimensions 359 var dimensions = this.$image.data("dimensions"); 360 dimensions = (dimensions === undefined) ? [0,0] : dimensions.split("x"); 361 362 // New dimensions 363 var newWidth = 0; 364 var newHeight = 0; 365 366 // Try to resize by width 367 newWidth = fullWidth; 368 newHeight = Math.ceil((newWidth/dimensions[0])*dimensions[1]); 369 370 // If height to short then resize by height 371 if(newHeight < fullHeight) { 372 // 373 newHeight = fullHeight; 374 newWidth = Math.ceil((newHeight/dimensions[1])*dimensions[0]); 375 } 376 } 377 378 379 // Set focal point 380 { 381 /* 382 Focal Point Difference 383 -- 384 The focal point difference is the amount the image needs to 385 move (left or right) before the focal point is centered. A positive 386 value should be aligned from the left and a negative value from 387 the right. An image should be moved to the right or left until 388 the focal point difference has been made up. 389 390 var fpd = (((imageWidth/2)-(imageWidth*fp))*2)*-1; 391 */ 392 393 // Focal points 394 var focalPoints = this.$image.data("focal-points"); 395 focalPoints = (focalPoints === undefined) ? [0.5,0.5] : focalPoints.split(","); 396 397 // New locations 398 var newTop = false; 399 var newLeft = false; 400 var newRight = false; 401 var newBottom = false; 402 403 // If width is greater than the viewport then set image focal point 404 if(newWidth > fullWidth) { 405 406 // Get focal point difference 407 var focalPointDifference = Math.ceil((((newWidth/2)-(newWidth*parseFloat(focalPoints[0])))*2)*-1); 408 409 // If focal point difference is greater than 0, move to left 410 if(focalPointDifference > 0) { 411 412 // If focal point difference is greater than amount to move, then move left 413 if(Math.ceil(newWidth-fullWidth) <= focalPointDifference) { 414 // Set left 415 newLeft = Math.ceil(newWidth-fullWidth)*-1; 416 newLeft = newLeft+'px'; 417 } 418 // If less than amount to move, then move left and center 419 else { 420 // Set left 421 newLeft = focalPointDifference; 422 newLeft += Math.ceil((Math.ceil(newWidth-fullWidth)-focalPointDifference)/2); 423 newLeft = newLeft*-1; 424 newLeft = newLeft+'px'; 425 } 426 427 // 428 newRight = 'auto'; 429 } 430 // If focal point difference is less than 0, move to right 431 else if(focalPointDifference < 0) { 432 433 // 434 focalPointDifference = focalPointDifference*-1; 435 436 // If focal point difference is greater than amount to move, then move right 437 if(Math.ceil(newWidth-fullWidth) <= focalPointDifference) { 438 // Set right 439 newRight = Math.ceil(newWidth-fullWidth)*-1; 440 newRight = newRight+'px'; 441 newLeft = 'auto'; 442 } 443 // If less than amount to move, then move right and center 444 else { 445 // Set right 446 newRight = focalPointDifference; 447 newRight += Math.ceil((Math.ceil(newWidth-fullWidth)-focalPointDifference)/2); 448 newRight = newRight*-1; 449 newRight = newRight+'px'; 450 newLeft = 'auto'; 451 } 452 } 453 // If focal point difference is 0 454 else { 455 // Set left 456 newLeft = Math.ceil((newWidth-fullWidth)/2); 457 newLeft = newLeft*-1; 458 newLeft = newLeft+'px'; 459 newRight = 'auto'; 460 } 461 } 462 else { 463 // Set left 464 newLeft = 0; 465 newRight = 'auto'; 466 } 467 468 469 // If height is greater than the viewport then set image focal point 470 if(newHeight > fullHeight) { 471 472 // Get focal point difference 473 var focalPointDifference = Math.ceil((((newHeight/2)-(newHeight*parseFloat(focalPoints[1])))*2)*-1); 474 475 // If focal point difference is greater than 0, move up 476 if(focalPointDifference > 0) { 477 478 // If focal point difference is greater than amount to move, then move up 479 if(Math.ceil(newHeight-fullHeight) <= focalPointDifference) { 480 // Set top 481 newTop = Math.ceil(newHeight-fullHeight)*-1; 482 newTop = newTop+'px'; 483 } 484 // If less than amount to move, then move up and center 485 else { 486 // Set left 487 newTop = focalPointDifference; 488 newTop += Math.ceil((Math.ceil(newHeight-fullHeight)-focalPointDifference)/2); 489 newTop = newTop*-1; 490 newTop = newTop+'px'; 491 } 492 493 // 494 newBottom = 'auto'; 495 } 496 // If focal point difference is less than 0, move down 497 else if(focalPointDifference < 0) { 498 499 // 500 focalPointDifference = focalPointDifference*-1; 501 502 // If focal point difference is greater than amount to move, then move down 503 if(Math.ceil(newHeight-fullHeight) <= focalPointDifference) { 504 // Set bottom
505 newBottom = Math.ceil(newHeight-fullHeight)*-1; 506 newBottom = newBottom+'px'; 507 newTop = 'auto'; 508 } 509 // If less than amount to move, then move down and center 510 else { 511 // Set bottom 512 newBottom = focalPointDifference; 513 newBottom += Math.ceil((Math.ceil(newHeight-fullHeight)-focalPointDifference)/2); 514 newBottom = newBottom*-1; 515 newBottom = newBottom+'px'; 516 newTop = 'auto'; 517 } 518 } 519 // If focal point difference is 0 520 else { 521 // Set top 522 newTop = Math.ceil((newHeight-fullHeight)/2); 523 newTop = newTop*-1; 524 525 // Hack for constrained parallax images 526 if(isConstrained && effects.indexOf('parallax') !== -1) { 527 newTop = newTop+50; 528 } 529 else if(effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) { 530 newTop = newTop+20; 531 } 532 533 newTop = newTop+'px'; 534 newBottom = 'auto'; 535 } 536 } 537 else { 538 // Set top 539 newTop = 0; 540 newBottom = 'auto'; 541 } 542 } 543 544 545 // Update image 546 { 547 this.$image.width(newWidth); 548 this.$image.height(newHeight); 549 550 // If top is set 551 if(newTop !== false) { 552 this.$image.css("top",""+newTop+""); 553 } 554 555 // If left is set 556 if(newLeft !== false) { 557 this.$image.css("left",""+newLeft+""); 558 } 559 560 // If right is set 561 if(newRight !== false) { 562 this.$image.css("right",""+newRight+""); 563 } 564 565 // If bottom is set 566 if(newBottom !== false) { 567 this.$image.css("bottom",""+newBottom+""); 568 } 569 } 570 571 //console.log("Resize"); 572 }, 573 574 init: function() { 575 576 // Add to item count 577 itemCount = itemCount+1; 578 579 // 580 var $this = this; 581 582 // Set item id 583 this.id = 'bgi-item-'+itemCount; 584 585 // Add background image classes to elements 586 this.$image = this.$elem.children("picture,img").first(); 587 this.$content = this.$elem.children("div").first(); 588 589 // Check if element is part of unslider 590 if(this.$elem.hasClass("sliderimg")) { 591 // 592 this.slide = true; 593 } 594 595 // Add class to container 596 this.$elem.addClass('backgroundimage-container'); 597 598 // Effects
599 this.imageEffects = this.$image.data("effect"); 600 this.contentEffects = this.$content.data("effect"); 601 602 if(this.settings.browser === "IE" || this.settings.browser === "Edge") { 603 604 this.imageEffects = ""; 605 this.contentEffects = ""; 606 } 607 608 // Wrap image 609 this.$image.css('display','block'); 610 this.$image.wrap('<div class="backgroundimage-image"></div>'); 611 612 // Add class to content 613 this.$content.addClass('backgroundimage-content'); 614 615 // Background image parameters 616 this.settings.top = this.$elem.offset().top; 617 this.settings.height = this.$elem.height(); 618 619 setTimeout(function() { 620 // 621 $this.settings.top = $this.$elem.offset().top; 622 $this.settings.height = $this.$elem.height(); 623 624 // Move background images 625 $this.move($this,true); 626 627 if(debugMode) { 628 $("html").append('<div id="'+$this.id+'-top-tag" class="top-tag" style="top:'+$this.settings.top+'px;"></div>'); 629 $("html").append('<div id="'+$this.id+'-bottom-tag" class="bottom-tag" style="top:'+($this.settings.top+$this.settings.height)+'px;"></div>'); 630 // 631 $("html").append('<div id="'+$this.id+'-image-top-tag" class="image-top-tag" style="top:'+$this.$image.offset().top+'px;"></div>'); 632 $("html").append('<div id="'+$this.id+'-image-bottom-tag" class="image-bottom-tag" style="top:'+($this.$image.offset().top+$this.$image.height())+'px;"></div>'); 633 } 634 },400); 635 636 //console.log(this.settings.top); 637 638 // Move background images 639 this.move(this,true); 640 641 // Adjust background image sizes 642 this.resize(this,true); 643 644 // Return element on complete 645 if($.isFunction(this.settings.complete)) { 646 // 647 this.settings.complete.call(this.$elem); 648 } 649 650 //console.log("Initialise"); 651 } 652 }; 653 654 // 655 $.fn[pluginName] = function(options) { 656 return this.each(function() { 657 658 // Check if there is an existing instance related to element 659 var instance = $.data(this, pluginName); 660 661 if(instance) { 662 if(typeof options === "string" && typeof instance[options] === "function") { 663 instance[options].apply(instance); 664 } 665 else if(options !== undefined) { 666 console.log('Method ' + options + ' does not exist on Plugin'); 667 } 668 } 669 else { 670 // Create the plugin 671 var plugin = new Plugin(this,options); 672 673 // Store the plugin instance on the element 674 $.data(this,pluginName,plugin); 675 } 676 }); 677 }; 678 679 // Basic browser detection 680 function browser() { 681 // 682 var browser = 'Other'; 683 var ua = window.navigator.userAgent; 684 var msie = ua.indexOf('MSIE '); 685 var trident = ua.indexOf('Trident/'); 686 var edge = ua.indexOf('Edge/'); 687 688 // IE 689 if(parseInt(msie) > 0 || parseInt(trident) > 0) { 690 // 691 browser = 'IE'; 692 } 693 // Edge 694 else if(parseInt(edge) > 0) { 695 // 696 browser = 'Edge'; 697 } 698 699 // 700 return browser; 701 } 702 703}(jQuery, window, document));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.