JS for -loop always use last element - scope issues - javascript

var url_array = ["ulr1", "ulr2", "ulr3", "ulr4", "ulr5"];
var img = document.createElement('img');
for (i = 0; i < url_array.length; i++){
var div = document.createElement('div');
div.setAttribute("id", "div"+i);
document.getElementById('main').appendChild(div);
document.getElementById('div'+i).style.width = ImageWidth+5+"px";
document.getElementById('div'+i).style.height = ImageHeight+5+"px";
console.log("\ncreate all the DIVs. \nFor loop count: "+i);
img.src = loadImage(url_array[i], ImageWidth, ImageHeight);
try{throw img}
catch(c_img) {
document.getElementById('div'+i).appendChild(c_img);
console.log("after load, and append, in Catch: "+img.src);
console.log("div NR = "+document.getElementById('div'+i).id);
console.log(document.getElementById('div'+i).childNodes.length);
} //catch
} // FOR
function loadImage(URL, h, w)
{
console.log("loadImage callaed with URL = "+URL);
return url = URL+Date.now().toString(10);
}
For-Loop is supposed to retrieve urls address of an images (from camera) and append them to DIV. DIV and IMGs are created on the fly. Problem is that only last DIV become image holder.
I am using catch-try to force execute code immediately so each separate Div+i will have distinctive image. Also construction like this one (immediately invoked function expression):
(function(){
something here;
})();
for creating "private" scope gives no hope. Either "Let" - which supposed to define variable locally is not helping. *My knowledge here is limited and I'm relying on data found on web site (can give link later if it is not against rules).
Output of console.log() is not helping much.
Everything goes as it should, except for the childNodes.length which is 1 for each for-loop iteration - that means each DIV have its IMG child I guess... If so - why I can't see them?
I feel I am close to what I want to achieve - using Intervals() refresh each DIV with new camera snapshot, but I need to solve this current issue.
Example of code ready to use:
js.js:
var url_array = [
"https://images.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg",
"https://images.pexels.com/photos/45201/kitty-cat-kitten-pet-45201.jpeg",
"https://images.pexels.com/photos/617278/pexels-photo-617278.jpeg"
];
var ImageWidth = 640;
var ImageHeight = 480;
var img = document.createElement('img');
for (i = 0; i < url_array.length; i++){
var div = document.createElement('div');//.setAttribute("id", "div0");
div.setAttribute("id", "div"+i);
document.getElementById('main').appendChild(div);
document.getElementById('div'+i).style.width = ImageWidth+5+"px";
document.getElementById('div'+i).style.height = ImageHeight+5+"px";
var color = ((Math.floor(Math.random() * (16777215)) + 1).toString(16)); // from 1 to (256^3) -> converted to HEX
document.getElementById('div'+i).style.background = "#"+color;
document.getElementById('div'+i).style.width = ImageWidth+5+"px";
document.getElementById('div'+i).style.height = ImageHeight+5+"px";
console.log("\ncreate all the DIVs. \nFor loop count: "+i);
img.src = loadImage(url_array[i], ImageWidth, ImageHeight);
try{throw img}
catch(c_img) {
document.getElementById('div'+i).appendChild(c_img);
console.log("after load, and append, in Catch: "+img.src);
console.log("div NR = "+document.getElementById('div'+i).id);
console.log(document.getElementById('div'+i).childNodes.length);
} // catch
} // FOR
function loadImage(URL, h, w)
{
console.log("loadImage callaed with URL = "+URL);
return url = URL+"?auto=compress&h="+h+"&w="+w;
}
HTML:
<html>
<head>
<meta charset="utf-8">
<STYLE>
div#main {
padding: 5px;
background: black;
}
</STYLE>
</head>
<body>
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "js.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
<div id="main"></div>
</body>
</html>

The problem is that your
var img = document.createElement('img');
is outside the loop - you're only ever creating one img. When appendChild is called on an element that already exists in the DOM (such as on the second, third, fourth, etc iteration), the element gets removed from its previous location and inserted into the new location.
Create the image inside the loop instead, and try not to implicitly create global variables - when declaring new variables, always use let or const.
Also, when you do
var div = document.createElement('div');
you have a reference to the div you just created - there's no need to assign an id to it in order to select it with
document.getElementById('div'+i)
in below lines in the same scope. Instead, just keep referencing the div:
const ImageWidth = 200;
const ImageHeight = 200;
const main = document.getElementById('main');
var url_array = ["ulr1", "ulr2", "ulr3", "ulr4", "ulr5"];
for (let i = 0; i < url_array.length; i++){
const img = document.createElement('img');
const div = document.createElement('div');
main.appendChild(div);
div.style.width = ImageWidth+5+"px";
div.style.height = ImageHeight+5+"px";
img.src = loadImage(url_array[i], ImageWidth, ImageHeight);
div.appendChild(img);
}
console.log(main.innerHTML);
function loadImage(URL, h, w) {
return URL+Date.now().toString(10);
}
div#main {
padding: 5px;
background: black;
}
<div id="main">
</div>

Related

why this javascript code don't work after i reload part of my page with ajax?

