Heavy image(very large image) loading effect - javascript

I have a problem want to share with you.
So here it is. Imagine I have a very large image and it take a heavy loading when I open my page. Is it possible if I want to have the effect like cut the image to many smaller pieces and merge them one by one while the image is loading(just javascript, jquery, css and html code).
html:
<div>
<div style="float:left; width: 200px; height: 200px;">
<img id="imgHeavy" src="http://i.stack.imgur.com/kLQe4.png" width="200"/>
</div>
<div id="frameMerge" style="float:left; width: 200px; height:200px; background: #ddd;">
</div>
</div>
So now I want to set the background of my element(#frameMerge) is every single pieces of the image(#imgHeavy) that have been cut when the page is opened.
Please take a look at 2 pictures!
My img:
My div element:
Any idea would be appreciated!

You can use the functionality of multiple background images provided by css3, but it won't be faster in the end as the data being loaded with multiple pictures is even bigger (header-information of every single file) than with just one. The only difference would be, that you see parts of the image before the rest is loaded. But you can have the same effect if your image is a jpg. So you can use a progressive jpg that will show parts of your image while the rest is still loading.

You can do it with CSS3 and jquery.
Here is an example for you :
jsfiddle.net/elclanrs/4nsJE/
;(function( $, window ) {
var _defaults = {
x : 2, // number of tiles in x axis
y : 2, // number of tiles in y axis
random : true, // animate tiles in random order
speed : 2000 // time to clear all times
};
/**
* range Get an array of numbers within a range
* #param min {number} Lowest number in array
* #param max {number} Highest number in array
* #param rand {bool} Shuffle array
* #return {array}
*/
function range( min, max, rand ) {
var arr = ( new Array( ++max - min ) )
.join('.').split('.')
.map(function( v,i ){ return min + i })
return rand
? arr.map(function( v ) { return [ Math.random(), v ] })
.sort().map(function( v ) { return v[ 1 ] })
: arr
}
// Prevent css3 transitions on load
$('body').addClass('css3-preload')
$( window ).load(function(){ $('body').removeClass('css3-preload') })
$.fn.sliced = function( options ) {
var o = $.extend( {}, _defaults, options );
return this.each(function() {
var $container = $(this);
/*---------------------------------
* Make the tiles:
---------------------------------*/
var width = $container.width(),
height = $container.height(),
$img = $container.find('img'),
n_tiles = o.x * o.y,
tiles = [], $tiles;
for ( var i = 0; i < n_tiles; i++ ) {
tiles.push('<div class="tile"/>');
}
$tiles = $( tiles.join('') );
// Hide original image and insert tiles in DOM
$img.hide().after( $tiles );
// Set background
$tiles.css({
width: width / o.x,
height: height / o.y,
backgroundImage: 'url('+ $img.attr('src') +')'
});
// Adjust position
$tiles.each(function() {
var pos = $(this).position();
$(this).css( 'backgroundPosition', -pos.left +'px '+ -pos.top +'px' );
});
/*---------------------------------
* Animate the tiles:
---------------------------------*/
var tilesArr = range( 0, n_tiles, o.random ),
tileSpeed = o.speed / n_tiles; // time to clear a single tile
// Public method
$container.on( 'animate', function() {
tilesArr.forEach(function( tile, i ) {
setTimeout(function(){
$tiles.eq( tile ).toggleClass( 'tile-animated' );
}, i * tileSpeed );
});
});
});
};
}( jQuery, window ));
$('.sliced').sliced({ x: 6, y: 4, speed: 1000 });
$('button').click(function() {
$('.sliced').trigger('animate');
});

Of course you can just put an onload event on every segment (must be on <img> though) that makes it fade in. However, actually splitting the image into segments cannot be done on client side. You will need to either manually split the image beforehand or rely on server side scripting (e.g. php) to do this.
Also, do note that doing this will create quite a lot of overhead depending on the amount of segments you use, since every segment will need to make a new request to the server including downloading the file headers for every image.

Related

Calculate div number with distance

I'm making a carousel like a casino roulette but i can't find the way to know which div number is when i make the animation. I'm trying to calculate by distance when i make the animation loop but i doesn't work
Here's my example
https://codepen.io/anon/pen/xXbpJr?page=1&
var giftamount = 10;
var gw = $('.gift').outerWidth(true);
var giftcenter = gw/2;
var cycle = 7;
var containercenter = $('.boxwrapper').outerWidth(true)/2;
for(var i = 0; i <=5; i++)
{
var giftduplicate = $('.giftwrapper').children().clone(true,true);
$('.giftwrapper').append(giftduplicate);
}
$('.button').click(function(){
var btn = $(this);
btn.hide();
var randomgift = Math.floor((Math.random() * 10) + 1);
var distance = giftamount * gw * cycle + containercenter + (randomgift*gw) - giftcenter;
console.log(distance);
$( ".giftwrapper" ).css({left: "0"});
$('.giftwrapper').animate({left: "-="+distance},10000,function(){
alert('You Won Gift' + randomgift);
btn.show();
});
});
i get the wrong number of div, i tried a lot of combination but it doesn't work
You can try and substitute this for the distance
var distance = giftamount * cycle * gw + (randomgift*gw) - containercenter -24;
The idea is the following: with distance=- containercenter; you would move to be left-aligned with the center of the container.
To that you add a certain number of cycles giftamount * cycle * gw and finally a random number of gift elements ((randomgift*gw)).
I could not figure out where the constant -24 comes from. I hard-coded and it needs to be better defined but I guess it might depend on some margins/approximations/jQuery/CSS/??
Now you should see that the animation always stops at the same point within the gift element (in the middle). To add a random deviation you could ad a small deviation dev (that lets you stay within the gift element) like this:
var dev = Math.random()*(giftcenter+1);
var distance = giftamount * cycle * gw + (randomgift*gw) - containercenter -24 +dev;
Updated demo: https://codepen.io/anon/pen/RLNeBX
If you want to get the prize that is underneath the pointer (the vertical red bar), you actually do not have to compute the distance. Instead, you can make use of a really handy but somewhat less known DOM API method known as elementFromPoint(x, y), where you can obtain a reference to the topmost DOM node under the x,y coordinate of the page.
In order for this to work, x and y will have to correspond to the visual center of the pointer, which can we can simply calculate by using:
var $pointer = $('.rafflebox .pointer');
var pointerX = $pointer.offset().left + $pointer.width() * 0.5;
var pointerY = $pointer.offset().top + $pointer.height() * 0.5;
In jQuery's animation callback, you simply can retrieve the element (aka the prize) underneath this coordinate:
// Hide pointer first, otherwise it will be returned as the topmost element
$pointer.hide();
// Get element from pointer's visual center
var prize = document.elementFromPoint(pointerX, pointerY);
// Show it again
$pointer.show();
Now you have the correct reference to the DOM node, it is up to you to decide what kind of metadata you want to store in the "prize" DOM node. For example, you can embed a HTML5 data- attribute in your HAML:
%img{:src => "http://placehold.it/125x125?text=Prize+#{i}", :data => {:prize => "Prize #{i}"}}
...which simply stores the text Prize (n) (where n is the prize number) in the attribute data-prize, and we can access it later using:
var prize = document.elementFromPoint(pointerX, pointerY);
console.log($(prize).data('prize'));
When we replace part of your code with what I have suggested, you get this:
// Get visual center of pointer
var $pointer = $('.rafflebox .pointer');
var pointerX = $pointer.offset().left + $pointer.width() * 0.5;
var pointerY = $pointer.offset().top + $pointer.height() * 0.5;
$( ".giftwrapper" ).css({left: "0"});
$('.giftwrapper').animate({left: "-="+distance},10000,function(){
// Hide pointer first, otherwise it will be returned as the topmost element
$pointer.hide();
// Get element from pointer's visual center
var prize = document.elementFromPoint(pointerX, pointerY);
// Show it again
$pointer.show();
alert('You Won Gift ' + $(prize).data('prize'));
btn.show();
});
Here is your updated pen with a working example: https://codepen.io/terrymun/pen/dVPdMg
Updated example
There is a very small chance that the pointer will land in between prizes. To prevent this, you will want to use padding instead of margin on the .gift element:
.gift {
// Change margin to padding
padding: 0px 4px;
}
...and perform additional checks on the returned prize node:
// Hide pointer first, otherwise it will be returned as the topmost element
$pointer.hide();
// Get element from pointer's visual center
var $prize = $(document.elementFromPoint(pointerX, pointerY));
// If prize lands on the .gift element instead
if(!$prize.is('img'))
$prize = $prize.find('img')
// Show it again
$pointer.show();
alert('You Won Gift' + $prize.data('prize'));
btn.show();
The pen here is simply a fork of the original solution, but with exaggerated horizontal padding to increase the chance of the pointer landing in between iamges: https://codepen.io/terrymun/pen/rGaJmY

My script for page loading bar, returns differently everytime of F5

I got a free source progress bar, and I wrote a script for it.
the script is here,
var nanobar = new Nanobar( options );
var loaded = 0;
var number_of_media = $("body img").length;
doProgress();
// function for the progress bar
function doProgress() {
$("img").load(function() {
loaded++;
var newWidthPercentage = (loaded / number_of_media) * 100;
nanobar.go(newWidthPercentage);
document.getElementById("showing").innerHTML = newWidthPercentage;
})
};
});
This. I think,
Loaded <-- (which gets + 1 every time an image finished loaded)
divided by
Number of total body images,,
and then multiplied by 100
So that this can make the percentage number of loading process.
Then I put that percentage number into the box of,
A Loading bar's destination point. (which is : nanobar.go( here ))
But the bar moves werid,
everytime I click the menu, it returns different.
so I made a box to display the percentage number ( in the red box you can see in the picture )
I don't understand how this kind of random numbers are coming out every time.
Please advice.
Consider....
6/7 = 0.8571428571;
0.8571428571 * 100 = 85.71428571;
So if you want to 'tidy' these long decimals, then you need to truncate the float. http://www.w3schools.com/jsref/jsref_tofixed.asp
var num = 0.8571428571 * 100;
var n = num.toFixed(2);
Then n == 85.71
I hope this helps.

