JavaScript, Trying to get buttons to move on click - javascript

/*
var young_link = {
power: 30,
cpower: 20,
hp: 3,
image: "../images/young_link.jpg",
};
var young_zelda = {
power: 30,
cpower: 20,
hp: 3,
}
var impa = {
power: 30,
cpower: 20,
hp: 3,
}
var hey = {
power: 30,
cpower: 20,
hp: 3,
}
//$("#test").html(young_link);
console.log(young_link);*/
$(document).ready(function() {
var hero_image = new Array();
hero_image[0] = new Image();
hero_image[0].src = 'assets/images/link.png';
hero_image[0].id = 'image';
hero_image[1] = new Image();
hero_image[1].src = 'assets/images/bongo.png';
hero_image[1].id = 'image';
hero_image[2] = new Image();
hero_image[2].src = 'assets/images/gandondorf.jpg';
hero_image[2].id = 'image';
hero_image[3] = new Image();
hero_image[3].src = 'assets/images/queen.png';
hero_image[3].id = 'image';
//var test = "<img src= '../images/young_link.jpg'>";
//var young_hero = ["young_link","young_zelda","impa", "malon"];
var young_hero = ["Link", "Bongo Bongo","Gandondorf","Queen Gohma"];
var health = [100, 70, 120, 50];
for (var i = 0; i < young_hero.length; i++) {
var hero_btns = $("<buttons>");
hero_btns.addClass("hero hero_button");
hero_btns.attr({"data-name":young_hero[i],"data-health":health[i],"data-image":hero_image[i]});
hero_btns.text(young_hero[i]);
hero_btns.append(hero_image[i]);
hero_btns.append(health[i]);
$("#buttons").append(hero_btns);
}
$(".hero_button").on("click" , function() {
var battle_ground = $("<div>");
battle_ground.addClass("hero hero_button");
battle_ground.text($(this).data("data-name"));
$("#battle").append(battle_ground);
});
});
The for loop is working and appending the buttons on the screen. But in $(".hero_button").on("click" , function() it is just putting a empty box on the page with a click. So, it is not taking the data that is attached to the button.

Sam answered your question correctly and rightly deserves the accepted answer. But I wanted to give you an insight into how you can do this in a cleaner way, without lots of arrays which must line up. Also without using jQuery at all. Below you can see a more object oriented way to do this.
You can see it in action in this jsFiddle
// Now we have an object which represents a hero. No need to duplicate loads of code.
function Hero(heroData) {
this.name = heroData.name;
this.health = heroData.health;
this.setImage = function() {
this.image = new Image();
this.image.src = heroData.imageSrc;
this.image.id = heroData.imageId;
}
this.createHeroButton = function() {
this.createButtonElement();
this.addButtonToPage();
this.attachButtonEvents();
}
this.createButtonElement = function() {
var heroButton = document.createElement('button');
heroButton.classList.add('hero,hero_button');
heroButton.setAttribute('name', this.name);
heroButton.setAttribute('health', this.health);
heroButton.appendChild(this.image);
this.button = heroButton;
}
this.attachButtonEvents = function() {
this.button.addEventListener('click', this.addButtonToPage.bind(this));
}
this.addButtonToPage = function() {
var container = document.getElementById('container');
container.appendChild(this.button);
}
this.takeDamage = function(damageValue) {
this.health -= damageValue;
this.button.setAttribute('health', this.health);
}
this.setImage();
}
// So here we create a Hero instance, in this case Link, we can use now describe links attributes, image, name, health...
var link = new Hero({
name: 'Link',
health: 100,
imageSrc: 'http://orig12.deviantart.net/8bb7/f/2011/276/4/e/four_swords_link_avatar_by_the_missinglink-d4bq8qn.png',
imageId: 'link-image'
});
var mario = new Hero({
name: 'Mario',
health: 100,
imageSrc: 'http://rs568.pbsrc.com/albums/ss123/stvan000/thumb-super-mario-bros-8bit-Mario.jpg~c200',
imageId: 'mario-image'
});
// Now we can easily make a button and add it to the page
link.createHeroButton();
mario.createHeroButton();
// Lets try decreasing the health on mario
mario.takeDamage(10);
// Because we have an object reference which handles all of our heros state we can decrease his health and update the buttons data without much trouble.

A couple of changes to get the data set and read correctly:
make button tags instead of buttons
use .attr() instead of .data() to get the attributes
See comments inline in the code below.
Also, instead of adding an attribute for the Image object of each item (which will add an attribute like data-image="[Object object]") just add an integer corresponding to the iterator index and use that to reference into the hero_image array when you need to get the corresponding image.
Additionally, you can use Array.forEach() to iterate over the items in the heroes array with a callback function. That way you don't have to worry about updating the iterator variable (i in this case) and indexing into the array. You should take a look at this functional programming guide which has some good exercises.
$(document).ready(function() {
var hero_image = new Array();
hero_image[0] = new Image();
hero_image[0].src = 'assets/images/link.png';
hero_image[0].id = 'image';
hero_image[1] = new Image();
hero_image[1].src = 'assets/images/bongo.png';
hero_image[1].id = 'image';
hero_image[2] = new Image();
hero_image[2].src = 'assets/images/gandondorf.jpg';
hero_image[2].id = 'image';
hero_image[3] = new Image();
hero_image[3].src = 'assets/images/queen.png';
hero_image[3].id = 'image';
var young_heroes = ["Link", "Bongo Bongo", "Gandondorf", "Queen Gohma"];
var health = [100, 70, 120, 50];
young_heroes.forEach(function(young_hero,i) {
var hero_btns = $("<button>");
hero_btns.addClass("hero hero_button");
hero_btns.attr({
"data-name": young_hero,
"data-health": health[i],
//instead of adding an attribute for the image object, just add an index
"data-index": i
});
hero_btns.text(young_hero);
hero_btns.append(hero_image[i]);
hero_btns.append(health[i]);
$("#buttons").append(hero_btns);
});
$(".hero_button").on("click", function() {
var battle_ground = $("<div>");
battle_ground.addClass("hero hero_button");
//use .attr() here instead of .data()
battle_ground.text($(this).attr("data-name"));
/** My additions -
* I am not sure exactly how this should be done
* so adjust accordingly
**/
//additionally, you can add attributes to the new battle_ground item
battle_ground.attr('data-health',$(this).attr("data-health"));
battle_ground.append(hero_image[$(this).attr("data-index")]);
battle_ground.append($(this).attr("data-health"));
/** End my additions **/
$("#battle").append(battle_ground);
});
});
#battle div {
border: 1px solid #555;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="buttons"></div>
Battle ground:
<div id="battle"></div>

Related

Canvas is flickering, img.src access

I got a game with falling pics
I push() the next func into an array
and my pics var bulletinare flickering, so I think it's probably I draw them a lot when use update() func
function rect () {
this.size = [rectSize.x, rectSize.y];
this.imagesSrc = rand(0, 1) ? 'bulletinYes' : 'bulletinNo';
this.position = [rand(0, w-rectSize.x), -rectSize.y];
this.bulletinValue = (this.imagesSrc === 'bulletinYes') ? 'bulletinYesValue' : 'bulletinNoValue';
}
rect.prototype = {
draw: function (){
var bulletin = new Image();
bulletin.src = imagesSrc[this.imagesSrc];
ctx.drawImage(bulletin, this.position[0], this.position[2], this.size[0], this.size[2]);
}
}
I've tried to put var bulletin outside the fuction like so
var bulletin = new Image();
bulletin.src = imagesSrc[this.imagesSrc]; <= ???
function rect () {
this.size = [rectSize.x, rectSize.y];
this.imagesSrc = rand(0, 1) ? 'bulletinYes' : 'bulletinNo';
this.position = [rand(0, w-rectSize.x), -rectSize.y];
this.bulletinValue = (this.imagesSrc === 'bulletinYes') ? 'bulletinYesValue' : 'bulletinNoValue';
}
rect.prototype = {
draw: function (){
ctx.drawImage(bulletin, this.position[0], this.position[1], this.size[0], this.size[1]);
}
}
but I have no idea how to change [this..imagesSrc] so it could work.
And also it is executed only once and pic are not randomizing for each pushed one.
Does anyone have any suggestion how to get rid of the flickering or change bulletin.src = imagesSrc[this.imagesSrc];
here's my github link if u want to see whole script
I just started my coding path, so thanks anyone who could answer this one:)
You create new image each time and trying to draw it before image is loaded.
Better way is prepare all images at start and just draw it.
Little changes in your code and all will work:
Prepare images:
var imagesSrc = {
ballotBoxImgSrc: 'img/ballotBox.png',
bulletinYes: 'img/yes.jpg',
bulletinNo: 'img/no.jpg'
};
var images = {
ballotBoxImgSrc: new Image(),
bulletinYes: new Image(),
bulletinNo: new Image()
}
for(let [name,value] of Object.entries(imagesSrc)) {
images[name].src = value;
}
Draw:
rect.prototype = {
draw: function (){
var bulletin = images[this.imagesSrc];
ctx.drawImage(bulletin, this.position[0], this.position[1], this.size[0], this.size[1]);
}
}

