Changes to Javascript created element doesn't reflect to DOM - javascript

I have a class, that is supposed to display grey overlay over page and display text and loading gif. Code looks like this:
function LoadingIcon(imgSrc) {
var elem_loader = document.createElement('div'),
elem_messageSpan = document.createElement('span'),
loaderVisible = false;
elem_loader.style.position = 'absolute';
elem_loader.style.left = '0';
elem_loader.style.top = '0';
elem_loader.style.width = '100%';
elem_loader.style.height = '100%';
elem_loader.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
elem_loader.style.textAlign = 'center';
elem_loader.appendChild(elem_messageSpan);
elem_loader.innerHTML += '<br><img src="' + imgSrc + '">';
elem_messageSpan.style.backgroundColor = '#f00';
this.start = function () {
document.body.appendChild(elem_loader);
loaderVisible = true;
};
this.stop = function() {
if (loaderVisible) {
document.body.removeChild(elem_loader);
loaderVisible = false;
}
};
this.setText = function(text) {
elem_messageSpan.innerHTML = text;
};
this.getElems = function() {
return [elem_loader, elem_messageSpan];
};
}
Problem is, when I use setText method, it sets innerHTML of elem_messageSpan, but it doesn't reflect to the span, that was appended to elem_loader. You can use getElems method to find out what both elements contains.
Where is the problem? Because I don't see single reason why this shouldn't work.
EDIT:
I call it like this:
var xml = new CwgParser('cwg.geog.cz/cwg.xml'),
loader = new LoadingIcon('./ajax-loader.gif');
xml.ondataparse = function() {
loader.stop();
document.getElementById('cover').style.display = 'block';
};
loader.setText('Loading CWG list...');
loader.start();
xml.loadXML();
xml.loadXML() is function that usually takes 3 - 8 seconds to execute (based on download speed of client), thats why I'm displaying loading icon.

Related

Not being able to Load Image from a function To HTML Canvas

I am trying to place the screenshot image into html canvas but not being able to. I have taken screenshot of current tab by using following chrome API. Trying to make a chrome extension.
/* background.js */
let id = 100;
//calling chrome api
chrome.browserAction.onClicked.addListener(() => {
chrome.tabs.captureVisibleTab((screenshotUrl) => {
const viewTabUrl = chrome.extension.getURL('screenshot.html?id=' + id++)
let targetId = null;
//checking if the opened tab id is the same as the target id
chrome.tabs.onUpdated.addListener(function listener(tabId, changedProps) {
if (tabId != targetId || changedProps.status != "complete")
return;
chrome.tabs.onUpdated.removeListener(listener);
const views = chrome.extension.getViews();
for (let i = 0; i < views.length; i++) {
let view = views[i];
if (view.location.href == viewTabUrl) {
view.setScreenshotUrl(screenshotUrl);
return;
}
}
});
//chrome tabs create method
//no listener on create event because the tab’s URL may not be set at the time this event is fired
chrome.tabs.create({ url: viewTabUrl }, (tab) => {
targetId = tab.id;
});
});
});
But not able to call the image from the function
function setScreenshotUrl(url) {
document.getElementById('target').src = url;
};
var cnv = document.getElementById("conv");
cnv.onclick = function() {
var x = document.getElementById("target").src;
document.getElementById("demo").innerHTML = x;
};
window.addEventListener('load', function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("target");
ctx.drawImage(img, 10, 10, 300, 175, 0, 0, 100, 175);
});
The problem was image was not ready at windows on load event, verified by checking the innerHTML of the image, while if I try to do the same thing in onClick event, the image is successfully loaded into canvas.

Change global variables by js function

