I just recently startet with Javascript and had the following Idea:
I would like to have short text (maybe just a headline) on my website which single chars will have a rainbow-color that travells from left to right.
So I wrote this short script.
var Count = 6;
setInterval(function RainbowColorFunction()
{
var Rainbow_Colors = ["#FFFF00","#FF7F00","#FF0000","#9400D3","#4B0082","#0000FF","#00FF00"];
var Color_Element = document.getElementById("RainbowColorText");
var Color_String = Color_Element.textContent;
var Letter = "";
var NewText = "";
var RainbowCount = Count;
var Stringlenght = Color_String.length;
Color_String = reverse(Color_String);
for (var i = Stringlenght, min = 0; i > min; i--)
{
Letter = Color_String.charAt(i -1);
if(Letter == " ")
{
NewText += Letter;
continue;
}
NewText += Letter.fontcolor(Rainbow_Colors[RainbowCount]);
RainbowCount--;
if(RainbowCount < 0){RainbowCount = 6;}
}
Count--;
if(Count < 0){Count = 6;}
Color_Element.innerHTML=NewText;
}, 60);
function reverse(s) {
return (s === '') ? '' : reverse(s.substr(1)) + s.charAt(0);
}
My Issue is now that the text changes colour from right to left. But I want it the other way around. Without the reverse Function my text is a big mess, but I am quite sure thats the point where I have to change things.
Short answer: just increment instead of decrement Count:
Count++;
if(Count>6 ){Count = 0;}
Other observations:
it's "length" not "lenght"
try to use singlequotes in Javascript and doublequotes for html
attributes. You will see that writing html in javascript and the
reverse become simple.
also the naming conventions for Javascript usually use lowercase
Camel variables, uppercase is reserved for class names, public
members maybe, etc. Whatever you use, be consistent after you choose.
you can move a lot of the function outside the interval, like the
part that gets the element.
you don't need to name the function that you give setInterval as an
attribute. Alternately you can name it then use
setInterval(functionName,500) on a separate line.
If I would do it, I would try to encapsulate it better. Here is my 5 minute effort:
function RainbowColor(elem)
{
this.Colors=["#FFFF00","#FF7F00","#FF0000","#9400D3","#4B0082","#0000FF","#00FF00"];
this.Speed=16.66;
this.Direction=1;
this._offset=0;
this._elem=elem;
this._originalContent=elem.innerHTML;
}
RainbowColor.prototype={
Colorize:function() {
var self=this;
function mod(v,l) {
var result=v%l;
return result<0?result+l:result;
}
function rainbowColorFunction() {
var text=self._elem.textContent;
var result='';
var k=self._offset;
for (var i=0; i<text.length; i++) {
var letter=text.charAt(i);
if (!letter) continue;
result+=letter.fontcolor(self.Colors[mod(k,self.Colors.length)]);
k-=self.Direction;
}
self._elem.innerHTML=result;
self._offset++;
}
this._interval=setInterval(rainbowColorFunction,1000/self.Speed);
},
Stop:function() {
if (this._interval) clearInterval(this._interval);
},
Restore:function() {
this._elem.innerHTML=this._originalContent;
}
}
var colorizer=new RainbowColor(document.getElementById('RainbowColorText'));
colorizer.Colorize();
setTimeout(function() { colorizer.Direction=-1; },5000);
setTimeout(function() { colorizer.Colors=['lightgray','gray','black'] },10000);
setTimeout(function() { colorizer.Speed=10; },15000);
setTimeout(function() { colorizer.Stop(); },20000);
setTimeout(function() { colorizer.Restore(); },23000);
I also looked into using CSS to create a text gradient, but I couldn't find any cross-browser solution (More details : How do I use a gradient as a font color in CSS?)
Speaking of cross-browser, perhaps you should use jQuery to get and set HTML content in order for this to work everywhere correctly.
Related
After a couple of hours struggling with the first part I finally made it work.
However I would like to nest two additional functions, the first one to generate a random color and the second one to set the random color into a div with id #gradient that represents the background.
Here is the code so far, can you help me please?
$(document).ready(function() {
$("#btn").on("click", function() {
$.getJSON("http://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?", function(json) {
var quote = json.quoteText;
var author = json.quoteAuthor;
$(".quoteText").text("'" + quote + "'");
$(".quoteAuthor").text("-" + author + "-");
function RandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function changeColor() {
$("#gradient").css("background-color", RandomColor()));}});});});
JQuery docs:
jQuery.getJSON( url [, data ] [, success ] )
Looking at your code, you got that down. You are sending a function callback when you call $.getJSON(). To start debugging it, I would first tidy up the code (don't do that to yourself or future coders, your editor most likely has a "reformat code" option to add appropriate indentations. Debugging untidy code like that will give you headaches in the future.)
Your code turns into this once you tidy it up and fix some closing/openings that are wrong.
$(document).ready(function () {
$("#btn").on("click", function () {
$.getJSON("http://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?", function (json) {
var quote = json.quoteText;
var author = json.quoteAuthor;
$(".quoteText").text("'" + quote + "'");
$(".quoteAuthor").text("-" + author + "-");
function RandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function changeColor() {
$("#gradient").css("background-color", RandomColor());
}
});
});
});
First problem
function changeColor() {
$("#gradient").css("background-color", RandomColor());
}
That function will never get called. You are merely declaring it, not calling it. Just take what's inside out of it, and you've got it. I would also take the function RandomColor() (I didn't check if it works or not...) outside of that scope, in case you want to reuse it.
You end up with this:
$(document).ready(function () {
$("#btn").on("click", function () {
$.getJSON("http://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?", function (json) {
var quote = json.quoteText;
var author = json.quoteAuthor;
$(".quoteText").text("'" + quote + "'");
$(".quoteAuthor").text("-" + author + "-");
$("#gradient").css("background-color", RandomColor());
});
});
});
function RandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
In addition, you will only be changing the color of the divupon success. If you want to do something upon failure, use the following:
The Promise interface in jQuery 1.5 also allows jQuery's Ajax methods, including $.getJSON(), to chain multiple .done(), .always(), and .fail() callbacks on a single request, and even to assign these callbacks after the request may have completed. If the request is already complete, the callback is fired immediately.
$.getJSON("...", function (json) {
...
}).fail(function() {
console.log( "error" );
});
Hope that helped.
I made a little script to practice and it seems I have a problem with my loops and their timeouts.
Here's the link to my script : http://codepen.io/JulienBarreira/pen/EWNoxJ
Sometimes when a word is writing, one or two letters are wrong. For example, instead of "cheeseburger", I get "chkesebxrger".
I found a little trick so it fails less, but i don't know why at all.
function charsAnim(i, word, j) {
setTimeout(function() {
var count = j;
if (j < steps) {
randomChar(i, word, count, j);
} else {
goodChar(i, word, count, j);
}
/* seems it fails less if I divide j, don't know why */
}, (speed/steps)*(j / 1.8));
}
The problems appears more often when others scripts are running on the computer (for example in my profile page).
Feel free to give me any advices about my code even if it's not about my problem. There's problably an easier way to do the same thing and i'm here to progress.
Thanks :)
Edit : I added 3 iframes in a snippet to show you the problem, when you start the snippet, the first word fails most of the time.
var words = [
'unicorn',
'cheeseburger',
'pizza',
'pineapple',
'popsicle',
'bubbles',
'seagull',
'doodle',
'goggles',
'artichoke',
'potato',
'carrot',
'vegeta'
];
var letters = "abcdefghijklmnopqrstuvwxyz#%&^+=-";
var speed = 250;
var steps = 4;
function getRandomWord() {
var randomWord = words[Math.floor(Math.random() * words.length)];
return randomWord;
}
function getRandomLetter() {
var randomLetter = letters[Math.floor(Math.random() * letters.length)];
return randomLetter;
}
function randomWordLoop() {
var word = getRandomWord();
var textLength = word.length;
for(i = 0; i < textLength; i++) {
letterAppear(i, word);
}
function letterAppear(i, word) {
setTimeout(function() {
randomLetters(i, word);
}, speed*i);
}
function randomLetters(i, word) {
for (j = 0; j <= steps; j++) {
charsAnim(i, word, j);
}
}
function charsAnim(i, word, j) {
setTimeout(function() {
var count = j;
if (j < steps) {
randomChar(i, word, count, j);
} else {
goodChar(i, word, count, j);
}
/* seems it fails less if I divide j, don't know why */
}, (speed/steps)*(j / 1.8));
}
function randomChar(i, word, count, j) {
var letter = getRandomLetter();
if (j > 0) {
var oldText = $('#loader').text().slice(0, -1);
} else {
var oldText = $('#loader').text();
}
$('#loader').text(oldText + letter);
}
function goodChar(i, word, count, j) {
var oldText = $('#loader').text().slice(0, -1);
$('#loader').text(oldText + word[i]);
if (i == textLength - 1 ) {
removeWord();
}
}
function removeWord() {
setTimeout(function() {
for (k = 0; k < textLength; k++) {
removeLetters(k);
}
}, speed*2);
}
function removeLetters(k) {
setTimeout(function() {
removeLetter(k);
}, 75*k);
}
function removeLetter(k) {
var actualText = $('#loader').text().slice(0, -1);
$('#loader').text(actualText);
if (k == textLength - 1) {
randomWordLoop();
}
}
}
randomWordLoop();
body {
background-color: #010101;
}
.loader {
width: 300px;
color: #0c9c73;
text-align: left;
font-size: 50px;
font-family: Roboto Mono;
font-weight: 700;
text-transform: uppercase;
}
.loader:after {
content:'_';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700" rel="stylesheet">
<div class="loader" id="loader"></div>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GquEnoqZAK0?autoplay=1" frameborder="0" allowfullscreen></iframe>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GquEnoqZAK0?autoplay=1" frameborder="0" allowfullscreen></iframe>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GquEnoqZAK0?autoplay=1" frameborder="0" allowfullscreen></iframe>
You are combining this loop, inside randomWordLoop()
for(i = 0; i < textLength; i++) {
letterAppear(i, word);
}
... with the setTimeout() inside letterAppear(). Basically, when letterAppear() executes inside letterAppear, i variable no longer has the same value as when you set the timeout. It has it's global value, which might have already been set to a completely different value by any other function in your page that might use i.
Also, please note the proper way to set your for would be not to use i globally, but rather set it as a local var of your function: for(var i = 0; i < textLength; i++) {...}.
You're not able to properly see it, as your function outputs random letters and there's no visual clue letting you know it runs on wrong values of i, but I believe your function is wrong most of the time.
To fix this, you need a closure in letterAppear() which will pass the correct values of i and word to the setTimeout() inside randomLetters(), irrespective of their global value when the contents of the setTimeout() executes:
for(var i = 0; i < textLength; i++) {
(function(i,word){
letterAppear(i, word);
})(i,word)
}
Looking closer to your code, you might need closures in more than one place (if it's important that the values you pass to the functions are the same at code execution) and you should also define the for iterators (i and j) locally, using var, like I did above.
Don't forget your best JavaScript friend ever:
console.log(this, arguments);
I'm working on trying to create a random image generator that will show a random image in Javascript. I've been able to make it show a random image via the Javascript math and using random variables. But sadly I'm still yet to be eligible to make my code repeat itself.
I know its probably very simplistic but as you know, we all start from somewhere. I've tried my best to compact my code and I have looked at other stackoverflow recourses but im still in no luck.
A quick overview of what happens, you are meant to be able to press a button and then, a selected random image is replaced by the current one.
What I want: to be able to press a button and then it will proceed to cycle through the random images 'x' times.
My code:
function imgRandom() {
var myImages1 = new Array();
myImages1[1] = "images/Random/Icon1.png";
myImages1[2] = "images/Random/Icon2.png";
myImages1[3] = "images/Random/Icon3.png";
myImages1[4] = "images/Random/Icon4.png";
myImages1[5] = "images/Random/Icon5.png";
myImages1[6] = "images/Random/Icon6.png";
myImages1[7] = "images/Random/Icon7.png";
myImages1[8] = "images/Random/Icon8.png";
myImages1[9] = "images/Random/Icon9.png";
myImages1[10] = "images/Random/Icon10.png";
myImages1[11] = "images/Random/Icon11.png";
myImages1[12] = "images/Random/Icon12.png";
myImages1[13] = "images/Random/Icon13.png";
myImages1[14] = "images/Random/Icon14.png";
myImages1[15] = "images/Random/Icon15.png";
myImages1[16] = "images/Random/Icon16.png";
myImages1[17] = "images/Random/Icon17.png";
myImages1[18] = "images/Random/Icon18.png";
myImages1[19] = "images/Random/Icon19.png";
myImages1[20] = "images/Random/Icon20.png";
myImages1[21] = "images/Random/Icon21.png";
myImages1[22] = "images/Random/Icon22.png";
myImages1[23] = "images/Random/Icon23.png";
var rnd = Math.floor(Math.random() * myImages1.length);
if (rnd == 0) {
rnd = 1;
}
document.getElementById("gen-img").src = myImages1[rnd];
}
<center>
<p>
<img id="gen-img" class="character-image" src="images/QuestionMark.png" style="width:180px;height:310px;">
</p>
<p>
<input type="button" class="button" value="Choose" onclick="setTimeout(imgRandom, 3000);" />
</p>
</center>
I hope this isn't too confusing, i'll be active for a long time if you're able to help! Thanks,
David.
I refactored your code a bit with an possible approach Here's the fiddle: https://jsfiddle.net/mrlew/d2py2jvb/
I commented with some explanations.
/* some flags you can set */
var timesTocycle = 10;
var totalImagesToCreate = 23;
var timeBetweenCycle = 3000;
/* global variables */
var allMyImages = [];
var timesCycled = 0;
/*
function to create your images path.
Called once when you load your page.
*/
function createMyImages(total) {
for (var i=0; i<total;i++) {
var imageNumber = i+1;
var path = getImagePath(imageNumber);
allMyImages.push(path);
}
}
/* separated your path getter */
function getImagePath(imageNumber) {
return "images/Random/Icon" + imageNumber + ".png";
}
/* this is the function called when you press the button and when one cycle ends */
function triggerRandomImage() {
if (timesCycled >= timesTocycle) return;
setTimeout(displayRandomImage, timeBetweenCycle);
}
/* random integer javascript function */
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/* function called on setTimeout */
function displayRandomImage() {
var rnd = getRandomInt(0,allMyImages.length-1);
var imageToDisplayPath = allMyImages[rnd];
document.getElementById("gen-img").src = imageToDisplayPath;
timesCycled++;
triggerRandomImage();
/* debug info */
document.getElementById('info').innerText = "(showing: " + imageToDisplayPath + ", cycle: " + timesCycled + ", max: " + timesTocycle + ")";
}
/* call this function to populate the allMyImages array */
createMyImages(totalImagesToCreate);
I believe what you want is for loop. Let me demonstrate with your code:
var count = 10; //number of times to run the for loop
for (i = 0; i < count; i++){
var rnd = Math.floor(Math.random() * myImages1.length);
if (rnd == 0) {
rnd = 1;
}
document.getElementById("gen-img").src = myImages1[rnd];
}
The above code would run the randomizing bit 10 times (= 10 images). Now, I have not tested it yet, but I believe that the images would flash by really quickly. Also, unrelated to the question you may want to read about Javascript arrays.
I might have missed something obvious here, apologies in advance if so...
Using ajax-solr and implementing my own version of their Current Search widget example/tutorial - https://github.com/evolvingweb/ajax-solr/wiki/Reuters-tutorial%3A-step-5 I have a code snippet which looks like this:
(function($) {
AjaxSolr.CurrentSearchWidget = AjaxSolr.AbstractWidget.extend({
start: 0,
afterRequest: function() {
var self = this;
var links = [];
var q = self.manager.store.get('q').val();
var qText = q;
if (q != null && q != '*:*') {
if (q.split(':').length == 2) {
qText = q.split(':')[1];
}
links.push($('')
.text('search: ' + qText + ' (remove)').click(function() {
localStorage.removeItem("query");
localStorage.setItem("query", "*");
self.manager.store.get('q').val('*:*');
self.doRequest();
return false;
}));
}
var fq = self.manager.store.values('fq');
var prettyText = "";
for (var i = 0, l = fq.length; i < l; i++) {
//string manipulation for user-facing text
links.push($('')
.text(prettyText + ' (remove)').click(self.removeFacet(fq[i])));
//local storage stuff
}
if (links.length > 1) {
links.unshift($('')
.text('remove all').click(function() {
localStorage.clear();
localStorage.setItem("query", "*");
self.manager.store.get('q').val('*');
self.manager.store.remove('fq');
self.doRequest();
return false;
}));
}
//update DOM
},
I've stripped out the unecessary code, but the above works fine. However, if I change
links.push($('')
.text(prettyText + ' (remove)')
.click(self.removeFacet(fq[i])));
to use a function as per the examples above it and below, like
links.push($('')
.text(prettyText + ' (remove)')
.click(function () {
self.removeFacet(fq[i]);
}));
so that I can add additional code there, it no longer runs removeFacet when the anchor is clicked. Thanks for any help on what I'm missing!
This seems to be a problem with function scope. This is not pointing to your object anymore. I would suggest binding your "self" object like so.
links.push($('')
.text(prettyText + ' (remove)')
.click(function () {
var self = this;
self.removeFacet(fq[i]);
}).bind(self));
please see if changing to this works
links.push($('')
.text(prettyText + ' (remove)')
.on('click', function () {
self.removeFacet(fq[i]);
}));
The problem you ran into - you have inner functions (the anonymous click function) that is not executed immediately, therefore the iterator gets "lost". Taking the following example
var i, colors = ['green', 'blue', 'red'];
for (i = 0; i < colors.length; i++) {
var color = colors[i];
setTimeout(function() {
console.log(color);
}, i * 1000);
}
// red, red, red
would log 3 times red, because the code of the function (here inside the timeout) is executed outside the loop, the iterator is at its last position.
Using this variant the value would be captured at each iteration into an argument to a function, which does create a scope, which would produce
the output green, blue, and red
var i, colors = ['green', 'blue', 'red'];
for (i = 0; i < colors.length; i++) {
(function(color) {
setTimeout(function() {
console.log(color);
}, i * 1000);
})(colors[i]);
}
// green, blue, red
In your case something like this should work:
links.push($('')
.text(prettyText + ' (remove)')
.click((function(instance, facet) {
// your code here
// and delete
instance.removeFacet(facet);
})(self, fq[i]));
It's always better to use the on function. Try something like this...
$(window, "a.cur-search", function () {
var self = this;
self.removeFacet(fq[i]);
});
You might need to put fq[i] in data or something to make it available.
I managed to pull together a script that will increase the font sizes of parts of a web page using buttons or links. It works in Moz/Chrome, but sticks on IE, tho theoretically it shouldn't have a issue in these major browsers. But I'm stuck on whether or not it's possible to use currentStyle to get the fontSize from a variable populated by getElementsByName; certainly IE is drawing blanks.
Here's my script:
function changeFontSize(element,step)
{
var styleProp = 'font-size';
step = parseInt(step,10);
var x = document.getElementsByName(element);
for(i=0;i<x.length;i++) {
if (x[i].currentStyle) {
var y = parseInt(x[i].currentStyle[styleProp],10);
} else if (window.getComputedStyle) {
var y = parseInt(document.defaultView.getComputedStyle(x[i],null).getPropertyValue(styleProp),10);
}
x[i].style.fontSize = (y+step) + 'px';
}
}
The 3 sites I've used to pull this together are:
www.vijayjoshi.org
www.quirksmode.org
and (this isn't spam, this is actually important) //http://www.white-hat-web-design.co.uk/blog/controlling-font-size-with-javascript/
Can anyone point out a solution please? Thanks in advance!
what about updating your code with the following :
function changeFontSize(element,step)
{
function computeFontSizeUpdate(oE)
{
//- init fSize with proper null value
var fSize = null;
//- retrieve fSize from style
if (oE.currentStyle) {
fSize = parseInt(oE.currentStyle[styleProp], 10);
}
else if (window.getComputedStyle) {
var s = document.defaultView.getComputedStyle(oE,null);
fSize = (s) ? parseInt(s.getPropertyValue(styleProp),10) : NaN;
}
//- check fSize value based on return of parseInt function
if( isNaN(fSize) == false && fSize != null)
{
fSize += nStep + 'px';
if(oE.currentStyle)
oE.currentStyle.fontSize = fSize;
else
oE.style.fontSize = fSize;
}
};
var styleProp = 'font-size';
var nStep = parseInt(step, 10);
//- ensure step value
if( isNaN(nStep) ) nStep = 0;
//- get target elements
var oElems = document.getElementsByName(element);
if ( oElems && oElems.length == 0)
{
var oE = document.getElementById(element);
if(oE) computeFontSizeUpdate(oE);
}
else
{
for(oE in oElems)
{
computeFontSizeUpdate(oE);
}
}
}
I have updated script with fix and few better naming for some variables.
Also, I am sorry cause I am on Mac right now, I wasn't able to test the provided script in IE ... but from what I remember it should do the trick.
Using some JS console you can directly execute directly on this page
changeFontSize("nav-tags", 50);
and you will notice that the Tags element in the menu bar would get affected :)
Hope this helps