How to change slider value on dat.GUI and how to reset dat.GUI

1) I'm working on a dat.GUI application on which I have 2 sliders. I want to reset one when the other is changed. For example :
var FizzyText = function() {
this.slider1 = 0;
this.slider2 = 0;
};
var gui = new dat.GUI();
var text = new FizzyText();
var slider1 = gui.add(text, 'slider1', 0, 5);
var slider2 = gui.add(text, 'slider2', 0, 5);
slider1.onChange(function(value){
console.log(value);
text.slider2 = 0; // this doesn't work
});
slider2.onChange(function(value){
console.log(value);
text.slider1 = 0; // this doesn't work
});
This is just an example but it is very important that the slider is reseted or set to its default value (in FizzyText).
The example above comes from https://workshop.chromeexperiments.com/examples/gui/#9--Updating-the-Display-Automatically where I can't automatically update the slider
2) I want to add a reset button in which all sliders will be reseted. But with the previous answer I'd be able to reset all values
I found the answer :
gui.__controllers is and array of controllers. So I just added something like that :
var FizzyText = function () {
this.slider1 = 0;
this.slider2 = 0;
};
var gui = new dat.GUI();
var text = new FizzyText();
var slider1 = gui.add(text, 'slider1', 0, 5);
var slider2 = gui.add(text, 'slider2', 0, 5);
/* Here is the update */
var resetSliders = function (name) {
for (var i = 0; i < gui.__controllers.length; i++) {
if (!gui.__controllers.property == name)
gui.__controllers[i].setValue(0);
}
};
slider1.onChange(function (value) {
console.log(value);
resetSliders('slider1');
});
slider2.onChange(function (value) {
console.log(value);
resetSliders('slider2');
});
It's best to reset dat.GUI's values by using the controller's .initialValue instead of hard coding it, so the following would be preferable: gui.__controllers[i].setValue(gui.__controllers[i]);
You can reset all of a GUI's controllers by using gui.__controllers.forEach(controller => controller.setValue(controller.initialValue));