I wanna change a group of scrolling images by clicking on button. question here is how to change the global variables by these function
please see the attached codes,
I wanna initiate the stack() function when onload and change the scrolling images set by onclick;
Should I add an onload event and seperately call the stack() funtions, only using the local var?
thanks,
Joe
var images = imagest;
function softtissue(){
var images = imagest;
}
function bone(){
var images = imagebone;
}
function lung(){
var images = imagelung;
}
var stack = new ImageStack({
images: images,
height: '512px',
width: '512px'
});
document.querySelector('.example').appendChild(stack);
// how to use the funciton on line 94
// for questions email felix#demont.is
var images10 = [
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg"
];
var imagesbone = [
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg",
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg"
];
var imageslung = [
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg",
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg",
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg"
];
function ImageStack(options) {
var self = this;
self.img_array = options.images;
self.stack = document.createElement('div');
self.stack.style.overflow = 'auto';
self.stack.style.maxWidth = '100%';
self.stack.style.height = options.height;
self.stack.style.width = options.width;
self.stack.style.backgroundSize = 'cover'
self.stack.style.position = 'relative';
var typeRegex = /(\D+)/
var sizeType = options.height.match(typeRegex)[0]
var numberRegex = /(\d+)/
self.height_number = Number(options.height.match(numberRegex)[0])
self.wrapper = document.createElement('div');
for (var i = 0; i < self.img_array.length; i++) {
var image = document.createElement('img');
image.src = self.img_array[i];
image.style.display = 'none';
image.style.position = 'absolute';
image.style.width = options.width;
image.style.height = options.height;
image.style.top = 0;
image.style.left = 0;
image.dataset.iid = i;
self.wrapper.appendChild(image);
}
self.image_elements = self.wrapper.querySelectorAll('img');
self.scrollobject = document.createElement('div');
self.scrollobject.style.width = '100%';
self.scrollobject.style.position = 'absolute';
self.scrollobject.style.zIndex = '2';
self.img_count = (self.img_array.length > 15) ? self.img_array.length : 15;
self.scrollobject_height = Math.floor(0.1 * self.img_count * self.height_number);
self.scrollobject.style.height = self.scrollobject_height + sizeType;
self.scrollUpdate = function(e) {
self.height_number = self.stack.getBoundingClientRect().height
self.scrollobject_height = Math.floor(0.1 * self.img_count * self.height_number);
var sT = self.stack.scrollTop
var hn05 = self.img_array.length - 1
var hh = (self.scrollobject_height - self.height_number) / hn05
scrollval = Math.floor(sT / (hh))
self.currentimg = self.image_elements[scrollval].src
self.stack.style.backgroundImage = 'url(' + self.currentimg + ')';
}
self.stack.addEventListener('scroll', self.scrollUpdate);
self.currentimg = self.image_elements[0].src
self.stack.style.backgroundImage = 'url(' + self.currentimg + ')';
window.addEventListener('resize', function() {
var stackRect = self.stack.getBoundingClientRect()
console.log(stackRect)
self.height_number = stackRect.height
self.scrollobject_height = Math.floor(0.1 * self.img_array.length * self.height_number);
self.stack.style.width = stackRect.width + 'px'
self.stack.style.eight = stackRect.width + 'px'
})
self.stack.appendChild(self.wrapper);
self.stack.appendChild(self.scrollobject);
return self.stack;
}
/*problems here*/
/*global var*/
var images = images10;
/*local var*/
function softtissue() {
var images = images10;
}
function bone() {
var images = imagesbone;
}
function lung() {
var images = imageslung;
}
/*how to switch the local var in global function*/
var stack = new ImageStack({
images: images,
height: '512px',
width: '512px'
});
document.querySelector('.example').appendChild(stack);
<div>
<button id="softtissue" type="button" onclick="softtissue();return false" class="button">
Soft Tissue</button>
<button id="bone" type="button" onclick="bone(); return false;" class="button">
Bone</button>
<button id="lung" type="button" onclick="lung(); return false" class="button">
Lung</button>
</div>
<div class="example">
</div>
var images = imagebone; never changes the global but it initializes a local variable. It creates a local variable images inside the function. You shouldn't use var inside functions
function softtissue(){
images = imagest;
}
function bone(){
images = imagebone;
}
function lung(){
images = imagelung;
}
A better approach would be to use images as a parameter to a general function instead of a separate function specific to the image. That way you can add unlimited amounts of images without the need to write an extra function for each image.
So inside the change_image() function, the correct image string just gets taken from the button clicked, instead of there being a function to set some global variable.
// ImageStack mockup
function ImageStack( config ) {
this.images = config.images;
this.height = config.height;
this.width = config.width;
}
ImageStack.prototype.node = function() {
return document.createElement( 'div' ).appendChild( document.createTextNode( this.images ));
};
// click event for all the buttons
function change_image( event ) {
var image_type = event.target.getAttribute( 'data-type' );
var stack = new ImageStack({
images: `image${ image_type }`,
height: '512px',
width: '512px'
});
render( stack.node() );
}
// render function.
// Could be inside the click event, but I would prefer seperate functions.
function render( image ) {
document.querySelector('.example').appendChild( image );
}
Array.from( document.querySelectorAll( 'button' )).forEach(function( button ) {
button.addEventListener( 'click', change_image );
});
<nav>
<button data-type="st">ST</button>
<button data-type="bone">BONE</button>
<button data-type="lung">LUNG</button>
</nav>
<section class="example"></section>
EDIT:
Since the question text got updated and no longer includes the line Or is there a better approach?, this answer might seem weird.
One approach is changing the varibility of the image
adding variability ="hidden" in the imagestack and after creating these three boxes, onclickfunction onlick choose which one to show

