I'm quite new to JS.
I want to have my html page stay the same when JS text will be appearing in one exact place without starting from blank page.
I trigger JS function via button on HTML, function in HTML:
function match () {
setTimeout(function () {
player_hp -= monster_dmg
monster_hp -= player_dmg
if (player_hp<=0) {
document.write("\nPlayer dies!")
menu();
return;
}
if (monster_hp<=0) {
document.write("\nPlayer wins!")
menu();
return;
}
if (fight=1) {
document.write("\nPlayer hp:" + player_hp)
document.write("\nMonster hp:" + monster_hp)
document.write("\n");
match()
}
}, interval)
}
One easy way to handle this is to simply create a <div> or a <span> element that has an ID attribute like this:
<div id="status"> </div>
Now you can access this element by using the Javascript method
document.querySelector("#status") and then use the innerHTML function of that element to change the internal content. You can even place the document.querySelector function into a convenient function which I have named send_status()
Here's the whole thing
/* default values */
var player_hp = 300;
var monster_dmg = 30;
var monster_hp = 200;
var interval = 500;
var player_dmg = 50;
match();
/* heres a function that will replace your document.write() functions */
function send_status(message) {
document.querySelector("#status").innerHTML = message;
}
function match() {
setTimeout(function() {
player_hp -= monster_dmg
monster_hp -= player_dmg
if (player_hp <= 0) {
send_status("\nPlayer dies!") // replaced document.write with send_status
menu();
return;
}
if (monster_hp <= 0) {
send_status("\nPlayer wins!")
menu();
return;
}
if (fight = 1) {
send_status("\nPlayer hp:" + player_hp)
send_status("\nMonster hp:" + monster_hp)
send_status("\n");
match()
}
}, interval)
}
function menu() {}
#game {
width: 100%;
height: 100px;
border: 2px solid black;
}
#status {
width: 100%;
height: 50px;
background-color: grey;
}
<div id="game">Game Goes Here</div>
<!-- here is your status area -->
<div id="status"></div>
You should create a results div, in which will be shown the match result.
Just add <div id="match_results"></div> in your HTML code.
And replace all yours document.write() for
document.getElementById('match_results').innerHTML += "<br>Player wins!"
This command is appending content in the element with ID match_results.
You should use <br> instead of \n because it is the proper way to break line in HTML code.
Related
I have a small test page setup to test a sprite sheet I have. Each sprite in sprites.css looks like this...
.a320_0 {
top: 0px;
left: 0px;
width: 60px;
height: 64px;
background: url("images/sprites.png") no-repeat -787px -398px;
}
My page looks like this...
var i = 0
function imageChange() {
setTimeout(function() {
var hdg = i * 15;
document.getElementById('image').className = "a320_" + hdg;
i++;
if (i < 24) {
imageChange();
}
}, 1000)
}
imageChange()
<div id='imageContainer'>
<div id='image'></div>
</div>
I'm logging the class name during the loop and can see it changing and the names correspond to classes that exist in my style sheet. sprites.css and sprites.png are both in the images folder and the images folder is in the same directory as my page.
If I just copy one of the rules from my style sheet and put it directly onto my page and replace the name with #image for testing purposes I can display that particular image so my sprite coordinates are fine but if I do the same thing on my actual css file I don't get the same result leading me to believe that my style sheet might not be loading. Even if I just put the styles directly into my document and try to use .className = , it still doesn't work. I had this working recently but it doesn't seem to be working anymore. I'm kind of lost here...
It should be document.getElementById("image").classList.add("a320_" + hdg);.
var i = 0;
function imageChange() {
setTimeout(function() {
var hdg = i * 15;
document.getElementById("image").classList.add("a320_" + hdg);
i++;
if (i < 24) {
imageChange();
}
}, 1000);
}
imageChange();
.a320_0 {
top: 0px;
left: 0px;
width: 60px;
height: 64px;
background: url("https://source.unsplash.com/random") no-repeat -787px -398px;
}
<div id='imageContainer'>
<div id='image'></div>
</div>
Codepen
While your script is correct, you seem to have made a major syntax error which is not giving you the desired results.
When adding class name to an HTML element using JavaScript, the syntax is as follows:
selector.property.action("property value");
for example your code should be:
document.getElementById('image').classList.add("a320_" + hdg);
So the correction needs to be done only in the javascript part:
var i = 0
function imageChange() {
setTimeout(function() {
var hdg = i * 15;
document.getElementById('image').classList.add("a320_" + hdg)
i++;
if (i < 24) {
imageChange();
}
}, 1000)
}
imageChange()
Hope this was helpful!
Its supposed to type one letter at a time when you open the page, however, it is not showing up at all. I'm a newbie at this javascript stuff.
HTML
<div class="wrap">
<div class="test type" data-text="Hi, my name is John Doe"></div>
</div>
CSS
body {
font: 16px/20px sans-serif;
}
.wrap {
width: 500px;
margin: 30px auto;
text-align: center;
}
.test {
margin-top: 10px;
text-align: left;
}
JS
function typeWriter(text, n) {
if (n < (text.length)) {
$('.test').html(text.substring(0, n+1));
n++;
setTimeout(function() {
typeWriter(text, n)
}, 100);
}
}
$('.type').click(function(e) {
e.stopPropagation();
var text = $('.test').data('text');
typeWriter(text, 0);
});
Use this, I made it worked in less code.
Another thing i did is used some random time to give real world effect..
$(function(){
var txt = $(".type").data("text").split("");
txt.forEach(function(chr, i){
var rand = Math.floor(Math.random() * 100) + 1;
setTimeout(function(){
$(".type").append( chr );
},300*(i+1) + rand)
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test type" data-text="Hi, my name is John Doe"></div>
$(function(){
function typeWriter(text, n) {
if (n < (text.length)) {
$('.test').html(text.substring(0, n+1));
n++;
setTimeout(function() {
typeWriter(text, n)
}, 100);
}
}
$('.type').click(function(e) {
e.stopPropagation();
var text = $('.test').data('text');
typeWriter(text, 0);
});
});
body {
font: 16px/20px sans-serif;
}
.wrap {
width: 500px;
margin: 30px auto;
text-align: center;
}
.test {
margin-top: 10px;
text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">
<div class="test type" data-text="Hi, my name is John Doe">Click me</div>
</div>
You needed to add something to click. (I added the text 'click me' in the div).
You may miss the CDN.
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
Your codes are good.
Here's another example JavaScript code that types out a string one letter at a time, with a delay of 500 milliseconds between each letter:
const myString = "Hello, world!"; // The string to be typed out
let i = 0; // Index of the current letter to be typed out
function typeString() {
if (i < myString.length) { // Check if there are more letters to type out
document.getElementById("myText").innerHTML += myString.charAt(i); // Add the next letter to the text
i++; // Increment the index for the next letter
setTimeout(typeString, 500); // Call this function again in 2 seconds
}
}
typeString(); // Call the function to start typing out the string
<div id="myText"></div>
This code uses a recursive function called typeString() that checks if there are more letters to type out, adds the next letter to a specified HTML element using the innerHTML property, increments the index for the next letter, and then sets a delay of 2 seconds using the setTimeout() method before calling itself again to type out the next letter. The function is called initially to start typing out the string. Note that you should replace "myText" in the code with the ID of the HTML element where you want the string to be displayed.
I am trying to set interval to a function that is only called when user scrolls below a certain height. My code return no errors and the function does not run either. However, I tried logging a random number at the end of the function and it doesn't so I think it has to do with my function. Take a look:
var firstString = ["This ", "is ", " me."];
var firstPara = document.querySelector("#firstPara");
var distanceSoFar = (document.body.scrollTop);
window.addEventListener("scroll", function() {
setInterval(slideIn, 450);
});
function slideIn() {
if (distanceSoFar > "130") {
for (var i = 0; i < firstString.length; i++) {
var stringOut = firstString.shift();
firstPara.innerHTML += stringOut;
console.log("5");
}
}
};
firstPara is just a paragraph in a div on the page. So the idea is to place some text in it on interval when a user scrolls into that view like so:
body {
height: 1000px;
}
div {
position: relative;
top: 700px;
}
div #firstPara {
border: 1px solid;
}
Part of your code is working. It handles the scroll event correctly and the slideIn function is called but the condition distanceSoFar > "130" is never met.
I'd suggest two changes to make your code work as you expect:
Use document.documentElement.scrollTop instead of document.body.scrollTop. document.body.scrollTop may return incorrect values (0) on some browsers. Look at this answer, for example.
Declare distanceSofar inside of the slideIn function. You declared the variable on the top of your code, so it stores a static value of the scrollTop property.
I'd avoid using setInterval inside a scroll event handler, you are setting a lot of intervals and not clearing them. I added some console.logs to show you how the slideIn function keeps being called even when the user is not scrolling.
A final tip: the scrollTop property is a number, so you can compare it to 130 instead of "130".
Here is the working fiddle.
I tried your code. I think it is working as you expected. I also added a clearInterval inorder to clear the timer after printing all text and also to avoid repeated calling.
<html>
<head>
<style>
body {
height: 1000px;
}
div {
position: relative;
top: 700px;
}
div #firstPara {
border: 1px solid;
}
</style>
<script>
function start(){
var s =0;
var interval = undefined;
function slideIn() {
console.log(distanceSoFar);
if (distanceSoFar > "130") {
while ( firstString.length > 0) {
var stringOut = firstString.shift();
firstPara.innerHTML += stringOut;
console.log(s++);
}
clearInterval(interval);
interval = undefined;
}
};
var firstString = ["This ", "is ", " me."];
var firstPara = document.querySelector("#firstPara");
var distanceSoFar = (document.body.scrollTop);
window.addEventListener("scroll", function() {
if(!interval)
interval = setInterval(slideIn, 450);
});
};
</script>
</head>
<body onload="start()">
<div id="firstPara"/>
</body>
<html>
Here is my fiddle link
I guess my question is clear by title itself. Still, what I am looking for is an way to bind click event on the image added using css's background-image property.
I know, I could have achieved the similar functionality (of placing image over input field using this way or this way) by simply positioning <img> tag over input box and then handling the required events but that way didn't seem too flexible with input fields of varying width and height or if the wrapping div doesn't have position:relative; as its property.
If adding event on image loaded with background-image is not possible then how to make the later approach more flexible.
Hope I have conveyed my issues clearly.
Thanks.
Something like this appears to also work:
$('.cross').click(function(e) {
var mousePosInElement = e.pageX - $(this).position().left;
if (mousePosInElement > $(this).width()) {
$(this).val('');
}
});
Link to example
So you need to bind the click event to the image but not using an embebed attributte that's really a very good and dificult question by the way.
I know my approach is complicated but is the only I can figure right now.
You can get the image size (widthImage and heightImage) and know the position relatives of one to another (here is a way of calculating a position of an objet relative to anohter:jQuery get position of element relative to another element) you may use it to calculate the position of the input in the whole screen
and try something like this:
$(document).ready(function(){
$('body').on('click', 'input.cross', function (e) {
var widthInput = parseInt($(this).css('width'),10);
var heightInput = parseInt($(this).css('height'),10);
var position = $(this).position();
var top = position.top;
var left = position.left;
var sizesRelativesInPercentage = $(this).css('background-size').split(/ +/);
var widthPorcentage = parseInt(sizesRelativesInPercentage[0],10);
var heightPorcentage = parseInt(sizesRelativesInPercentage[1],10);
var widthImage = (widthInput * widthPorcentage)/100;
var heightImage = (heightInput * heightPorcentage)/100;
var xFinalImageFinish= (left+widthInput);
var yFinalImageFinish = (top+heightInput);
// Fire the callback if the click was in the image
if (e.pageX >= xFinalImageStart && e.pageX <= xFinalImageFinish &&
e.pageY >= yFinalImageStart && e.pageY <= yFinalImageFinish) {
// Prevent crazy animations and redundant handling
$(this).off('click');
alert('click on the image');
//Do whatever you want
}
});
});
This is only an idea...I am trying to make a fiddle about this, hope so :O
As pointed out by #Felix King
Since the image is not an element in the document, it does not trigger
events and you cannot bind a handler to it. You have to use a
workaround.
Here is a possible work-around (in jquery, but could just as easily be POJS).
CSS
.wrapper {
padding: 1px;
display: inline-block;
border: 2px LightGray inset;
}
.wrapperFocus {
border: 2px DarkGray inset;
}
.textInput {
padding: 0;
border:none;
outline: none;
height: 20px;
width: 150px;
}
.cross {
float: right;
height: 20px;
width: 20px;
background-image:url('http://s20.postimg.org/6125okgwt/rough_Close.png');
background-repeat:no-repeat;
background-position: center;
background-size:90%;
cursor: pointer;
}
HTML
<fieldset class="wrapper">
<input type="text" class="textInput" /><span class="cross"></span>
</fieldset>
<fieldset class="wrapper">
<input type="text" class="textInput" /><span class="cross"></span>
</fieldset>
<fieldset class="wrapper">
<input type="text" class="textInput" /><span class="cross"></span>
</fieldset>
<hr>
<button>submit</button>
Javascript
$(document).on("click", "span.cross", function () {
$(this).prev().val("");
}).on("focus", "input.textInput", function () {
$(this).parent().addClass("wrapperFocus");
}).on("blur", "input.textInput", function () {
$(this).parent().removeClass("wrapperFocus");
});
On jsfiddle
Or if you want to do it without the additional CSS and HTML, then this should be cross-browser (POJS as you already have a jquery example).
CSS
.cross {
height: 20px;
width: 150px;
background-image:url('http://s20.postimg.org/6125okgwt/rough_Close.png');
background-repeat:no-repeat;
background-position:right center;
background-size:10% 90%;
z-index: -1;
padding-right: 6%;
}
HTML
<input type="text" class="cross" />
<input type="text" class="cross" />
<input type="text" class="cross" />
<hr>
<button>submit</button>
Javascript
function normalise(e) {
e = e || window.event;
e.target = e.target || e.srcElement;
return e;
}
var getWidth = (function () {
var func;
if (document.defaultView.getComputedStyle) {
func = document.defaultView.getComputedStyle;
} else if (target.currentStyle) {
func = function (t) {
return t.currentStyle;
}
} else {
func = function () {
throw new Error("unable to get a computed width");
}
}
return function (target) {
return parseInt(func(target).width);
};
}());
function isInputCross(target) {
return target.tagName.toUpperCase() === "INPUT" && target.className.match(/(?:^|\s)cross(?!\S)/);
}
function isOverImage(e) {
return (e.clientX - e.target.offsetLeft) > getWidth(e.target);
}
function clearCrossInput(e) {
e = normalise(e);
if (isInputCross(e.target) && isOverImage(e)) {
e.target.value = "";
}
}
document.body.onclick = (function () {
var prevFunc = document.body.onclick;
if ({}.toString.call(prevFunc) === "[object Function]") {
return function (ev) {
prevFunc(ev);
clearCrossInput(ev);
};
}
return clearCrossInput;
}());
On jsfiddle
But if you want the cursor to change when hovered over the position then you will need to do some extra work. Like this (you could just as easily do this with jquery too).
Javascript
function hoverCrossInput(e) {
e = normalise(e);
if (isInputCross(e.target)) {
if (isOverImage(e)) {
e.target.style.cursor = "pointer";
return;
}
}
e.target.style.cursor = "";
}
document.body.onmousemove = (function () {
var prevFunc = document.body.onmousemove;
if ({}.toString.call(prevFunc) === "[object Function]") {
return function (ev) {
prevFunc(ev);
hoverCrossInput(ev);
};
}
return hoverCrossInput;
}());
On jsfiddle
I do something similar by using an <input type="text" ... > immediately followed by an <input type="button">
The button is given a background image and positioned-relative to move it into the text field; essentially...
position: relative;
top: 4px;
right: 1.6em;
height: 16px;
width: 16px;
border: none;
Then I just add a dead-plain click handler to the button, no computations necessary.
The height x width would depend on your image, and you would tweak the top and right to fit your situation.
This fiddle shows it pared down to the bare essentials.
I have a given list of p elements on my html code.
On page load, I try to queuing modifications of each <p> elements's content by a given interval of time (1sec).
Given the html:
<p>I want to change first!</p>
<p>I want too!</p>
<p>Me 3rd !</p>
<p>Hey, don't forget me!</p>
the CSS:
p { padding: 2px 5px 0px 10px; }
.p { color: #999; }
.green { color:green; border-bottom: 1px solid #888; background: #EEE; }
What should be the JS to since I want to chain up modification. Literally: the first p sentence to be CSS / HTML modified first, 1sec later the 2nd line should be replaced, 1sec later the 3rd line, 4sec later the 4th line, etc.
$("p").ready(function(){
setInterval(function () {
$('p').text('aaaahhhhh.... happy!')
}, 1000);
});
That's fail (fiddle).
What I am doing wrong ? should I use a for loop, each(), instead of selector + setInterval ? please forward keywords so I may dig in the relevant docs. Fiddle appreciate~
Try this
$(document).ready(function(){
var st=null;
var i=0;
st=setInterval(function () {
$('p').eq(i).text('aaaahhhhh.... happy!');
if(i==$('p').length-1)// one less because i initialised by 0.
clearTimeout(st);
i++
}, 1000);
});
Check live demo here http://jsfiddle.net/gT3Ue/14/
(function next($set, i) {
setTimeout(function () {
$set.eq(i).text('aaaahhhhh.... happy!');
if (i < $set.length - 1) {
next($set, i + 1);
}
}, 1000);
// /\
// ||------ the delay
}($('p'), 0));
// /\ /\
// || ||-- the starting index
// ||----- -- your set of elements
demo: http://jsbin.com/otevif/1/
function modifyTargetDeferred(target) {
target.first().text('ahhh... happy');
if (target.length > 1) {
setTimeout(function() {
modifyTargetDeferred(target.not(':first'));
}, 1000);
}
}
setTimeout(function() {
modifyTargetDeferred($('p'));
}, 1000);
Your interval is working use append instead of text to see the effect. Use document.ready not $("p").ready
Live Demo
$(document).ready(function(){
setInterval(function () {
$('p').append('aaaahhhhh.... happy!')
}, 1000);
});
Live Demo
i = 0;
$(document).ready(function () {
div1 = $('#div1');
parry = $("p");
setInterval(function () {
div1.append(parry.eq(i++).text() + '<br />')
if (i > 3) i = 0;
}, 400);
});