tick method in javascript for canvas

I'm trying to make a tick method for this code.
When I try to put a while loop or time interval it just goes blank.
I want the tick method to call this function without the canvas going blank.
How would i make that tick method
function setup(){
var canvas = document.getElementById('my_canvas');
var ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
var gun = new Image();
var badguy = new Image();
var wall1 = 200;
var ground = new Image();
var back = new Image();
var back2 = new Image();
var back3 = new Image();
var wall = new Image();
var wall2 = new Image();
back.onload = function() {
ctx.drawImage(back, 0, 0, 800, 300);
};
back2.onload = function() {
ctx.drawImage(back2, mountainplace, 0, mtnsize1, 300);
};
back3.onload = function() {
ctx.drawImage(back3, mountainplace2, 0, mtnsize2, 300);
};
ground.onload = function() {
ctx.drawImage(ground, groundplace, 300, 1980, 200);
};
wall.onload = function() {
ctx.drawImage(wall, place2, 250, size2, 100);
};
wall2.onload = function() {
ctx.drawImage(wall2, place, 250, size, 100);
};
badguy.onload = function() {
ctx.drawImage(badguy, badguyplace, 250, 100, 100);
};
gun.onload = function() {
ctx.drawImage(gun, 0, 100, 400, 400);
};
back2.src = "moutain1.png";
back3.src = "moutain2.png";
back.src = "backing.png";
ground.src = "ground1.jpg";
wall.src = "wall.png";
wall2.src = "wall2.png";
badguy.src = "santa2.png";
gun.src = "gun1.png";
};
You need to clarify the question because I'm not sure what exactly you are trying to achieve.
I assume you put some code at the end of your setup() function that performs some operations on the images. But before you can do it you need to wait for the images to load.
BTW: another problem with your code is that the images will be drawn on the canvas in the order in which they load, which may be unpredictable. You probably want to avoid this too.
A solution to your problem (or at least to what I think your problem is) is to first start loading the images and then only perform further operations after they have all been loaded.
You can use the following code to do this:
function makeAllLoadedHandler(image_files_count, on_all_loaded) {
return function() {
--image_files_count;
if (image_files_count == 0) {
// All images loaded, call the function.
on_all_loaded();
}
}
}
function loadAllImages(image_files, on_all_loaded) {
var images = {};
var callback = makeAllLoadedHandler(image_files.length, function() { on_all_loaded(images); } );
for (var i = 0; i < image_files.length; ++i) {
var image = new Image;
image.src = image_files[i];
image.onload = callback;
images[image_files[i]] = image;
}
}
The loadAllImages() function takes an array of image file names and a function to call when all the images have been loaded.
You can use it like this in your code:
function setup() {
var image_files = [
"mountain1.png",
"mountain2.png",
"backing.png",
"ground1.jpg",
"wall.png",
"wall2.png",
"santa2.png",
"gun1.png" ];
loadAllImages(image_files, onAllImagesLoaded);
}
function onAllImagesLoaded(images) {
// Draw your images and perform all the other tasks on them.
// The 'images' object stores each of the Image object under a key that is
// its file name.
ctx.drawImage(images['backing.png'], 0, 0, 800, 300);
// ...
// Do other stuff with the images.
}
You just call the setup() function like you used to and then the onAllImagesLoaded function will be called some time later when all the images are available. You continue your processing in there.
I hope this helps. Although it's possible that your problem is completely different ;)