I have 3 files with php and js. in first file i load some information and show it to user, then user can change them. for show other information to user i reload part of my page with some code that they are in second php file. i put them in <div id='show_album'>my data</div> and change them with second php file.
for first run my javascript code work fine, but after reloading part of page it never work. what must i change in code that it work after reloading?!
this is part of code that can reload div element with ajax:
<select onchange="showList('showalbum.php?change=',this.value,'show_album')"><option value='1'>1</option> <option value='2'>2</option></select>
in this part of code that in first page i reload my div element with new data.
then in new data i have something like this:
size of picture: 460*345
that show picture link to user and when user click on it, with javascript i show it to user on this page and on my other information that user can close it.but now this rel="lightbox" don't work and when user click on link, this picture open in same window.
this is my javascript code and in <head> i define it:
/*
Table of Contents
-----------------
Configuration
Functions
- getPageScroll()
- getPageSize()
- pause()
- getKey()
- listenKey()
- showLightbox()
- hideLightbox()
- initLightbox()
- addLoadEvent()
Function Calls
- addLoadEvent(initLightbox)
*/
//
// Configuration
//
// If you would like to use a custom loading image or close button reference them in the next two lines.
var loadingImage = './LightBox/loading.gif';
var closeButton = './LightBox/close.gif';
//
// getPageScroll()
// Returns array with x,y page scroll values.
// Core code from - quirksmode.org
//
function getPageScroll(){
var yScroll;
if (self.pageYOffset) {
yScroll = self.pageYOffset;
} else if (document.documentElement && document.documentElement.scrollTop){ // Explorer 6 Strict
yScroll = document.documentElement.scrollTop;
} else if (document.body) {// all other Explorers
yScroll = document.body.scrollTop;
}
arrayPageScroll = new Array('',yScroll)
return arrayPageScroll;
}
//
// getPageSize()
// Returns array with page width, height and window width, height
// Core code from - quirksmode.org
// Edit for Firefox by pHaez
//
function getPageSize(){
var xScroll, yScroll;
if (window.innerHeight && window.scrollMaxY) {
xScroll = document.body.scrollWidth;
yScroll = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
var windowWidth, windowHeight;
if (self.innerHeight) { // all except Explorer
windowWidth = self.innerWidth;
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
// for small pages with total height less then height of the viewport
if(yScroll < windowHeight){
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if(xScroll < windowWidth){
pageWidth = windowWidth;
} else {
pageWidth = xScroll;
}
arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
return arrayPageSize;
}
//
// pause(numberMillis)
// Pauses code execution for specified time. Uses busy code, not good.
// Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
//
function pause(numberMillis) {
var now = new Date();
var exitTime = now.getTime() + numberMillis;
while (true) {
now = new Date();
if (now.getTime() > exitTime)
return;
}
}
//
// getKey(key)
// Gets keycode. If 'x' is pressed then it hides the lightbox.
//
function getKey(e){
if (e == null) { // ie
keycode = event.keyCode;
} else { // mozilla
keycode = e.which;
}
key = String.fromCharCode(keycode).toLowerCase();
if(key == 'x'){ hideLightbox(); }
}
//
// listenKey()
//
function listenKey () { document.onkeypress = getKey; }
//
// showLightbox()
// Preloads images. Pleaces new image in lightbox then centers and displays.
//
function showLightbox(objLink)
{
// prep objects
var objOverlay = document.getElementById('overlay');
var objLightbox = document.getElementById('lightbox');
var objCaption = document.getElementById('lightboxCaption');
var objImage = document.getElementById('lightboxImage');
var objLoadingImage = document.getElementById('loadingImage');
var objLightboxDetails = document.getElementById('lightboxDetails');
var arrayPageSize = getPageSize();
var arrayPageScroll = getPageScroll();
// center loadingImage if it exists
if (objLoadingImage) {
objLoadingImage.style.top = (arrayPageScroll[1] + ((arrayPageSize[3] - 35 - objLoadingImage.height) / 2) + 'px');
objLoadingImage.style.left = (((arrayPageSize[0] - 20 - objLoadingImage.width) / 2) + 'px');
objLoadingImage.style.display = 'block';
}
// set height of Overlay to take up whole page and show
objOverlay.style.height = (arrayPageSize[1] + 'px');
objOverlay.style.display = 'block';
// preload image
imgPreload = new Image();
imgPreload.onload=function(){
objImage.src = objLink.href;
// center lightbox and make sure that the top and left values are not negative
// and the image placed outside the viewport
var lightboxTop = arrayPageScroll[1] + ((arrayPageSize[3] - 35 - imgPreload.height) / 2);
var lightboxLeft = ((arrayPageSize[0] - 20 - imgPreload.width) / 2);
objLightbox.style.top = (lightboxTop < 0) ? "0px" : lightboxTop + "px";
objLightbox.style.left = (lightboxLeft < 0) ? "0px" : lightboxLeft + "px";
objLightboxDetails.style.width = imgPreload.width + 'px';
if(objLink.getAttribute('title')){
objCaption.style.display = 'block';
//objCaption.style.width = imgPreload.width + 'px';
objCaption.innerHTML = objLink.getAttribute('title');
} else {
objCaption.style.display = 'none';
}
// A small pause between the image loading and displaying is required with IE,
// this prevents the previous image displaying for a short burst causing flicker.
if (navigator.appVersion.indexOf("MSIE")!=-1){
pause(250);
}
if (objLoadingImage) { objLoadingImage.style.display = 'none'; }
objLightbox.style.display = 'block';
// After image is loaded, update the overlay height as the new image might have
// increased the overall page height.
arrayPageSize = getPageSize();
objOverlay.style.height = (arrayPageSize[1] + 'px');
// Check for 'x' keypress
listenKey();
return false;
}
imgPreload.src = objLink.href;
var e = document.getElementById('gand');
e.style.display = 'none';
}
//
// hideLightbox()
//
function hideLightbox()
{
// get objects
objOverlay = document.getElementById('overlay');
objLightbox = document.getElementById('lightbox');
// hide lightbox and overlay
objOverlay.style.display = 'none';
objLightbox.style.display = 'none';
// disable keypress listener
document.onkeypress = '';
var e = document.getElementById('gand');
e.style.display = 'block';
}
//
// initLightbox()
// Function runs on window load, going through link tags looking for rel="lightbox".
// These links receive onclick events that enable the lightbox display for their targets.
// The function also inserts html markup at the top of the page which will be used as a
// container for the overlay pattern and the inline image.
//
function initLightbox()
{
if (!document.getElementsByTagName){ return; }
var anchors = document.getElementsByTagName("a");
// loop through all anchor tags
for (var i=0; i<anchors.length; i++){
var anchor = anchors[i];
if (anchor.getAttribute("href") && (anchor.getAttribute("rel") == "lightbox")){
anchor.onclick = function () {showLightbox(this); return false;}
}
}
// the rest of this code inserts html at the top of the page that looks like this:
//
// <div id="overlay">
// <img id="loadingImage" />
// </div>
// <div id="lightbox">
// <a href="#" onclick="hideLightbox(); return false;" title="Click anywhere to close image">
// <img id="closeButton" />
// <img id="lightboxImage" />
// </a>
// <div id="lightboxDetails">
// <div id="lightboxCaption"></div>
// <div id="keyboardMsg"></div>
// </div>
// </div>
var objBody = document.getElementsByTagName("body").item(0);
// create overlay div and hardcode some functional styles (aesthetic styles are in CSS file)
var objOverlay = document.createElement("div");
objOverlay.setAttribute('id','overlay');
objOverlay.onclick = function () {hideLightbox(); return false;}
objOverlay.style.display = 'none';
objOverlay.style.position = 'absolute';
objOverlay.style.top = '0';
objOverlay.style.left = '0';
objOverlay.style.zIndex = '90';
objOverlay.style.width = '100%';
objBody.insertBefore(objOverlay, objBody.firstChild);
var arrayPageSize = getPageSize();
var arrayPageScroll = getPageScroll();
// preload and create loader image
var imgPreloader = new Image();
// if loader image found, create link to hide lightbox and create loadingimage
imgPreloader.onload=function(){
var objLoadingImageLink = document.createElement("a");
objLoadingImageLink.setAttribute('href','#');
objLoadingImageLink.onclick = function () {hideLightbox(); return false;}
objOverlay.appendChild(objLoadingImageLink);
var objLoadingImage = document.createElement("img");
objLoadingImage.src = loadingImage;
objLoadingImage.setAttribute('id','loadingImage');
objLoadingImage.style.position = 'absolute';
objLoadingImage.style.zIndex = '150';
objLoadingImageLink.appendChild(objLoadingImage);
imgPreloader.onload=function(){}; // clear onLoad, as IE will flip out w/animated gifs
return false;
}
imgPreloader.src = loadingImage;
// create lightbox div, same note about styles as above
var objLightbox = document.createElement("div");
objLightbox.setAttribute('id','lightbox');
objLightbox.style.display = 'none';
objLightbox.style.position = 'absolute';
objLightbox.style.zIndex = '100';
objBody.insertBefore(objLightbox, objOverlay.nextSibling);
// create link
var objLink = document.createElement("a");
objLink.setAttribute('href','#');
objLink.setAttribute('title','براي بستن کليک کنيد');
objLink.onclick = function () {hideLightbox(); return false;}
objLightbox.appendChild(objLink);
// preload and create close button image
var imgPreloadCloseButton = new Image();
// if close button image found,
imgPreloadCloseButton.onload=function(){
var objCloseButton = document.createElement("img");
objCloseButton.src = closeButton;
objCloseButton.setAttribute('id','closeButton');
objCloseButton.style.position = 'absolute';
objCloseButton.style.zIndex = '200';
objLink.appendChild(objCloseButton);
return false;
}
imgPreloadCloseButton.src = closeButton;
// create image
var objImage = document.createElement("img");
objImage.setAttribute('id','lightboxImage');
objLink.appendChild(objImage);
// create details div, a container for the caption and keyboard message
var objLightboxDetails = document.createElement("div");
objLightboxDetails.setAttribute('id','lightboxDetails');
objLightbox.appendChild(objLightboxDetails);
// create caption
var objCaption = document.createElement("div");
objCaption.setAttribute('id','lightboxCaption');
objCaption.style.display = 'none';
objLightboxDetails.appendChild(objCaption);
// create keyboard message
var objKeyboardMsg = document.createElement("div");
objKeyboardMsg.setAttribute('id','keyboardMsg');
objKeyboardMsg.innerHTML = 'براي بستن کليد <kbd>x</kbd> را فشار دهيد';
objLightboxDetails.appendChild(objKeyboardMsg);
}
//
// addLoadEvent()
// Adds event to window.onload without overwriting currently assigned onload functions.
// Function found at Simon Willison's weblog - http://simon.incutio.com/
//
function addLoadEvent(func)
{
var oldonload = window.onload;
if (typeof window.onload != 'function'){
window.onload = func;
} else {
window.onload = function(){
oldonload();
func();
}
}
}
addLoadEvent(initLightbox); // run initLightbox onLoad
and i have css for this js that it is not importat but i write it here:
#lightbox {
background-color: #eee;
padding: 10px;
border-bottom: 2px solid #666;
border-right: 2px solid #666;
}
#lightboxDetails {
font-size: 0.8em;
padding-top: 0.4em;
}
#lightboxCaption {
float: left;
}
#keyboardMsg {
float: right;
}
#closeButton {
top: 5px;
right: 5px;
}
#lightbox img {
border: none;
clear: both;
}
#overlay img {
border: none;
}
#overlay {
background: url(../LightBox/overlay.png);
}
* html #overlay {
background-color: #000;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader( src="../LightBox/overlay.png", sizingMethod="scale");
filter: alpha(opacity=70);
opacity: 0.7;
}
i think this code just run one time on window.load() and after i reload part of page it can't load again and don't work.
how i can resolve this problem?
tnks for reading my question...
Because to new html elements added after you need to recall all functions that work with it, for example recall functions that is called on document is created
When you get result from ajax and put it on html page, after write initLightbox();
You need to add initLightbox() here and change them with second php file. for first run my javascript
But you not write that code and I can't help you.
I can say only, put initlightbox after code where you receive response with ajax after lines where you insert new html elements.