Display a loading icon while loading image

I would like to be able to display a GIF while the image is being loaded. Is this possible with the script I am using?
From what I understand I would use something like
$('#image').load { loadingimage.hide }
Here is my code:
$.get('http://192.168.1.69:8090/VirtualRadar/AirportDataThumbnails.json?icao=' + p.Icao + '&reg=' + p.Reg , function(res) {
var error = res.status;
if (error == "404") {
$("#image").attr('src', "placeholder.jpg");
$("#image2").attr('src', "placeholder.jpg");
$("#imageurl").attr('href', "//airport-data.com");
} else {
var imgUrl = res.data[0].image;
var imgHref = res.data[0].link;
$("#image").attr('src', imgUrl);
$("#image2").attr('src', imgUrl);
$("#imageurl").attr('href', imgHref);
}
})
Use the Image.onload attribute or attach an event listener.. load the loading wheel image first then display that while the larger image is loading...
function loadImage(src){
return new Promise(done=>{
var i = new Image();
i.onload = ()=>done(i);
i.src = src;
});
}
const loadImgSrc = "https://media.giphy.com/media/3oEjI6SIIHBdRxXI40/giphy.gif";
const bigImgSrc = "https://www.gannett-cdn.com/-mm-/4252e7af1a3888197136b717f5f93523f21f8eb2/r=x1683&c=3200x1680/local/-/media/USATODAY/onpolitics/2012/10/03/bigbird-16_9.jpg";
loadImage(loadImgSrc).then(img=>{
img.style.maxWidth = "100%";
document.getElementById('myImg').appendChild(img);
loadImage(bigImgSrc).then(img=>{
img.style.maxWidth = "100%";
document.getElementById('myImg').innerHTML = '';
document.getElementById('myImg').appendChild(img);
});
})
<div id=myImg></div>

Using PreloadJS to load images and adding them to CreateJS stage