I can't edit text on layer after add new layer using kineticjs

I have make this http://jsfiddle.net/62Wjc/5/, create and change text on layer but it's static. Now I make script for dynamic add fields + add layer + change layer.
On my script have three functions, which are :
Function CreateTxt for create element and create layer with KineticJS.
Function fRField for remove element
Function ChangeTxt for change text on layer.
And this my script :
$(document).ready(function() {
var nwValue = [];
var nwLayer = {};
var nwTxt = {};
var tulisan = 'Your text here';
var con = $('#idEditor');
var cW = con.width();
var cH = con.height();
var stage = new Kinetic.Stage({
container: 'idEditor',
width: cW,
height: cH
});
$('a[data-selector="get_new_txt"], a[data-selector="get_new_img"]').on('click', function(event){
var time = new Date().getTime();
var regexp = new RegExp($(this).data('id'), 'g');
$('#nF').append($(this).data('fields').replace(regexp, time));
CreateTxt(time);
event.preventDefault();
});
$('#nF').on('click', 'a[data-selector="removeField"]', function(e) {
var a = $(this);
fRField(a);
e.preventDefault();
});
$('#nF').on('keyup', 'input[data-selector="inputName"]', function() {
var a = $(this);
ChangeTxt(a);
});
function CreateTxt(idV) {
var iclone = 0;
nwValue.push(idV);
$.each(nwValue, function( index, value ){
nwLayer["layer"+ value] = new Kinetic.Layer();
});
stage.add(nwLayer["layer"+ idV]);
$.each(nwValue, function( index, value ){
nwTxt["text"+ value] = new Kinetic.Text({
x: 100,
y: 100,
text: "Your text here",
fontSize:18,
fill: 'red',
draggable: true,
id: 'txt'+ value
});
});
nwLayer["layer"+ idV].add(nwTxt["text"+ idV]);
nwLayer["layer"+ idV].draw();
}
function fRField(a){
if(confirm('Are you sure to delete this field ?')) {
a.prev("input[type=hidden]").value = "1";
a.closest(".form-inline").remove();
}
return false;
}
function ChangeTxt(a){
var dataid = a.attr('data-id');
var newValue = a.val();
nwTxt["text"+ dataid].setText(newValue);
nwLayer["layer"+ dataid].draw();
}
});
jsfiddle : http://jsfiddle.net/8oLsoo25/5/
After add a new text, I can't change text on layer first.
Your $.each call for nwValue is ruining things for you. If you place nwValue = []; above nwValue.push(idV); in CreateTxt, everything works as expected. In other words, you're replacing references to the original objects. Also, do you know that a new Layer in Kinetic means a new canvas element in the DOM?

webGL story sphere popups