Javascript: move new element after createElement

I have created a zombie img in my banner div but I can't get the img to move to the left after it has been created.
createZombie function is on a timer:
createZombieTimer = window.setInterval(createZombie, 1000);
That is in an init() that loads with the body.
function createZombie(){
var imgElem = document.createElement("img");
imgElem.src = "img/zombie_walk_right.gif";
var newZom = document.getElementById('banner').appendChild(imgElem);
newZom.style.height = "40px";
newZom.style.width = "auto";
newZom.style.display = "block";
newZom.style.marginLeft = "50px";
var zomPos = parseInt(newZom.style.marginLeft);
if (zomPos > 0) {
newZom.style.marginLeft = (zomPos + 50) + "px";
}
}
Since it's clear from the comments now what you want to do, I'll post it here as the answer.
You can do this with plain javascript as well. What you will have to do, is use setInterval(). This will execute a function every second, in which you can update the position of the elements.
Example:
// Function to move the zombie by 50 pixels
function moveZombie()
{
// Select the zombie element (will need additional logic to select all of them, just an example)
zomElement = document.getElementById('zombie1');
zomPos = parseInt(zomElement.style.marginLeft);
zomElement.style.marginLeft = (zomPos + 50) + 'px';
}
// Call this function every second
setInterval(moveZombie(), 1000);