About image rotation once element with specific id is clicked

Logo and elements from ul once clicked rotates image. By default image is already rotated by certain degrees, then on each click image rotates to necessary value.
So far I was using the following:
$("#objRotates").css('opacity','.2');
var value = 0;
var prev_value = 0;
$( "li" ).click(function() {
var text=$(this).text();
if(text==="text1"){value=0;}
if(text==="text2"){value=33;}
if(text==="text3"){value=66;}
if(prev_value != value){
$("#objRotates").animate({opacity:'1'});
$("#objRotates").rotate({
animateTo:value,
easing: $.easing.easeInOutExpo,
center: ["25px", "150px"],
callback: function(){$("#objRotates").animate({opacity:'0.2'});}
});
}
prev_value = value;
});
Above code is the one that was used before, where images start position was 0 and its animation was triggered from link text.
Using jqueryRotate.js examples(here)
How do I change the code, so that images start position is certain degrees and animation starts if element with specific ID is clicked?
Give at least clue..Cause for now, looking at my old code, I am lost. Thanks in advance.
SIMPLIFIED FIDDLE
Ok, so I've created a couple of samples for you to check out. The first one is very basic and I've simplified the code a little to make it easier to understand. This one just uses completely static values and a static elementId for the event, which I'm pretty sure answers your question based on your response to my comment yesterday. http://jsfiddle.net/x9ja7/594/
$("#elementId").click(function () {
var startingAngle = 45;
var endingAngle = 90;
var elementToRotate = "img";
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
});
});
But I wanted to give another example as well that would be dynamic and repeatable for multiple elements. With the code above, you would have to copy/paste the same code over and over again if you want to perform this animation by clicking different elements. Here's an alternative. In this example, you set all of your parameters in the data attributes in the clickable element, then the function is completely repeatable, you only have to write it once. Less code = everyone happy! Here's the example: http://jsfiddle.net/x9ja7/595/
//#region Default starting angles
$("#image1").rotate({ angle: 90 });
$("#image2").rotate({ angle: 20 });
//#endregion
$(".rotateAction").click(function () {
//#region Optional parameter - used in the optional callback function
var $self = $(this);
//#endregion
var startingAngle = Number($(this).attr("data-startingangle"));
var endingAngle = Number($(this).attr("data-endingangle"));
var elementToRotate = $(this).attr("data-elementtorotate");
//#region If the current angle is the ending angle, reverse the animation - this can be removed if you want, I thought it may be cool to show some of the things you can do with this.
var currentAngle = $(elementToRotate).getRotateAngle();
if ( currentAngle[0] === endingAngle) {
startingAngle = Number($(this).attr("data-endingangle"));
endingAngle = Number($(this).attr("data-startingangle"));
}
//#endregion
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
//#region This is optional - uncommenting this code would make the animation single-use only
//, callback: function () { $self.off().removeClass("clickable"); }
//#endregion
});
});
Hope this helps. If you need any other assistance, please let me know.