I am trying to adapt the really cool looking WebGL Story Sphere, source code and css here. There's one big problem: once you click on a news article, the text of the article in the popup is always the same. I want to modify the code so that when you click on an article, the right text appears in the popup.
I'm working from a set of article texts that I specify in the code, e.g. var captions = ["good","better","best"]. Though the article titles and images populate correctly in the popup, I can't get the text to do so. Can you help me?? Here's what I've got:
// function code
var passvar = null; // failed attempt to store texts for later
function initialize() {
math = tdl.math;
fast = tdl.fast;
canvas = document.getElementById("canvas");
g_fpsTimer = new tdl.fps.FPSTimer();
hack();
canvas.addEventListener("mousedown", handleMouseDown, false);
canvas.addEventListener("mousemove", handleMouseMove, false);
canvas.addEventListener("mouseup", handleMouseUp, false);
// Create a canvas 2d for making textures with text.
g_canvas2d = document.createElement('canvas');
window.two2w = window.two2h = g_tilesize;
g_canvas2d.width = two2w;
g_canvas2d.height = two2h;
g_ctx2d = g_canvas2d.getContext("2d");
window.gl = wu.create3DContext(canvas);
if (g_debug) {
gl = wd.makeDebugContext(gl, undefined, LogGLCall);
}
//gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, gl.TRUE);
// Here is where I specify article titles, images, captions
// Titles and images populate the popup correctly, captions don't...
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
var headlines = titles.concat( titles);
var blurbs = captions.concat( captions);
var tmpImages = [];
var tmpHeadlines = [];
var tmpCaptions = [];
// make a bunch of textures.
for (var ii = 0; ii < g_imagesDownGrid; ++ii) {
var textures = [];
for (var jj = 0; jj < g_imagesAcrossGrid; ++jj) {
var imgTexture = new ImgTexture();
textures.push(imgTexture);
if (tmpImages.length == 0) {
tmpImages = images.slice();
}
if (tmpHeadlines.length == 0) {
tmpHeadlines = headlines.slice();
}
if (tmpCaptions.length == 0) {
tmpCaptions = blurbs.slice();
}
var rando = math.randomInt(tmpImages.length);
var img = tmpImages.splice(rando, 1)[0];
var headline = tmpHeadlines.splice(rando, 1)[0];
var caption = tmpCaptions.splice(rando, 1)[0];
passvar = caption;
if (img.indexOf('videoplay.jpg') > -1){
window.vidtexture = imgTexture;
images = images.slice(1); // dont use that thumb again.
headlines = 'WebGL Brings Video To the Party as Well'
}
imgTexture.load(img, /* "[" + jj + "/" + ii + "]" + */ headline);
}
g_textures.push(textures);
}
// And here's where I try to put this in a popup, finally
// But passvar, the stored article text, never refreshes!!!
<div id="story" class="prettybox" style="display:none">
<img class="close" src="imagesphere/assets/close.png">
<div id="storyinner">
<input id = "mytext">
<script>document.getElementById("mytext").value = passvar;</script>
</div>
</div>
And here is my click handler code:
function sphereClick(e){
window.console && console.log('click!', e, e.timeStamp);
var selected = g_textures[sel.y][sel.x];
window.selected = selected;
animateGL('eyeRadius', glProp('eyeRadius'), 4, 500);
var wwidth = $(window).width(),
wheight = $(window).height(),
story = $('#story').width( ~~(wwidth / 7 * 4) ).height( ~~(wheight / 6 * 5) ),
width = story.width(),
height = story.height(),
miniwidth = 30;
story.detach()
.find('#storyinner').find('h3,img,caption').remove().end().end()
.show();
story.css({
left : e.pageX,
top : e.pageY,
marginLeft : - width / 2,
marginTop : - height / 2
}).appendTo($body); // we remove and put back on the DOM to reset it to the correct position.
$('style.anim.story').remove();
$('<style class="anim story">')
.text( '.storyopen #story { left : ' + (wwidth / 3 * 2) + 'px !important; top : ' + wheight / 2 + 'px !important; }' )
.appendTo($body);
$(selected.img).prependTo('#storyinner').parent();
$('<h3>').text(selected.msg.replace(/\(.*/,'')).prependTo('#storyinner');
$body.addClass('storyopen');
} // eo sphereClick()
There's a lot wrong here, but here's a start. It won't solve your problem, but it will help you avoid issues like this.
var passvar = null; is a global variable.
Your loop for (var ii = 0; ... sets that global variable to a new value on every iteration.
Later, you click something and the global variable passvar is never changed.
If you want to use this pattern, you need to set passvar from your click handler so it has the value that was clicked. Since you didn't actually post your click handlers, it's hard to advise more.
But this is also a bad pattern, functions take arguments for a good reason. Since you have to find your clicked item in the click handler anyway, why not pass it directly which does involve a shared global variable at all?
var handleMouseUp = function(event) {
var story = findClickedThing(event);
if (obj) {
showPopup(story.texture, story.caption);
}
}
Which brings me to this:
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
When you have 3 arrays, all of the same length, each array describing a different property of an object, you are doing it wrong. What you want, is one array of objects instead.
var stories = [
{
title: "a",
caption: "good",
image: "imagesphere/assets/1.jpg"
}, {
title: "b",
caption: "better",
image: "imagesphere/assets/bp/2.jpg"
}, {
title: "c",
caption: "best",
image: "imagesphere/assets/bp/3.jpg"
},
];
console.log(stories[1].caption); // "better"
Now once you find the clicked object, you can just ask it what it's caption is. And you can pass the whole object to the popup maker. And no field is handled differently or passed around in a different manner, because you are not passing around the fields. You are passsing the entire object.

Categories

Resources