Setting up an array to handle size conditions - javascript

I've got the following code. I am working on an array. I found a javascript array instructions..if this is wrong, I'd love help to find out if there is a jQuery version of this.
My issue comes into play when I am trying to implement an if() and else if() conditions to the array. I am using i (variable) to count items in array.
It is saying that there is an issue on the line that reads else if(width <= Sizes[i]) { $(element).attr('src', 'images/' + Sizes[i] + '/' + name[name.length - 1]) }
Also, it appears that the array isn't working at all. Its pulling the default image.
I am probably doing this wrong. I am doing this trying to figure out how arrays work and implementing them into a code I already have. Can someone please help solve this? It isn't working. The code works perfectly without the array, so it is something in the array.
$(document).ready(function() {
window.onresize = resize;
function resize() {
var img = $('img.resizable');
var width = $(window).innerWidth();
var Sizes, sLength, i;
img.each(function(index, element) {
var name = element.src.split('/') // Split is a native javascript function, which 'splits' the string into an array with the components
Sizes = [2880, 1920, 1000, 600];
sLength = Sizes.length;
for (i = 0; i < sLength; i++) {
if (i == 0) {
if (width <= Sizes[i]) {
$(element).attr('src', 'images/' + Sizes[i] + '/' + name[name.length - 1])
}
}
if (i > 0) {
else if (width <= Sizes[i]) {
$(element).attr('src', 'images/' + Sizes[i] + '/' + name[name.length - 1])
}
}
} else {
$(element).attr('src', 'images/2880/' + name[name.length - 1])
}
})
}
resize();
});
The actual script I am trying to convert
$(document).ready(function() {
window.onresize = resize;
function resize() {
var img = $('img.resizable');
var width = $(window).innerWidth();
img.each(function(index, element) {
var name = element.src.split('/') // Split is a native javascript function, which 'splits' the string into an array with the components
if(width <= 600) {
$(element).attr('src', 'images/600/' + name[name.length - 1]) // This name[name.length -1] trick is being used to select the 'last value in the string' based on the length of the string.
}
else if(width <= 1000) {
$(element).attr('src', 'images/1000/' + name[name.length - 1])
}
else if(width <= 1920) {
$(element).attr('src', 'images/1920/' + name[name.length - 1])
}
else {
$(element).attr('src', 'images/2880/' + name[name.length - 1])
}
})
}
resize();
});

Here's a solution that simplifies matters by using Array#filter to select the appropriate width; the appropriate size will sit in the first position of the sizes array:
$(document).ready(function() {
window.onresize = resize;
resize();
});
function resize() {
// use $.each to iterate over each element
$('img.resizable').each(function(index, element) {
// get the image name directly
var name = element.src.substring(element.src.lastIndexOf('/'));
// let's whittle down sizes to *only* those that fit our screen width
var sizes = [600, 1000, 1920, 2880].filter(function(s){
return window.innerWidth < s || s == 2880;
});
// update the image with whatever size is in the first position
$(element).attr('src', 'images/' + sizes[0] + name);
});
}
We can move the resize function definition outside of your on ready handler, to make it globally accessible. We can dispense with use of split to just find whatever is after the last / (the image name). And we can avoid using loops and if statements with breaks, which tend to be difficult to read and maintain.

This is a bit verbose and follows your array starting with the largest value which I used instead of hard coding that for the "largest" (last) conditional. Remove the console logs prior to deployment.
$(document).ready(function() {
window.onresize = resize;
var sizes = [2880, 1920, 1000, 600];
function resize() {
console.log('si');
var img = $('img.resizable');
var width = $(window).innerWidth();
img.each(function(index, element) {
var name = element.src.split('/');
name = name[name.length - 1];
var setto = 0;
for (var i = sizes.length; i >= 0; i--) {
console.log(i,width,setto, sizes[i]);
if (width <= sizes[i]) {
setto = sizes[i];
break;
}
}
setto = width >= sizes[0] ? sizes[0] : setto;
$(element).attr('src', 'images/' + setto + '/' + name);
});
}
resize();
});

You are referencing Sizes array using lowercase s at sizes[i], where sizes is not defined