Why does my setInterval function not work second time? (JavaScript)

I made a div and I want to make it animate in a specific direction every 1 second. In the code that I have provided there's a function called resetPosition() don't worry about that, it's from my other js file that I linked in the head section(That works perfectly). I just want to know why setInterval() doesn't work correctly?
Here's my code:-
<!DOCTYPE html>
<html>
<head>
<title>Animtion</title>
<link rel="icon" href="http://3.bp.blogspot.com/-xxHZQduhqlw/T-cCSTAyLQI/AAAAAAAAAMw/o48rpWUeg2E/s1600/html-logo.jpg" type="image/jpg">
<script src="easyJs.js"></script>
<style type="text/css">
div{height:100px; width:100px; background:cyan;}
</style>
</head>
<body onload="">
<div id="demo"></div>
</body>
<script type="text/javascript">
setInterval(function(){var x = new element('demo');
x.resetPosition('absolute', '100px', '10px');}, 1000);
</script>
</html>
Here's easyJs:-
function element(elementId){
this.myElement = document.getElementById(elementId);
this.resetColor = changeColor;
this.resetSize = changeSize;
this.resetBackground = changeBackground;
this.resetPosition = changePosition;
this.resetBorder = changeBorder;
this.resetFontFamily = changeFont;
this.resetFontSize = changeFontSize;
this.resetFontStyle = changeFontStyle;
this.resetZindex = changeZindex;
this.resetClass = changeClass;
this.resetTitle = changeTitle;
this.resetMarginTop = changeMarginTop;
this.resetMarginLeft = changeMarginLeft;
this.resetSource = changeSource;
this.resetInnerHTML = changeInnerHTML;
this.resetHref = changeHref;
this.resetTextDecoration = changeTextDecoration;
this.resetFontWeight = changeFontWeight;
this.resetCursor = changeCursor;
this.resetPadding = changePadding;
this.getValue = getTheValue;
this.getName = getTheName;
this.getHeight = getTheHeight;
}
function changeColor(color){
this.myElement.style.color = color;
}
function changeSize(height, width){
this.myElement.style.height = height;
this.myElement.style.width = width;
}
function changeBackground(color){
this.myElement.style.background = color;
}
function changePosition(pos, x, y){
this.myElement.style.position = pos;
this.myElement.style.left = x;
this.myElement.style.top = y;
}
function changeBorder(border){
this.myElement.style.border = border;
}
function changeFont(fontName){
this.myElement.style.fontFamily = fontName;
}
function changeFontSize(size){
this.myElement.style.fontSize = size;
}
function changeZindex(indexNo){
this.myElement.style.zIndex = indexNo;
}
function changeClass(newClass){
this.myElement.className = newClass;
}
function changeTitle(newTitle){
this.myElement.title = newTitle;
}
function changeMarginTop(top){
this.myElement.style.marginTop = top;
}
function changeMarginLeft(left){
this.myElement.style.marginLeft = left;
}
function changeSource(newSource){
this.myElement.src = newSource;
}
function changeHref(newHref){
this.myElement.href = newHref;
}
function changeInnerHTML(newHTML){
this.myElement.innerHTML = newHTML;
}
function changeTextDecoration(decoration){
this.myElement.style.textDecoration = decoration;
}
function changeFontWeight(weight){
this.myElement.style.fontWeight = weight;
}
function changeFontStyle(style){
this.myElement.style.fontStyle = style;
}
function changeCursor(cursor){
this.myElement.style.cursor = cursor;
}
function changePadding(padding){
this.myElement.style.padding = padding;
}
function getTheValue(){
var theValue = this.myElement.value;
return theValue;
}
function getTheName(){
var theName = this.myElement.name;
return theName;
}
function getTheHeight(){
var theHeight = this.myElement.offsetHeight;
return theHeight;
}
This might help you see what and how. (Scroll down to bottom of code):
Fiddle
// Create a new EasyJS object
var el = new element('demo');
// x and y position of element
var x = 0, y = 0;
// Interval routine
setInterval(function(){
x = x + 1; // Increment x by 1
y = y + 1; // Increment y by 1
// Move element to position xy
el.resetPosition('absolute', x + 'px', y + 'px');
// Add text inside element showing position.
el.resetInnerHTML(x + 'x' + y);
// Run five times every second
}, 1000 / 5);
Explanation of original code:
setInterval(function() {
// Here you re-declare the "x" object for each iteration.
var x = new element('demo');
// Here you move the div with id "demo" to position 100x10
x.resetPosition('absolute', '100px', '10px');
// Once every second
}, 1000);
The HTML div element demo initially has no positioning styling (CSS). As such it is rendered in the default position according to the browser defaults.
In first iteration you change the style option position to absolute. That means you can move it anywhere. Secondly you move it to offset 100x10.
On the second and every iteration after that the element has position set to absolute, and it reside at 100x10. Then you say it should be moved to 100x10 – as in same place as it is.
If you do not change either x or y position (left / top), it will stay at 100x10, no mather how many times you run the loop. Run it 100 times a second for a year and it will still be at 100x10 ;-)
Think about it. Everytime the interval runs, it creates a new instance of element "demo".
This demo variable has all the default values your elements object sets it to (if any), and runs the same function each time. That's why it only moves once.
Hoist your element higher and you won't be re-declaring each interval.
<script type="text/javascript">
var x = new element('demo');
setInterval(function(){
x.resetPosition('absolute', '100px', '10px');}, 1000);
</script>
The problem isn't in the setInterval, because a copypasta'd fiddle of the same expression worked properly, so it's probably either an issue with resetPosition or maybe easyJS, though I doubt the latter.
Also, it's unclear whether demo appears on-page, as it's not added anywhere visibly.
EDIT:
If demo is appended somewhere behind the scenes, it's still piling a new demo on that spot every second