I'm trying to create a Tri Peaks Solitaire game in Javascript, using CreateJS to help interact with the HTML canvas. I'm not entirely new to programming, as I've taken college courses on Java and C, but I am new to both Javascript and HTML.
I created a large amount of the card game using a Card class and Deck class, with the image adding, event listening, and game logic done in one Javascript file, but this resulted in a lot of messy, somewhat buggy code that I felt needed cleaning up.
I'm trying to implement a separate class for the card table, which will be the canvas, or stage, and it will draw the 4 rows of playable cards, the stock pile, and the waste pile. I'm currently just trying to get the stock pile to show up on the canvas, but it's not happening.
My question is, why is my stock pile not showing up? Also, as you can see, the card images are being loaded when the cards are created. Should I be doing that differently?
Card class:
var Card = function(number) {
this.isFaceUp = false;
//number for image file path
this.number = number;
this.value = Math.ceil( (this.number)/4 );
//back of the card is default image
this.initialize("images/" + 0 + ".png");
console.log("card created")
this.height = this.getBounds().height;
this.width = this.getBounds().width;
//load the card's front image
this.frontImage = new Image();
this.frontImage.src = ( this.getImagePath() );
};
Card.prototype = new createjs.Bitmap("images/" + this.number + ".png");
Card.prototype.getImagePath = function() {
return "images/" + this.number + ".png";
};
Card.prototype.getValue = function () {
return this.value;
}
Card.prototype.flip = function() {
// this.image = new Image();
// this.image.src = ( this.getImagePath() );
this.image = this.frontImage;
this.isFaceUp = true;
};
Card.prototype.getHeight = function() {
return this.height;
};
Card.prototype.getWidth = function() {
return this.width;
};
CardDeck class:
function CardDeck() {
//create empty array
this.deck = [];
//fill empty array
for(i=1; i<=52; i++) {
//fill deck with cards, with i being the number of the card
this.deck[i-1] = new Card(i);
}
//shuffle deck
this.shuffle();
}
CardDeck.prototype.getCard = function() {
if(this.deck.length < 1) alert("No cards in the deck");
return this.deck.pop();
};
CardDeck.prototype.getSize = function() {
return this.deck.length;
};
CardDeck.prototype.shuffle = function() {
for (i=0; i<this.deck.length; i++) {
var randomIndex = Math.floor( Math.random()*this.deck.length );
var temp = this.deck[i];
this.deck[i] = this.deck[randomIndex];
this.deck[randomIndex] = temp;
}
};
CardDeck.prototype.getRemainingCards = function() {
return this.deck.splice(0);
}
CardDeck.prototype.listCards = function() {
for(i=0; i<this.deck.length; i++) {
console.log(this.deck[i].number);
}
};
CardTable class:
var CardTable = function(canvas) {
this.initialize(canvas);
this.firstRow = [];
this.secondRow = [];
this.thirdRow = [];
this.fourthRow = [];
this.stockPile = [];
this.wastePile = [];
//startX is card width
this.startX = ( new Card(0) ).width*3;
//startY is half the card height
this.startY = ( new Card(0) ).height/2;
};
CardTable.prototype = new createjs.Stage();
CardTable.prototype.createStockPile = function(cards) {
for(i=0; i<23; i++) {
cards[i].x = 10;
cards[i].y = 50;
this.stockPile[i] = cards[i];
}
};
CardTable.prototype.addToWastePile = function(card) {
card.x = startX + card.width;
card.y = startY;
this.wastePile.push(card);
this.addChild(card);
this.update();
};
CardTable.prototype.drawStockPile = function() {
for(i=0; i<this.stockPile.length; i++) {
console.log("this.stockPile[i]");
this.addChild(this.stockPile[i]);
}
this.update();
};
HTML file:
<html>
<head>
<title>Tri-Peaks Solitaire</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.createjs.com/easeljs-0.8.1.min.js"></script>
<script src="card.js"></script>
<script src="carddeck.js"></script>
<script src="cardtable.js"></script>
<script>
function init(){
var canvas = document.getElementById("canvas");
var table = new CardTable("canvas");
deck = new CardDeck();
table.createStockPile(deck.getRemainingCards());
table.drawStockPile();
table.update();
}
</script>
</head>
<body onload="init()">
<h1>Tri-Peaks Solitaire</h1>
<canvas style='border: 5px solid green; background: url("images/background.jpg");'
id="canvas" width="1000" height="450">
</canvas>
</body>
</html>
PRELOADJS UPDATE:
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);
var gameDeck = new CardDeck();
var numbers = [];
var preloader;
var progressText = new createjs.Text("", "20px Arial","#FF0000");
progressText.x = 50;
progressText.y = 20;
stage.addChild(progressText);
stage.update();
setupManifest();
startPreload();
function setupManifest() {
for(i=0; i<=52; i++) {
console.log("manifest");
manifest.push( {src:"images/" + i + ".png",
id: i} );
numbers.push(i);
}
}
function startPreload() {
preload = new createjs.LoadQueue(true);
preload.on("fileload", handleFileLoad);
preload.on("progress", handleFileProgress);
preload.on("complete", loadComplete);
preload.on("error", loadError);
preload.loadManifest(manifest);
}
function handleFileLoad(event) {
console.log("A file has loaded of type: " + event.item.type);
//console.log(numbers.pop());
var cardNumber = numbers.pop();
var newCard = new Card(cardNumber);
//faces.push( new Image() );
//faces[ faces.length - 1 ].src = "images/" + cardNumber + ".png";
gameDeck.insertCard(newCard);
}
function loadError(evt) {
console.log("error",evt.text);
}
function handleFileProgress(event) {
progressText.text = (preload.progress*100|0) + " % Loaded";
stage.update();
}
function loadComplete(event) {
console.log("Finished Loading Assets");
}
You are only updating the stage immediately after creating the cards. The cards are loading bitmap images, which is a concurrent operation that takes time. As such, the only time you render the stage is before the images load.
I would suggest using PreloadJS to preload your card images. This will also give you a lot more control over when / how they load, and let you show a progress bar or distractor to the user as they load.
I would suggest waiting for all the images to load and then calling stage.update(). Alternatively use the createjs.Ticker.addEventListener("tick", handleTick); event handler to update the stage for you.
Reference: http://www.createjs.com/docs/easeljs/classes/Ticker.html