I hope this could solve your problem:
$(window).on('resize', function (e) {
var img = $('img.resizable');
var width = $(window).innerWidth();
var Sizes, sLength, i;
img.each(function (index, element) {
var name = element.getAttribute('src').split('/') // Split is a native javascript function, which 'splits' the string into an array with the components
Sizes = [2880, 1920, 1000, 600].sort((a, b) => {return a - b;});
sLength = Sizes.length;
for (i = 0; i < sLength; i++) {
if (width <= Sizes[i]) {
$(element).attr('src', 'images/' + Sizes[i] + '/' + name.pop())
console.log('New src for image N. ' + index + ' is: ' + $(element).attr('src'));
break;
}
}
});
});
$(function () {
// simulate a resize on dom ready: for testing
$(window).trigger('resize');
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<img class="resizable" src="images/100/nameofimage1.png">
<img class="resizable" src="images/100/nameofimage2.png">

You want something like this probably:
sort_array_small_to_large(Sizes)
for (i = 0; i < Sizes.length; i++)
{
if (width <= Sizes[i])
{
size = Sizes[i]
break
}
}
$(element).attr('src', 'images/' + size + '/' + name[name.length - 1])

Related

How to adapt script to work with parallax

I've got the following script
$(document).ready(function() {
window.onresize = resize;
var sizes = [2880, 1920, 1000, 600];
function resize() {
//console.log('si');
var img = $('img.resizable');
var width = $(window).innerWidth();
img.each(function(index, element) {
var name = element.src.split('/');
name = name[name.length - 1];
var setto = 0;
for (var i = sizes.length; i >= 0; i--) {
//console.log(i,width,setto, sizes[i]);
if (width <= sizes[i]) {
setto = sizes[i];
break;
}
}
setto = width >= sizes[0] ? sizes[0] : setto;
$(element).attr('src', 'images/' + setto + '/' + name);
});
}
resize();
});
It works with IMG tags: <img src="images/August-Vision-Night.png" class="resizable" alt=""/>
I'm trying to adapt it to work with a parallax background image. Instead of changing src it needs to change data-image-src
<div id="contentsection_1_container" class="parallax-window parallax-resizable" data-parallax="scroll" data-image-src="images/texture-clouds.png">
I attempted the following code; however, it didn't work at all. I'm new to this, so I have no clue how to actually fix the script.
$(document).ready(function() {
window.onresize = resize;
var sizes = [2880, 1920, 1000, 600];
function resize() {
//console.log('si');
var img = $('.parallax-resizable');
var width = $(window).innerWidth();
img.each(function(index, element) {
var name = element.data-image-src.split('/');
name = name[name.length - 1];
var setto = 0;
for (var i = sizes.length; i >= 0; i--) {
//console.log(i,width,setto, sizes[i]);
if (width <= sizes[i]) {
setto = sizes[i];
break;
}
}
setto = width >= sizes[0] ? sizes[0] : setto;
$(element).attr('data-image-src', 'images/' + setto + '/' + name);
});
}
resize();
});

Fit text width to div width

SetBoxText = function(Box, Text) {
if(! Website.Connected) {
return false;
}
if(Box == null || ! Box.Created) {
return false;
}
if(Box.Text == Text) {
return false;
}
Box.Text = Text;
UpdateBox(Box);
// To avoid constant updating.
for(var LetterPos = 0; LetterPos < Box.Letter.length; LetterPos++) {
Box.Element.removeChild(Box.Letter[LetterPos].Element);
}
Box.Letter = [];
var
Letter = " ",
Element = null,
FontSize = 0
;
for(var LetterPos = 0; LetterPos < Box.Text.length; LetterPos++) {
Letter = Box.Text[LetterPos];
Element = document.createElement("font");
Box.Element.appendChild(Element);
Box.Letter[LetterPos] = {};
Box.Letter[LetterPos].Letter = Letter;
Box.Letter[LetterPos].Element = Element;
Box.Letter[LetterPos].Element.style.fontFamily = Box.Font;
Box.Letter[LetterPos].Element.style.textAlign = "center";
Box.Letter[LetterPos].Element.innerHTML = Box.Letter[LetterPos].Letter;
FontSize = 1;
Box.Letter[LetterPos].Element.style.fontSize = FontSize + "px";
while(Box.Letter[LetterPos].Element.offsetWidth < (Box.Element.offsetWidth / Box.Text.length)) {
FontSize++;
Box.Letter[LetterPos].Element.style.fontSize = FontSize + "px";
}
while(Box.Letter[LetterPos].Element.offsetWidth > (Box.Element.offsetWidth / Box.Text.length)) {
FontSize--;
Box.Letter[LetterPos].Element.style.fontSize = FontSize + "px";
}
Box.Letter[LetterPos].Element.style.width = Box.Letter[LetterPos].Element.offsetWidth + "px";
Box.Letter[LetterPos].Element.style.height = Box.Letter[LetterPos].Element.offsetHeight + "px";
}
return true;
}
I have this function ^ up there.
What it's supposed to do is create a font tag for every letter in the Text region.
While it does that, it's supposed to fit itself into it's parent's width Box.Element.
What's happening is my browser freezes if I try to run this function.
When I comment out the while statements, this runs but I'm stuck with 1px size font.
I don't want to use jQuery.
Please help me =]
Edit:
I've also noticed if I switch the tags from font to div, it will make it, but only vertically, and when I do Element.style.display = "inline-block"; to the div it will do the same as the font.
Edit2: I changed the while loops to a for loop:
for(var FontSize = 1; FontSize < 100; FontSize++) {
if(Box.Letter[LetterPos].Element.offsetWidth < (Box.Element.offsetWidth / Box.Text.length)) {
Box.Letter[LetterPos].Element.style.fontSize = FontSize + "px";
}
}
This runs but some of the letters too big and some too small.
i hope this helps, considering that your browser is hanging, i did a small test with a for loop nesting a while loop, my browser hanged, too..
i hope this could be the solution to your problem, using the keyword break.
while(Box.Letter[LetterPos].Element.offsetWidth < (Box.Element.offsetWidth / Box.Text.length)) {
FontSize++;
Box.Letter[LetterPos].Element.style.fontSize = FontSize + "px";
break; // break out of loop when condition is met
}
while(Box.Letter[LetterPos].Element.offsetWidth > (Box.Element.offsetWidth / Box.Text.length)) {
FontSize--;
Box.Letter[LetterPos].Element.style.fontSize = FontSize + "px";
break;
}

Move each character of a div based on mouse movement

I'm developing a site and I don't know how to create a javascript animation that looks like this:
I have a div that have some text on it, and when the user moves his mouse over this text, I want each character to move independently of each other, in order to maintain a certain distance from it (the mouse). Also, I want this animation to have rotation, but it isn't that important now. Here's an image explanation:
Here's what I did so far:
HTML:
<div class="div1">Hello World</div>
Javascript:
var chars = $(".div1").html().split('');
$(".div1").empty();
for(var i = 0; i < chars.length; i++){
$(".div1").append("<span class='letter'>"+chars[i]+"</span>");
}
JSFiddle
Can someone help me to achieve this effect? I don't know how to proceed and there's no site or answer that helped me. You can use jQuery or pure JavaScript but, please, keep it simple! Thank you.
Oh here we go, I've found a solution for this.
What I did was using a different class name for each character (.letter + character number) and then created a way of moving the characters depending on the mouse position and distance compared to each character, so, for example, when the distance between the mouse and a character is less than X, and the mouse Y is less than the character Y, then the character will go down.
Thanks to adeneo and Derek
Here's the relevant code:
JavaScript:
var chars = $(".div1").html().split('');
$(".div1").empty();
for (var i = 0; i < chars.length; i++) {
$(".div1").append("<span class='letter" + i + "'>" + chars[i] + "</span>");
$(".letter" + i).css({
"position":"relative",
});
$(".letter" + i).css({
"transition": "0.5s"
});
}
$(document).on("mousemove", function (e) {
for (var i = 0; i < chars.length; i++) {
var x = e.pageX,
y = e.pageY;
var distx = x - $(".letter" + i).offset().left + ($(".letter" + i).width() / 2);
var disty = y - $(".letter" + i).offset().top;
if (Math.abs(distx) < 24 && Math.abs(disty) < 24) {
if (distx > 6 || distx < -6) {
if (x < $(".letter" + i).offset().left) {
$(".letter" + i).css({
"left": + (24 / Math.abs(distx) * Math.abs(distx)),
"position": "relative"
});
} else {
$(".letter" + i).css({
"left": - (24 / Math.abs(distx) * Math.abs(distx)),
"position": "relative"
});
}
}
if (disty > 12 || disty < -12) {
if (y < $(".letter" + i).offset().top + 6) {
$(".letter" + i).css({
"top": + (24 / Math.abs(disty) * Math.abs(disty)),
"position": "relative"
});
} else {
$(".letter" + i).css({
"top": - (24 / Math.abs(disty) * Math.abs(disty)),
"position": "relative"
});
}
}
}
distx = 0;
disty = 0;
}
});
HTML:
<div class="div1">Hello World</div>
Updated JSFiddle with CSS Transitions to improve smoothness
Well since you say yo want to learn, i'll give a code to help you out, but you have to work your way through, i haven't test it, i just wrote it blindly so it propably won't work but might give you a good idea of what must be done.
Html:
<div class="container">
<div id="coolDiv" class="scatterContainer">Hello World</div>
</div>
Css:
*{margin:0;}
span:hover{
color:#0CF;
}
.scatterContainer{
display: inline;
}
.container {
margin: 30px auto;
}
Javascript
LetterScatterer = (function() {
function LetterScatterer(id) {
this.id = id
this.$el = $('#' + this.id);
this.rangeOfaction = 3; // Number of characters to affect
this.maxVerticalMovement = 10; // Value in px
this.minVerticalMovement = 2
this.duration = 100; // In miliseconds
// Event Listeners
this.$el.on(mousemove((function(_this){
return function(e){
var x = e.pageX;
var y = e.pageY;
return _this.scatter(x, y);
}
})(this));
}
LetterScatterer.prototype.splitCharacters = function() {
var nodes = [];
var nodesQ = 0;
var _this = this;
this.chars = $el.text().split('');
$el.empty();
for(var i = 0; i < chars.length; i++){
var markup = "<span class='letter'>"+chars[i]+"</span>";
nodes.push(markup);
}
this.$nodes = $(nodes);
this.nodesWidth = [];
this.$nodes.each(function(){
var width = $(this).outerWidth();
_this.nodesWidth.push(width);
});
$el.append(this.$nodes);
}
LetterScatterer.prototype.scatter = function(x, y) {
var epicenter;
var offset = 0;
var midPoint, farestLeft;
for(var i = 0, len = this.nodesWidth.length; i < len; i++){
offset += this.nodesWidth[i];
if(x <= offset){
epicenter = i;
break;
}
}
leftRange = (this.rangeOfaction - 1) / 2; // We remove one, this is our epicenter, then we get left and right halves
farestLeft = epicenter - leftRange;
for(var i = farestLeft; i < this.rangeOfaction; i++){
this.animateY($node[i]);
}
}
LetterScatterer.prototype.animateY = function(node, verticalDisplacement) {
var $node = $(node);
$node.animate({margin-top: verticalDisplacement + 'px'}, this.duration);
}
return LetterScatterer;
})();
letterScatterer = new LetterScatterer('coolDiv');
What you see in the code is a classlike function, first you pass it the id of the element containing the text that will be scattered. There are some config varaibles, range of action is lets say, if you mouse over one character, how many characters to the left and to the right (also including the current hovered element) should be animated, the max and min verticalMovement, determines how much should move the one that is hovered (max) and those further apart will use min, those in between should interpolate, but i didn't code that far.
We then got a mousemove listener, that calls the method scatter, this method finds which items is currently hovered by adding up each character widht, but now i think about it, it should be easier to just add a listener to the span, and get the current index of that element with the jQuery method index(), then based on that index you animate that one and those in the range. You must create the code that calculates the rotation, and x movement if you want to, but i think i gave you a lot to start, it took me a while to code it, so i hope it helps and this answer satisfies your question. :)

Putting simple functions that contain jquery in a jquery execution queue

I have a number of functions containing jquery that should be executed sequentially. They aren't used to create effects but rather to position certain elements at a calculated location inside a div. All online resources on jquery queue are focused on the creation of transitions or animations so it's hard to find a simple example on how to execute a number of simple functions sequentially.
I have these functions:
function bigItemRecalc(recalc, idBase, innerHeight, i) {
if (recalc < 0) {
$('#' + idBase + i).css('max-height', (innerHeight + (2 * recalc)));
recalc = 0;
}
return recalc;
}
function firstCheck(recalc, idBase, i) {
if (i == 1) {
$('#' + idBase + i).css('margin-top', recalc * -1);
}
}
function lastCheck(recalc, idBase, itemAmount, i) {
if (i == itemAmount) {
$('#' + idBase + i).css('margin-top', recalc);
}
}
function truncateItems(totalHeight, widgetHeight, idBase, i) {
if (totalHeight > (widgetHeight - 20)) {
$('#' + idBase + i).remove();
$('#' + idBase + "b" + i).remove();
}
}
In another function I want to execute these sequentially by using a jquery queue preferably , but I haven't got a clue how.
The code is called here:
function styleWidget(itemAmount, widgetHeight, widgetWidth, idBase) {
var innerHeight;
var outerHeight;
var recalc;
var totalHeight = 0;
var totalWidth = 0;
for (var i = 1; i <= itemAmount; i++)
{
if (widgetHeight >= widgetWidth)
{
totalHeight += $('#'+idBase+i).height();
innerHeight = $('#' + idBase + i).height();
outerHeight = (widgetHeight/itemAmount);
recalc = ((outerHeight / 2) - (innerHeight / 2));
recalc = bigItemRecalc(recalc, idBase, innerHeight, i);
$('#' + idBase + i).css('padding-top', recalc);
firstCheck(recalc, idBase, i);
lastCheck(recalc, idBase, itemAmount, i);
truncateItems(totalHeight, widgetHeight, idBase, i);
}
else
{
innerHeight = $('#'+idBase+i).height();
outerHeight = widgetHeight;
recalc = ((outerHeight/2)-(innerHeight/2));
$('#'+idBase+i).css('padding-top',recalc);
totalWidth += $('#'+idBase+i).width();
if (totalWidth > (widgetWidth-20))
{
$('#' + idBase + i).remove();
$('#' + idBase + "b" + i).remove();
}
}
}
}
The bottom part hasn't been updated just yet, but it can be ignored as it's being tested with portrait mode widgets.
I think I've found a clue. When no delay is introduced the values of totalHeight and innerHeight seem very low. So I assume that the page isn't fully loaded by the time the script is executed. Every time a new widget is generated the above script is called like this:
$(document).ready(styleWidget(3, 225, 169, 'id-871206010'));
This fixed it:Why does Firefox 5 ignore document.ready?
It seems like reloading the page did not trigger the .ready() function.

Getting Javascript/jQuery scrolling function to work on successive divs

I'm currently trying to implement functionality similar to infinite/continuous/bottomless scrolling, but am coming up with my own approach (as an intern, my boss wants to see what I can come up with on my own). So far, I have divs of a fixed size that populate the page, and as the user scrolls, each div will be populated with an image. As of now, the function I've written works on the first div, but no longer works on successive divs.
$(window).scroll(function () {
var windowOffset = $(this).scrollTop();
var windowHeight = $(this).height();
var totalHeight = $(document).height();
var bottomOffset = $(window).scrollTop() + $(window).height();
var contentLoadTriggered = new Boolean();
var nextImageCount = parseInt($("#nextImageCount").attr("value"));
var totalCount = #ViewBag.totalCount;
var loadedPageIndex = parseInt($("#loadedPageIndex").attr("value"));
var calcScroll = totalHeight - windowOffset - windowHeight;
$("#message").html(calcScroll);
contentLoadTriggered = false;
if (bottomOffset >= ($(".patentPageNew[id='" + loadedPageIndex + "']").offset().top - 1000)
&& bottomOffset <= $(".patentPageNew[id='" + loadedPageIndex + "']").offset().top && contentLoadTriggered == false
&& loadedPageIndex == $(".patentPageNew").attr("id"))
{
contentLoadTriggered = true;
$("#message").html("Loading new images");
loadImages(loadedPageIndex, nextImageCount);
}
});
This is the image-loading function:
function loadImages(loadedPageIndex, nextImageCount) {
var index = loadedPageIndex;
for(var i = 0; i < nextImageCount; i++)
{
window.setTimeout(function () {
$(".patentPageNew[id='" + index + "']").html("<img src='/Patent/GetPatentImage/#Model.Id?pageIndex=" + index + "' />");
index++;
var setValue = index;
$("#loadedPageIndex").attr("value", setValue);
}, 2000);
}
}
I was wondering what may be causing the function to stop working after the first div, or if there might be a better approach to what I'm attempting?
EDIT: It seems that loadedPageIndex == $(".patentPageNew").attr("id") within the if statement was the culprit.
#ViewBag.totalCount; is not a JavaScript, it's .NET, so your script probably stops after encountering an error.
Also: ".patentPageNew[id='" + loadedPageIndex + "']" is inefficient. Since IDs must be unique, just query by ID instead of by class name then by ID.

Categories

Resources