How to display whole PDF (not only one page) with PDF.JS?

I've created this demo:
http://polishwords.com.pl/dev/pdfjs/test.html
It displays one page. I would like to display all pages. One below another, or place some buttons to change page or even better load all standard controls of PDF.JS like in Firefox. How to acomplish this?
PDFJS has a member variable numPages, so you'd just iterate through them. BUT it's important to remember that getting a page in pdf.js is asynchronous, so the order wouldn't be guaranteed. So you'd need to chain them. You could do something along these lines:
var currPage = 1; //Pages are 1-based not 0-based
var numPages = 0;
var thePDF = null;
//This is where you start
PDFJS.getDocument(url).then(function(pdf) {
//Set PDFJS global object (so we can easily access in our page functions
thePDF = pdf;
//How many pages it has
numPages = pdf.numPages;
//Start with first page
pdf.getPage( 1 ).then( handlePages );
});
function handlePages(page)
{
//This gives us the page's dimensions at full scale
var viewport = page.getViewport( 1 );
//We'll create a canvas for each page to draw it on
var canvas = document.createElement( "canvas" );
canvas.style.display = "block";
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
//Draw it on the canvas
page.render({canvasContext: context, viewport: viewport});
//Add it to the web page
document.body.appendChild( canvas );
//Move to next page
currPage++;
if ( thePDF !== null && currPage <= numPages )
{
thePDF.getPage( currPage ).then( handlePages );
}
}
Here's my take. Renders all pages in correct order and still works asynchronously.
<style>
#pdf-viewer {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.1);
overflow: auto;
}
.pdf-page-canvas {
display: block;
margin: 5px auto;
border: 1px solid rgba(0, 0, 0, 0.2);
}
</style>
<script>
url = 'https://github.com/mozilla/pdf.js/blob/master/test/pdfs/tracemonkey.pdf';
var thePdf = null;
var scale = 1;
PDFJS.getDocument(url).promise.then(function(pdf) {
thePdf = pdf;
viewer = document.getElementById('pdf-viewer');
for(page = 1; page <= pdf.numPages; page++) {
canvas = document.createElement("canvas");
canvas.className = 'pdf-page-canvas';
viewer.appendChild(canvas);
renderPage(page, canvas);
}
});
function renderPage(pageNumber, canvas) {
thePdf.getPage(pageNumber).then(function(page) {
viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({canvasContext: canvas.getContext('2d'), viewport: viewport});
});
}
</script>
<div id='pdf-viewer'></div>
The pdfjs-dist library contains parts for building PDF viewer. You can use PDFPageView to render all pages. Based on https://github.com/mozilla/pdf.js/blob/master/examples/components/pageviewer.html :
var url = "https://cdn.mozilla.net/pdfjs/tracemonkey.pdf";
var container = document.getElementById('container');
// Load document
PDFJS.getDocument(url).then(function (doc) {
var promise = Promise.resolve();
for (var i = 0; i < doc.numPages; i++) {
// One-by-one load pages
promise = promise.then(function (id) {
return doc.getPage(id + 1).then(function (pdfPage) {
// Add div with page view.
var SCALE = 1.0;
var pdfPageView = new PDFJS.PDFPageView({
container: container,
id: id,
scale: SCALE,
defaultViewport: pdfPage.getViewport(SCALE),
// We can enable text/annotations layers, if needed
textLayerFactory: new PDFJS.DefaultTextLayerFactory(),
annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory()
});
// Associates the actual page with the view, and drawing it
pdfPageView.setPdfPage(pdfPage);
return pdfPageView.draw();
});
}.bind(null, i));
}
return promise;
});
#container > *:not(:first-child) {
border-top: solid 1px black;
}
<link href="https://npmcdn.com/pdfjs-dist/web/pdf_viewer.css" rel="stylesheet"/>
<script src="https://npmcdn.com/pdfjs-dist/web/compatibility.js"></script>
<script src="https://npmcdn.com/pdfjs-dist/build/pdf.js"></script>
<script src="https://npmcdn.com/pdfjs-dist/web/pdf_viewer.js"></script>
<div id="container" class="pdfViewer singlePageView"></div>
The accepted answer is not working anymore (in 2021), due to the API change for var viewport = page.getViewport( 1 ); to var viewport = page.getViewport({scale: scale});, you can try the full working html as below, just copy the content below to a html file, and open it:
<html>
<head>
<script src="https://mozilla.github.io/pdf.js/build/pdf.js"></script>
<head>
<body>
</body>
<script>
var url = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf';
// Loaded via <script> tag, create shortcut to access PDF.js exports.
var pdfjsLib = window['pdfjs-dist/build/pdf'];
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://mozilla.github.io/pdf.js/build/pdf.worker.js';
var currPage = 1; //Pages are 1-based not 0-based
var numPages = 0;
var thePDF = null;
//This is where you start
pdfjsLib.getDocument(url).promise.then(function(pdf) {
//Set PDFJS global object (so we can easily access in our page functions
thePDF = pdf;
//How many pages it has
numPages = pdf.numPages;
//Start with first page
pdf.getPage( 1 ).then( handlePages );
});
function handlePages(page)
{
//This gives us the page's dimensions at full scale
var viewport = page.getViewport( {scale: 1.5} );
//We'll create a canvas for each page to draw it on
var canvas = document.createElement( "canvas" );
canvas.style.display = "block";
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
//Draw it on the canvas
page.render({canvasContext: context, viewport: viewport});
//Add it to the web page
document.body.appendChild( canvas );
var line = document.createElement("hr");
document.body.appendChild( line );
//Move to next page
currPage++;
if ( thePDF !== null && currPage <= numPages )
{
thePDF.getPage( currPage ).then( handlePages );
}
}
</script>
</html>
The following answer is a partial answer targeting anyone trying to get a PDF.js to display a whole PDF in 2019, as the api has changed significantly. This was of course the OP's primary concern. inspiration sample code
Please take note of the following:
extra libs are being used -- Lodash (for range() function) and polyfills (for promises)....
Bootstrap is being used
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div id="wrapper">
</div>
</div>
</div>
<style>
body {
background-color: #808080;
/* margin: 0; padding: 0; */
}
</style>
<link href="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.1.266/pdf_viewer.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.1.266/pdf.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.1.266/pdf_viewer.js"></script>
<script src="//cdn.polyfill.io/v2/polyfill.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
<script>
$(document).ready(function () {
// startup
});
'use strict';
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
alert("Please build the pdfjs-dist library using\n" +
" `gulp dist-install`");
}
var url = '//www.pdf995.com/samples/pdf.pdf';
pdfjsLib.GlobalWorkerOptions.workerSrc =
'//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.1.266/pdf.worker.js';
var loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then(function(pdf) {
// please be aware this uses .range() function from lodash
var pagePromises = _.range(1, pdf.numPages).map(function(number) {
return pdf.getPage(number);
});
return Promise.all(pagePromises);
}).then(function(pages) {
var scale = 1.5;
var canvases = pages.forEach(function(page) {
var viewport = page.getViewport({ scale: scale, }); // Prepare canvas using PDF page dimensions
var canvas = document.createElement('canvas');
canvas.height = viewport.height;
canvas.width = viewport.width; // Render PDF page into canvas context
var canvasContext = canvas.getContext('2d');
var renderContext = {
canvasContext: canvasContext,
viewport: viewport
};
page.render(renderContext).promise.then(function() {
if (false)
return console.log('Page rendered');
});
document.getElementById('wrapper').appendChild(canvas);
});
},
function(error) {
return console.log('Error', error);
});
</script>
If you want to render all pages of pdf document in different canvases, all one by one synchronously this is kind of solution:
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PDF Sample</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="pdf.js"></script>
<script type="text/javascript" src="main.js">
</script>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body id="body">
</body>
</html>
main.css
canvas {
display: block;
}
main.js
$(function() {
var filePath = "document.pdf";
function Num(num) {
var num = num;
return function () {
return num;
}
};
function renderPDF(url, canvasContainer, options) {
var options = options || {
scale: 1.5
},
func,
pdfDoc,
def = $.Deferred(),
promise = $.Deferred().resolve().promise(),
width,
height,
makeRunner = function(func, args) {
return function() {
return func.call(null, args);
};
};
function renderPage(num) {
var def = $.Deferred(),
currPageNum = new Num(num);
pdfDoc.getPage(currPageNum()).then(function(page) {
var viewport = page.getViewport(options.scale);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
if(currPageNum() === 1) {
height = viewport.height;
width = viewport.width;
}
canvas.height = height;
canvas.width = width;
canvasContainer.appendChild(canvas);
page.render(renderContext).then(function() {
def.resolve();
});
})
return def.promise();
}
function renderPages(data) {
pdfDoc = data;
var pagesCount = pdfDoc.numPages;
for (var i = 1; i <= pagesCount; i++) {
func = renderPage;
promise = promise.then(makeRunner(func, i));
}
}
PDFJS.disableWorker = true;
PDFJS.getDocument(url).then(renderPages);
};
var body = document.getElementById("body");
renderPDF(filePath, body);
});
First of all please be aware that doing this is really not a good idea; as explained in https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#allthepages
How to do it;
Use the viewer provided by mozilla;
https://mozilla.github.io/pdf.js/web/viewer.html
modify BaseViewer class, _getVisiblePages() method in viewer.js to
/* load all pages */
_getVisiblePages() {
let visible = [];
let currentPage = this._pages[this._currentPageNumber - 1];
for (let i=0; i<this.pagesCount; i++){
let aPage = this._pages[i];
visible.push({ id: aPage.id, view: aPage, });
}
return { first: currentPage, last: currentPage, views: visible, };
}
If you want to render all pages of pdf document in different canvases
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="pdf.js"></script>
<script src="jquery.js"></script>
</head>
<body>
<h1>PDF.js 'Hello, world!' example</h1>
<div id="canvas_div"></div>
<body>
<script>
// If absolute URL from the remote server is provided, configure the CORS
// header on that server.
var url = 'pdff.pdf';
// Loaded via <script> tag, create shortcut to access PDF.js exports.
var pdfjsLib = window['pdfjs-dist/build/pdf'];
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'worker.js';
var loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then(function(pdf) {
var __TOTAL_PAGES = pdf.numPages;
// Fetch the first page
var pageNumber = 1;
for( let i=1; i<=__TOTAL_PAGES; i+=1){
var id ='the-canvas'+i;
$('#canvas_div').append("<div style='background-color:gray;text-align: center;padding:20px;' ><canvas calss='the-canvas' id='"+id+"'></canvas></div>");
var canvas = document.getElementById(id);
//var pageNumber = 1;
renderPage(canvas, pdf, pageNumber++, function pageRenderingComplete() {
if (pageNumber > pdf.numPages) {
return;
}
// Continue rendering of the next page
renderPage(canvas, pdf, pageNumber++, pageRenderingComplete);
});
}
});
function renderPage(canvas, pdf, pageNumber, callback) {
pdf.getPage(pageNumber).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport({scale: scale});
var pageDisplayWidth = viewport.width;
var pageDisplayHeight = viewport.height;
//var pageDivHolder = document.createElement();
// Prepare canvas using PDF page dimensions
//var canvas = document.createElement(id);
var context = canvas.getContext('2d');
canvas.width = pageDisplayWidth;
canvas.height = pageDisplayHeight;
// pageDivHolder.appendChild(canvas);
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).promise.then(callback);
});
}
</script>
<html>
The accepted answer works perfectly for a single PDF. In my case there were multiple PDFs that I wanted to render all pages for in the same sequence of the array.
I adjusted the code so that the global variables are encapsulated in an object array as follows:
var docs = []; // Add this object array
var urls = []; // You would need an array of the URLs to start.
// Loop through each url. You will also need the index for later.
urls.forEach((url, ix) => {
//Get the document from the url.
PDFJS.getDocument(url).then(function(pdf) {
// Make new doc object and set the properties of the new document
var doc = {};
//Set PDFJS global object (so we can easily access in our page functions
doc.thePDF = pdf;
//How many pages it has
doc.numPages = pdf.numPages;
//Push the new document to the global object array
docs.push(doc);
//Start with first page -- pass through the index for the handlePages method
pdf.getPage( 1 ).then(page => handlePages(page, ix) );
});
});
function handlePages(page, ix)
{
//This gives us the page's dimensions at full scale
var viewport = page.getViewport( {scale: 1} );
//We'll create a canvas for each page to draw it on
var canvas = document.createElement( "canvas" );
canvas.style.display = "block";
var context = canvas.getContext('2d');
canvas.height = viewport.viewBox[3];
canvas.width = viewport.viewBox[2];
//Draw it on the canvas
page.render({canvasContext: context, viewport: viewport});
//Add it to an element based on the index so each document is added to its own element
document.getElementById('doc-' + ix).appendChild( canvas );
//Move to next page using the correct doc object from the docs object array
docs[ix].currPage++;
if ( docs[ix].thePDF !== null && docs[ix].currPage <= docs[ix].numPages )
{
console.log("Rendering page " + docs[ix].currPage + " of document #" + ix);
docs[ix].thePDF.getPage( docs[ix].currPage ).then(newPage => handlePages(newPage, ix) );
}
}
Because the entire operation is asynchronous, without a unique object for each document, global variables of thePDF, currPage and numPages will be overwritten when subsequent PDFs are rendered, resulting in random pages being skipped, documents entirely skipped or pages from one document being appended to the wrong document.
One last point is that if this is being done offline or without using ES6 modules, the PDFJS.getDocument(url).then() method should change to pdfjsLib.getDocument(url).promise.then().
Make it to be iterate every page how much you want.
const url = '/storage/documents/reports/AR-2020-CCBI IND.pdf';
pdfjsLib.GlobalWorkerOptions.workerSrc = '/vendor/pdfjs-dist-2.12.313/package/build/pdf.worker.js';
const loadingTask = pdfjsLib.getDocument({
url: url,
verbosity: 0
});
(async () => {
const pdf = await loadingTask.promise;
let numPages = await pdf.numPages;
if (numPages > 10) {
numPages = 10;
}
for (let i = 1; i <= numPages; i++) {
let page = await pdf.getPage(i);
let scale = 1.5;
let viewport = page.getViewport({ scale });
let outputScale = window.devicePixelRatio || 1;
let canvas = document.createElement('canvas');
let context = canvas.getContext("2d");
canvas.width = Math.floor(viewport.width * outputScale);
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
document.getElementById('canvas-column').appendChild(canvas);
let transform = outputScale !== 1
? [outputScale, 0, 0, outputScale, 0, 0]
: null;
let renderContext = {
canvasContext: context,
transform,
viewport
};
page.render(renderContext);
}
})();