Is there a way to access fonts icons from html5 canvas?

I am new to html5 canvas.
I need to display fonticons (fontawesome) as images.
Is this possible? Thanks
It is indeed possible, though it is a bit cumbersome.
Since Canvas will draw with a fallback font if the actual font it not yet ready, and since fonts are lazy loaded you will need to hold of rendering until the font is ready. This should be possible using something like Google/Typekit's Web Font Loader (https://github.com/typekit/webfontloader)
Once the font is ready, you can draw it in canvas as any other string, something like
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = '48px FontAwesome';
ctx.fillText(String.fromCharCode(61449), 10, 50);
The biggest challenge is that you have to remap all the symbols in Font Awesome, the their JavaScript char representations.
Edit:
This can actually be done using the name, by calcualting CSS rules
getFAChar = function (name) {
var elm = document.createElement('i');
elm.className = 'fa fa-' + name;
elm.style.display = 'none';
document.body.appendChild(elm);
var content = window.getComputedStyle(
elm, ':before'
).getPropertyValue('content')
document.body.removeChild(elm);
return content;
};
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = '48px FontAwesome';
ctx.fillText(getFAChar('bed'), 10, 50)
Edit:
To improve performance, FA icons should be cached, especially if the Canvas is redrawn often (adding and removing a lot of DOM elements is not a good idea when trying to reach 60 fps)
var FontAwesome = (function () {
var me = {},
FACache = {};
function find (name) {
var elm = document.createElement('i');
elm.className = 'fa fa-' + name;
elm.style.display = 'none';
document.body.appendChild(elm);
var content = window.getComputedStyle(
elm, ':before'
).getPropertyValue('content')
document.body.removeChild(elm);
return content;
};
me.get = function (name) {
if (!!FACache[name]) return FACache[name];
var c = find(name);
FACache[name] = c;
return c;
};
return me;
}());
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = '48px FontAwesome';
ctx.fillText(FontAwesome.get('bed'), 10, 50);
Edit
Complete example using deferred render, auto css injection and mapping of css chars, though only tested in Chrome (Uses font loading API and Promises without polyfill)
var FontAwesome = function () {
return new Promise(function (done, failed) {
var me = {},
FACache = {};
function find (name) {
var elm = document.createElement('i');
elm.className = 'fa fa-' + name;
elm.style.display = 'none';
document.body.appendChild(elm);
var content = window.getComputedStyle(
elm, ':before'
).getPropertyValue('content')
document.body.removeChild(elm);
return content;
};
me.get = function (name) {
if (!!FACache[name]) return FACache[name];
var c = find(name)[1];
FACache[name] = c;
return c;
};
(function() {
var l = document.createElement('link'); l.rel = 'stylesheet';
l.onload = function () {
document.fonts.load('10px FontAwesome')
.then(function (e) { done(me); })
.catch(failed);
}
l.href = '//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css';
var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
}());
});
};
FontAwesome()
.then(function (fa) {
// All set, and ready to render!
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = '48px FontAwesome';
ctx.fillText(fa.get('bed'), 10, 50);
});
<canvas id="canvas"></canvas>

Categories

Resources