Change the style of selected objects in fabric.js

If u look at this Fiddle
When i click #uploadImage button it adds the images randomly to the #html2canvas div.
Now what i want is to select a specific object after adding many and then click the #grayscale
button to change the object only with the selected area to turn grayscale . is this possible using fabric.js or i have to change loyality ?
HTML
<div id="html2canvas">
<canvas id="c"></canvas>
</div>
<img src="http://i.imgur.com/tEpBeQV.jpg" height="50" width="50" id="my-img">
<button class="deepblue-button" id="uploadImage">Upload</button>
<button id="grayscale">GrayScale</button>
JavaFabric SCRIPT
var canvas = new fabric.Canvas('c');
canvas.setWidth(640);
canvas.setHeight(480);
var img = document.getElementById("my-img");
var upload = document.getElementById("uploadImage");
upload.addEventListener('click',uploadI,false);
function uploadI() {
canvas.add(new fabric.Image(img, {
left: Math.floor(Math.random() * 400) + 100,
top: Math.floor(Math.random() * 250) + 200,
width: 100,
height: 100
}));
}
UPDATE
This Fiddle ("Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data." presumably because of JSfiddle) did the trick but if i am selecting multiple objects and then changing the grayscale it wont work . This only applies for one and only one object selected but not multiple . Therefore anyone with a better answer ?
Sorry I misunderstood your question. My previous fiddle indeed only changes the color of one object (the selected, active object).
If you want to have all objects grayscaled at the same time, you could push them into an array, then loop over that array to change their properties, and finally, render all of them.
var allImages = [],
greyscale = document.getElementById('grayscale');
greyscale.addEventListener('click', function() {
var filter = new fabric.Image.filters.Grayscale();
// loop over all indexes in allImages array
for ( var i = 0; i < allImages.length; i++ ) {
allImages[i].filters.push(filter);
allImages[i].applyFilters(canvas.renderAll.bind(canvas));
// NB: don't know if this can be done out of the loop?
}
}, false);
function uploadI() {
var obj = new fabric.Image(img, {
left: Math.floor(Math.random() * 400) + 100,
top: Math.floor(Math.random() * 250) + 200,
width: 100,
height: 100
});
// now last image added to array is at index allImages[allImages.length-1]
allImages.push(obj);
// now add it to the canvas
canvas.add(allImages[allImages.length-1]);
}
NB / Disclaimer: I am not an expert in fabric.js, and although this may work, there may be better methods of doing this, eg see fabric.Collection, however documentation is hard to find so I hope this helps.
NB: Again wasn't able to test if it works because of the jsfiddle restrictions