Javascript load images in canvas with JCanvaScript

I am using JcanvaScript library to work with Html5 canvas and now I want to load some images in my Canvas, but only last image loading is successful, I can't see any other images but the last one and I don't know what is wrong with my code.
here is the code
<!DOCTYPE HTML>
<html>
<head>
<style>
canvas {
border: 1px solid #9C9898;
}
</style>
<script src="jcanvas/jCanvaScript.1.5.15.js"></script>
<script>
var imagesUrl = [];
var imagesObj = [];
var canvasWidth = 800;
var canvasHeight = 600;
var imagesIdPrefix = 'images_';
var canvas = "canvas";
var fps = 60;
imagesUrl.push('images/image1.jpg');
imagesUrl.push('images/image2.jpg');
imagesUrl.push('images/image3.jpg');
imagesUrl.push('images/image4.jpg');
function init(){
for (i = 0; i < imagesUrl.length; i++){
var xImage = new Image();
xImage.src = imagesUrl[i];
xImage.onload = function(){
jc.start(canvas, fps);
jc.image(xImage, i*10, 0, 200, 200)
.id(imagesIdPrefix.toString() + i.toString());
jc.start(canvas, fps);
}
imagesObj.push(xImage);
}
}
</script>
</head>
<body onload="init()">
<canvas id="canvas" width="800px" height="600px"></canvas>
</body>
</html>
The bug has been identified in comment by MrOBrian : when the onload callbacks are called, i has the value it has at the end of the loop. That's the reason why you think that only last image loading is successful.
A standard solution is to embbed the content of the loop in a closure keeping the value of i :
for (i = 0; i < imagesUrl.length; i++){
(function(i){
var xImage = new Image();
xImage.src = imagesUrl[i];
xImage.onload = function(){
jc.start(canvas, fps);
jc.image(xImage, i*10, 0, 200, 200)
.id(imagesIdPrefix.toString() + i.toString());
jc.start(canvas, fps);
}
imagesObj.push(xImage);
})(i);
}
EDIT :
when you want to ensure all the needed images are loaded before running some code, you may use this function :
function onLoadAll(images, callback) {
var n=0;
for (var i=images.length; i-->0;) {
if (images[i].width==0) {
n++;
images[i].onload=function(){
if (--n==0) callback();
};
}
}
if (n==0) callback();
}
The images must have been provided their src first. You call the function like this :
onLoadAll(imagesObj, function(){
// do something with imagesObj
});
You need to make sure the images are loaded before you go and loop through them.
By defining your onload function inside of the for loop, the image may not have loaded by that point, and so the script will skip over it. And when it's done looping, the last image may be the only one that's loaded in time.
I would recommend adding a loader for each of the images outside the for loop, and when all the images are loaded go ahead and loop through the array.
A loader and checker looks something like this:
var loadedImages = [];
var loadedNumber = 3 //the number of images you need loaded
var imageToBeLoaded = new Image();
imageToBeLoaded.onload = function() {
loadedImages.push(true);
checkImages();
}
function checkImages() {
if (loadedImages.length != loadedNumber) {
setTimeout(checkImages(),1000);
} else {
init(); //your draw function
}
}

Categories