Change HTML Background randomly on page refresh

I know this topic has been looked at loads of times, but I would like my home page to randomly select an image and then change the subtitle for that image. The URL for my site is: http://www.connorloughlin.com
At the bottom of the page is a little subtitle, would be great if it changed for the relevant background. If it's too complex I won't bother but thought it'd look good! Preferably i'd have 5 images each with their own subtitle.
Let me know if you want me to clarify anything and thanks in advance!
Since you're using jQuery, I've made a version using that: http://jsbin.com/OQugAMI/4/edit
1) create an Array containing the list of images & subtitles
var backgrounds = [
{ image: 'http://www.connorloughlin.com/images/background.jpg',
subtitle: 'Looking out at Carcassonne, France - August 2013'
},
{ image: 'http://upload.wikimedia.org/wikipedia/commons/1/13/1632x1224_sertaoe_2_rio_grande_do_norte_landscape_panorama_brasil.jpg',
subtitle: 'Version 2'
},
{ image: 'http://upload.wikimedia.org/wikipedia/commons/7/71/1632x1224_sertaoe_rio_grande_do_norte_landscape_panorama_brasil.jpg',
subtitle: 'Version 3'
}
];
2) select a random image from that array
/**
* Returns a random integer between min and max
* Using Math.round() will give you a non-uniform distribution!
* http://stackoverflow.com/questions/1527803/generating-random-numbers-in-javascript-in-a-specific-range
*/
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
$(document).ready(function(){
var bgNumber = getRandomInt(0, backgrounds.length-1);
}
3) update the H4 & body CSS to reflect the choice
$('body').css('background-image', 'url('+backgrounds[bgNumber].image+')');
$('h4').html(backgrounds[bgNumber].subtitle);
This will pick a new image & subtitle on each page load
The following is in JQuery:
Just name each of your images bg1 or bg2
// On Page Load
backgroundSelect();
function backgroundSelect(){
var sub1 = "this is my subtitle"
var numImgs = 5; // The Number of images you have total.
var select = Math.round(Math.random() * numImgs) + 1; // add one so not zero based.
$('body').css('background-image', 'bg' + select);
$('subtitle_element').replaceWith(sub1);
}
This is not the cleanest and most semantic way to write your code. But hopefully it will get you started in the right direction.
The simplest way, in plain JavaScript:
var images = [
{
subtitle : 'Subtitle text for image one...',
src : 'http://placekitten.com/1000/1000'
},
{
subtitle : 'Subtitle text for image two...',
src : 'http://lorempixel.com/1000/1000/people/'
},
{
subtitle : 'Subtitle text for image three...',
src : 'http://lorempixel.com/1000/1000/nightlife/'
},
{
subtitle : 'Subtitle text for image four...',
src : 'http://lorempixel.com/1000/1000/nature/'
}
];
function setBackground (images) {
// generates a random integer between 0 and the length of the supplied array:
var n = Math.floor(Math.random() * images.length),
// works out whether to use the 'textContent' or 'innerText' property:
textProperty = 'textContent' in document ? 'textContent' : 'innerText';
// sets the background-image of the 'body' element:
document.body.style.backgroundImage = 'url(' + images[n].src + ')';
// sets the text of the relevant subtitle element:
document.getElementById('subtitleElementID')[textProperty] = images[n].subtitle;
}
setBackground(images);
JS Fiddle demo.
Or, if you'd rather change the background every n milliseconds, you could add the following:
window.setInterval(function(){
setBackground(images)
}, 5000);
JS Fiddle demo.
Which, obviously, will change the image (and subtitle) every 5000 milliseconds.

Categories

Resources