How to get my function to increase variable "_time" - javascript

// videogame.js
// don't forget to validate at jslint.com
/*jslint devel: true, browser: true */
/*global $*/
$(function () {
"use strict";
// global functions
function boundaryCheck(element_selector) {
var element = $(element_selector);
var universe = $("#universe");
var p = element.position();
if (p.left < 0) {
element.css("left", "0px");
}
if (p.top < 0) {
element.css("top", "0px");
}
if (p.left + element.width() > universe.width()) {
element.css("left", (universe.width() - element.width()) + "px");
}
if (p.top + element.height() > universe.height()) {
element.css("top", (universe.height() - element.height()) + "px");
}
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
// Constructor for Player Ship object
function PlayerShip() {
var my = {};
$("#universe").append($("<div>").attr("id", "player"));
my.navigate = function (keys) {
var RIGHTARROW_KEYCODE = 39;
var LEFTARROW_KEYCODE = 37;
var UPARROW_KEYCODE = 38;
var DOWNARROW_KEYCODE = 40;
if (keys === RIGHTARROW_KEYCODE) {
$("#player").css("left", "+=10px");
}
if (keys === LEFTARROW_KEYCODE) {
$("#player").css("left", "-=10px");
}
if (keys === UPARROW_KEYCODE) {
$("#player").css("top", "-=10px");
}
if (keys === DOWNARROW_KEYCODE) {
$("#player").css("top", "+=10px");
}
boundaryCheck("#player");
};
return my;
}
// Constructor for Enemy Ship object
function EnemyShip() {
var my = {};
$("#universe").append($("<div>").attr("id", "enemy"));
my.move = function (paused) {
if (!paused) {
var left = Boolean(getRandomInt(0, 2));
var top = Boolean(getRandomInt(0, 2));
if (left) {
$("#enemy").css("left", "-=" + getRandomInt(1, 10) + "px");
} else {
$("#enemy").css("left", "+=" + getRandomInt(1, 10) + "px");
}
if (top) {
$("#enemy").css("top", "-=" + getRandomInt(1, 10) + "px");
} else {
$("#enemy").css("top", "+=" + getRandomInt(1, 10) + "px");
}
boundaryCheck("#enemy");
}
};
return my;
}
// this might make an asteroid happen, maybe. I don't know if it will work.
function Asteroid() {
var my = {};
$("#universe").append($("<div>").attr("id", "asteroid"));
my.move = function (paused) {
if (!paused) {
var left = Boolean(getRandomInt(0, 2));
var top = Boolean(getRandomInt(0, 2));
if (left) {
$("#asteroid").css("left", "-=" + getRandomInt(1, 10) + "px");
} else {
$("#asteroid").css("left", "+=" + getRandomInt(1, 10) + "px");
}
if (top) {
$("#asteroid").css("top", "-=" + getRandomInt(1, 10) + "px");
} else {
$("#asteroid").css("top", "+=" + getRandomInt(1, 10) + "px");
}
boundaryCheck("#asteroid");
}
};
return my;
}
// Constructor for Game object
function Game() {
// total points
var _health = 1000;
var _time = 0;
// is the game paused?
var _game_paused = false;
// speed of background animation in ms (larger = slower)
var _background_speed = 100;
// player ship
var _player_ship = new PlayerShip();
// enemy ship
var _enemy_ship = new EnemyShip();
var _asteroid = new Asteroid(); //make this an actual thing
var my = {
health: _health,
time: _time,
game_paused: _game_paused,
background_speed: _background_speed,
player_ship: _player_ship,
enemy_ship: _enemy_ship,
asteroid: _asteroid
};
$("#universe").append($("<div>").attr("id", "results"));
$("#results").append($("<h1>"));
$("#universe").append($("<div>").attr("id", "results2"));
$("#results2").append($("<h1>"));
my.health = function (value) {
if (value === undefined) {
return _health;
}
_health = value;
return my;
};
my.time = function (value) {
if (value === undefined) {
return _time;
}
_time = value;
return my;
};
my.game_paused = function (value) {
if (value === undefined) {
return _game_paused;
}
_game_paused = value;
return my;
};
my.background_speed = function (value) {
if (value === undefined) {
return _background_speed;
}
_background_speed = value;
return my;
};
my.player_ship = function (value) {
if (value === undefined) {
return _player_ship;
}
_player_ship = value;
return my;
};
function runtimer() {
_time++;
};
my.enemy_ship = function (value) {
if (value === undefined) {
return _enemy_ship;
}
_enemy_ship = value;
return my;
};
my.asteroid = function (value) {
if (value === undefined) {
return _asteroid;
}
_asteroid = value;
return my;
};
// METHODS
// display total points
my.displayHealth = function () {
$("#results h1").html("Health: " + _health);
};
my.increaseTime = function () {
setInterval(function(){ runTimer() }, 1000)
}
my.displayTimer = function () {
$("#results2 h1").html("Time: "+ _time);
};
my.moveBackground = function () {
if (!_game_paused) {
var background_position = $("#universe")
.css("backgroundPosition")
.split(" ");
var current_x = parseInt(background_position[0], 10);
var current_y = parseInt(background_position[1], 10);
var new_x = current_x - 1;
var new_y = current_y;
$("#universe").css({
"background-position": new_x + "px " + new_y + "px"
});
}
};
my.checkKeys = function () {
var ESCAPE_KEYCODE = 27;
$(document).keydown(function (key_event) {
if (key_event.which === ESCAPE_KEYCODE) {
if (_game_paused) {
_game_paused = false;
$("#pause").remove();
} else {
_game_paused = true;
var pause = $("<div>", {id: "pause"});
$("body").prepend(pause);
}
} else {
_player_ship.navigate(key_event.which);
}
});
};
my.checkCollisions = function (paused) {
var p = $("#player");
var e = $("#enemy");
var ppos = p.position();
var epos = e.position();
if (!paused) {
if (
(
(ppos.left + p.width() < epos.left) ||
(ppos.left > epos.left + e.width())
) ||
(
(ppos.top + p.height() < epos.top) ||
(ppos.top > epos.top + e.height())
)
) {
return false;
} else {
return true;
}
}
};
my.checkAsteroid = function (paused) {
var p = $("#player");
var a = $("#asteroid");
var ppos = p.position();
var apos = a.position();
if (!paused) {
if (
(
(ppos.left + p.width() < apos.left) ||
(ppos.left > apos.left + a.width())
) ||
(
(ppos.top + p.height() < apos.top) ||
(ppos.top > apos.top + a.height())
)
) {
return false;
} else {
return true;
}
}
};
my.play = function () {
_enemy_ship.move(_game_paused);
_asteroid.move(_game_paused);
if (my.checkCollisions(_game_paused)) {
_health --;
my.displayHealth();
} else if (
my.checkAsteroid(_game_paused)) {
_health --;
my.displayHealth();
}
};
return my;
}
var game = new Game();
game.checkKeys();
game.displayHealth();
game.displayTimer();
game.increaseTime();
setInterval(game.moveBackground, game.background_speed);
setInterval(game.play, game.background_speed);
});
I'm relatively new to programming. I took a class in high school, which was very mediocre. I'm now taking some starter courses in college, and my assignment is to improve a generic space game (which I have already started doing). I have a div for the timer, but for some reason, I can't get any functions to increase the _time variable. It's almost as though they're not allowed to access it. I have a function called "runTimer", which is supposed to increase "_time" by one every time it is run. I have another function called "increaseTime", which is supposed to run "runTimer" every 1000 milliseconds. The variable never seems to increase though. This hasn't been my first spaghetti code implementation of a timer, since I've tried various things over the past few hours. I just can't understand why the variable won't increase.

This is a big hunk of code. As RobG pointed out, try to work on paring back your question to the minimal, complete, and verifiable example you can.
That said, at a glance, it would appear that your timer probably is updating. At least _time is.
The problem is likely you are never re-drawing your div, so it isn't showing the updated value. You need to call game.displayTimer() every time _time updates.
Probably the easiest place to add it would be in your setInterval() in increaseTime():
my.increaseTime = function () {
setInterval(function(){
runTimer();
my.displayTime();
}, 1000)
}

Related

Javascript not able to make common functions for a prototype

I am trying to make timer in javascript using a prototype. Each time a new timer is created, a object of prototype is created. There are methods to increase time and print each second. The whole code snippet is as follows:
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
Timer.prototype.start = function() {
var self = this;
if (!self.interval) {
self.interval = setInterval(update, 1000);
}
function update() {
incrementTime();
render();
}
function render() {
self.elem.innerText = getPrintableTime();
}
function incrementTime() {
self.currentTime["min"] += Math.floor((++self.currentTime["sec"]) / 60);
self.currentTime["hr"] += Math.floor(self.currentTime["min"] / 60);
self.currentTime["sec"] = self.currentTime["sec"] % 60;
self.currentTime["min"] = self.currentTime["min"] % 60;
}
function getPrintableTime() {
var text = getTwoDigitNumber(self.currentTime["hr"]) + ":" + getTwoDigitNumber(self.currentTime["min"]) + ":" + getTwoDigitNumber(self.currentTime["sec"]);
return text;
}
function getTwoDigitNumber(number) {
if (number > 9) {
return "" + number;
} else {
return "0" + number;
}
}
};
module.exports = Timer;
I have all methods in start function. The problem is that for each new object of Timer, new space for each method will be used which is very inefficient. But when I try to put methods outside of start function, they lose access to self variable. You can see that there is setInterval function used which will be calling these methods per second. I cannot use this also as this will be instance of Window in subsequent calls.
How can I solve this situation by only keeping one instance of all the interior methods?
You don't need to have all methods in the start function. Yes, for each new Timer instance, new space for each function will be used, but that is necessary when you want to work with setInterval as you need a function which closes over the instance. However, you need only one such closure, the other methods can be standard prototype methods.
function getTwoDigitNumber(number) {
return (number > 9 ? "" : "0") + number;
}
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
Timer.prototype.start = function() {
var self = this;
if (!this.interval) {
this.interval = setInterval(function update() {
self.incrementTime();
self.render();
}, 1000);
}
};
Timer.prototype.render() {
this.elem.innerText = this.getPrintableTime();
};
Timer.prototype.incrementTime = function() {
this.currentTime.sec += 1;
this.currentTime.min += Math.floor(this.currentTime.sec / 60);
this.currentTime.hr += Math.floor(this.currentTime.min / 60);
this.currentTime.sec = this.currentTime.sec % 60;
this.currentTime.min = this.currentTime.min % 60;
};
Timer.prototype.getPrintableTime = function() {
var text = getTwoDigitNumber(this.currentTime.hr) + ":"
+ getTwoDigitNumber(this.currentTime.min) + ":"
+ getTwoDigitNumber(self.currentTime.sec);
return text;
};
module.exports = Timer;
Btw, regarding your incrementTime pattern, you should have a look at How to create an accurate timer in javascript?.
You can use apply to use functions defined outside of prototype with correct this context.
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
function update() {
incrementTime.apply(this);
render.apply(this);
}
function render() {
this.elem.innerText = getPrintableTime.apply(this);
}
function incrementTime() {
this.currentTime["min"] += Math.floor((++this.currentTime["sec"]) / 60);
this.currentTime["hr"] += Math.floor(this.currentTime["min"] / 60);
this.currentTime["sec"] = this.currentTime["sec"] % 60;
this.currentTime["min"] = this.currentTime["min"] % 60;
}
function getPrintableTime() {
var text = getTwoDigitNumber(this.currentTime["hr"]) + ":" + getTwoDigitNumber(this.currentTime["min"]) + ":" + getTwoDigitNumber(this.currentTime["sec"]);
return text;
}
function getTwoDigitNumber(number) {
if (number > 9) {
return "" + number;
} else {
return "0" + number;
}
}
Timer.prototype.start = function() {
var self = this;
if (!self.interval) {
self.interval = setInterval(function() {
update.apply(self);
}, 1000);
}
};
document.addEventListener('DOMContentLoaded', function() {
var timer = new Timer(document.getElementById('timer'));
timer.start();
}, false);
<div id="timer"></div>
If I understand correctly, you're wanting to only create one interval.
One possible solution would be to create a static method and variable to manage the setInterval. I would note that while this may be more performance friendly, the timers will always start and run on the same count...not from the moment each timer is created. (See example)
Of course, you could capture the current timestamp and calculate the elapsed time from there. But, that's another thread ;)
function Timer(elem) {
this.interval = null;
this.currentTime = {
sec: 0,
min: 0,
hr: 0
};
this.elem = elem;
};
Timer.subscribe = function(timer) {
Timer.subscribers = Timer.subscribers || [];
if (Timer.subscribers.indexOf(timer) === -1) {
Timer.subscribers.push(timer);
timer.update.call(timer);
}
Timer.checkInterval();
};
Timer.unsubscribe = function(timer) {
Timer.subscribers = Timer.subscribers || [];
if (Timer.subscribers.indexOf(timer) !== -1) {
Timer.subscribers.splice(Timer.subscribers.indexOf(timer), 1);
}
Timer.checkInterval();
};
Timer.checkInterval = function() {
if (!Timer.interval && Timer.subscribers.length > 0) {
Timer.interval = setInterval(function() {
Timer.subscribers.forEach(function(item) {
item.update.call(item);
});
}, 1000);
} else if (Timer.interval && Timer.subscribers.length === 0) {
clearInterval(Timer.interval);
Timer.interval = null;
}
};
Timer.prototype = {
start: function() {
Timer.subscribe(this);
},
stop: function() {
Timer.unsubscribe(this);
},
update: function() {
this.incrementTime();
this.render();
},
incrementTime: function() {
this.currentTime["min"] += Math.floor((++this.currentTime["sec"]) / 60);
this.currentTime["hr"] += Math.floor(this.currentTime["min"] / 60);
this.currentTime["sec"] = this.currentTime["sec"] % 60;
this.currentTime["min"] = this.currentTime["min"] % 60;
},
render: function() {
var self = this;
function getPrintableTime() {
var text = getTwoDigitNumber(self.currentTime["hr"]) + ":" + getTwoDigitNumber(self.currentTime["min"]) + ":" + getTwoDigitNumber(self.currentTime["sec"]);
return text;
}
function getTwoDigitNumber(number) {
if (number > 9) {
return "" + number;
} else {
return "0" + number;
}
}
this.elem.innerText = getPrintableTime();
}
};
/**
*
*/
var timers = document.getElementById('timers');
function addTimer() {
var el = document.createElement('div');
var tmr = document.createElement('span');
var btn = document.createElement('button');
var t = new Timer(tmr);
btn.innerText = 'Stop';
btn.onclick = function() {
t.stop();
};
el.appendChild(tmr);
el.appendChild(btn);
timers.appendChild(el);
t.start();
};
<div id="timers"></div>
<button onclick="addTimer()">Add Timer</button>

Combining two Javascript functions to one window.onload not working

I have two functions that I want to run on window.onload event but only the last function seems to work so far. One function is for an image slider and the other one retrieves data from a google spreadsheet cell.
function fun1() { //image slider
var ul;
var li_items;
var imageNumber;
var imageWidth;
var prev, next;
var currentPostion = 0;
var currentImage = 0;
function init() {
ul = document.getElementById('image_slider');
li_items = ul.children;
imageNumber = li_items.length;
imageWidth = li_items[0].children[0].clientWidth;
ul.style.width = parseInt(imageWidth * imageNumber) + 'px';
prev = document.getElementById("prev");
next = document.getElementById("next");
prev.onclick = function() {
onClickPrev();
};
next.onclick = function() {
onClickNext();
};
}
function animate(opts) {
var start = new Date;
var id = setInterval(function() {
var timePassed = new Date - start;
var progress = timePassed / opts.duration;
if (progress > 1) {
progress = 1;
}
var delta = opts.delta(progress);
opts.step(delta);
if (progress == 1) {
clearInterval(id);
opts.callback();
}
}, opts.delay || 17);
}
function slideTo(imageToGo) {
var direction;
var numOfImageToGo = Math.abs(imageToGo - currentImage);
direction = currentImage > imageToGo ? 1 : -1;
currentPostion = -1 * currentImage * imageWidth;
var opts = {
duration: 1000,
delta: function(p) {
return p;
},
step: function(delta) {
ul.style.left = parseInt(currentPostion + direction * delta * imageWidth * numOfImageToGo) + 'px';
},
callback: function() {
currentImage = imageToGo;
}
};
animate(opts);
}
function onClickPrev() {
if (currentImage == 0) {
slideTo(imageNumber - 1);
} else {
slideTo(currentImage - 1);
}
}
function onClickNext() {
if (currentImage == imageNumber - 1) {
slideTo(0);
} else {
slideTo(currentImage + 1);
}
}
}
function fun2() {
// Google spreadsheet js
google.load('visualization', '1', {
callback: function() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1sA7M5kG6Xo8YScD1Df38PIA_G0bvhGRdqoExXg0KJTs/gviz/tq?tqx=out:html&tq?gid=0&headers=0&range=A1:C');
query.send(displayData);
}
});
function displayData(response) {
numRows = response.getDataTable().getValue(0, 0);
document.getElementById('data').innerHTML = numRows;
}
}
var addFunctionOnWindowLoad = function(callback) {
if (window.addEventListener) {
window.addEventListener('load', callback, false);
} else {
window.attachEvent('onload', callback);
}
}
addFunctionOnWindowLoad(fun1);
addFunctionOnWindowLoad(fun2);
This is the answer I've tried link but I can't seem to figure out where I'm going wrong.
This is what I ended up doing, and now all the functions work.
var ul;
var li_items;
var imageNumber;
var imageWidth;
var prev, next;
var currentPostion = 0;
var currentImage = 0;
function init() {
ul = document.getElementById('image_slider');
li_items = ul.children;
imageNumber = li_items.length;
imageWidth = li_items[0].children[0].clientWidth;
ul.style.width = parseInt(imageWidth * imageNumber) + 'px';
prev = document.getElementById("prev");
next = document.getElementById("next");
prev.onclick = function() {
onClickPrev();
};
next.onclick = function() {
onClickNext();
};
}
function animate(opts) {
var start = (new Date());
var id = setInterval(function() {
var timePassed = (new Date()) - start;
var progress = timePassed / opts.duration;
if (progress > 1) {
progress = 1;
}
var delta = opts.delta(progress);
opts.step(delta);
if (progress == 1) {
clearInterval(id);
opts.callback();
}
}, opts.delay || 17);
//return id;
}
function slideTo(imageToGo) {
var direction;
var numOfImageToGo = Math.abs(imageToGo - currentImage);
// slide toward left
direction = currentImage > imageToGo ? 1 : -1;
currentPostion = -1 * currentImage * imageWidth;
var opts = {
duration: 1000,
delta: function(p) {
return p;
},
step: function(delta) {
ul.style.left = parseInt(currentPostion + direction * delta * imageWidth * numOfImageToGo) + 'px';
},
callback: function() {
currentImage = imageToGo;
}
};
animate(opts);
}
function onClickPrev() {
if (currentImage === 0) {
slideTo(imageNumber - 1);
} else {
slideTo(currentImage - 1);
}
}
function onClickNext() {
if (currentImage == imageNumber - 1) {
slideTo(0);
} else {
slideTo(currentImage + 1);
}
}
window.onload = init;
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function fun2() {
// Google spreadsheet js
google.load('visualization', '1', {
callback: function() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1sA7M5kG6Xo8YScD1Df38PIA_G0bvhGRdqoExXg0KJTs/gviz/tq?tqx=out:html&tq?gid=0&headers=0&range=A1:C');
query.send(displayData);
}
});
function displayData(response) {
numRows = response.getDataTable().getValue(0, 0);
document.getElementById('data').innerHTML = numRows;
}
}
addLoadEvent(fun2);
addLoadEvent(function() {
});
I found this function a while ago and believe it or not, I still need to use it every so often. addEventLoad() Just call addEventLoad while passing the function to load.
"The way this works is relatively simple: if window.onload has not already been assigned a function, the function passed to addLoadEvent is simply assigned to window.onload. If window.onload has already been set, a brand new function is created which first calls the original onload handler, then calls the new handler afterwards."
This snippet will load 3 functions on window.onload
Snippet
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
function alert1() {
alert("First Function Loaded");
}
function alert2() {
alert("Second Function Loaded");
}
function alert3(str) {
alert("Third Function Loaded; Msg: " + str);
}
addLoadEvent(alert1);
addLoadEvent(alert2);
addLoadEvent(function() {
alert3("This works");
});
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Toggle class on HTML element without jQuery

I have a section on my website which holds all the content, but I want a "sidebar" with hidden content to smoothly appear from the left at the push of an external button.
CSS transitions can handle the smoothness no problem, and jQuery toggle() can switch between classes to move the hidden div in and out of the screen.
How can I get the same effect without using jQuery?
You can toggle classes using the classList.toggle() function:
var element = document.getElementById('sidebar');
var trigger = document.getElementById('js-toggle-sidebar'); // or whatever triggers the toggle
trigger.addEventListener('click', function(e) {
e.preventDefault();
element.classList.toggle('sidebar-active'); // or whatever your active class is
});
That should do everything you need - if you have more than one trigger I'd recommend using document.querySelectorAll(selector) instead.
You can implement it only by CSS3:
<label for="showblock">Show Block</label>
<input type="checkbox" id="showblock" />
<div id="block">
Hello World
</div>
And the CSS part:
#block {
background: yellow;
height: 0;
overflow: hidden;
transition: height 300ms linear;
}
label {
cursor: pointer;
}
#showblock {
display: none;
}
#showblock:checked + #block {
height: 40px;
}
The magic is the hidden checkbox and the :checked selector in CSS.
Working jsFiddle Demo.
HTML ONLY
You can use <summary>. The following code doesn't have any dependency.
No JavaScript, CSS at all, HTML only.
<div class="bd-example">
<details open="">
<summary>Some details</summary>
<p>More info about the details.</p>
</details>
<details>
<summary>Even more details</summary>
<p>Here are even more details about the details.</p>
</details>
</div>
For more detail, go to MDN official docs.
you can get any element by id with javascript (no jquery) and the class is an attribute :
element.className
so have this as a function:
UPDATE:
since this is becoming a somewhat popular I updated the function to make it better.
function toggleClass(element, toggleClass){
var currentClass = element.className || '';
var newClass;
if(currentClass.split(' ').indexOf(toggleClass) > -1){ //has class
newClass = currentClass.replace(new RegExp('\\b'+toggleClass+'\\b','g'), '')
}else{
newClass = currentClass + ' ' + toggleClass;
}
element.className = newClass.trim();
}
function init() {
animateCSS(document.getElementById("slide"), 250, {
left: function (timePercent, frame) {
var endPoint = 128,
startPoint = 0,
pathLength = endPoint - startPoint,
base = 64, //slope of the curve
currentPos = Math.floor(startPoint + (Math.pow(base, timePercent) - 1) / (base - 1) * pathLength);
return currentPos + "px";
}
}, function (element) {
element.style.left = "128px";
});
};
var JobType = function () {
if (!(this instanceof JobType)) {
return new JobType(arguments[0]);
};
var arg = arguments[0];
this.fn = arg["fn"];
this.delay = arg["delay"];
this.startTime = arg["startTime"];
this.comment = arg["comment"];
this.elapsed = 0;
};
function JobManager() {
if (!(this instanceof JobManager)) {
return new JobManager();
};
var instance;
JobManager = function () {
return instance;
};
JobManager.prototype = this;
instance = new JobManager();
instance.constructor = JobManager;
var jobQueue = [];
var startedFlag = false;
var inProcess = false;
var currentJob = null;
var timerID = -1;
var start = function () {
if (jobQueue.length) {
startedFlag = true;
currentJob = jobQueue.shift();
var startOver = currentJob.delay - ((new Date()).getTime() - currentJob.startTime);
timerID = setTimeout(function () {
inProcess = true;
currentJob.fn();
if (jobQueue.length) {
try {
while ((jobQueue[0].delay - ((new Date()).getTime() - currentJob.startTime)) <= 0) {
currentJob = jobQueue.shift();
currentJob.fn();
};
}
catch (e) { };
}
inProcess = false;
start();
}, (startOver > 0 ? startOver : 0));
}
else {
startedFlag = false;
timerID = -1;
};
};
instance.add = function (newJob) {
if (newJob instanceof JobType) {
stopCurrent();
var jobQueueLength = jobQueue.length;
if (!jobQueueLength) {
jobQueue.push(newJob);
}
else {
var currentTime = (new Date()).getTime(),
insertedFlag = false;
for (var i = 0; i < jobQueueLength; i++) {
var tempJob = jobQueue[i],
tempJobElapsed = currentTime - tempJob["startTime"],
tempJobDelay = tempJob["delay"] - tempJobElapsed;
tempJob["elapsed"] = tempJobElapsed;
if (newJob["delay"] <= tempJobDelay) {
if (!insertedFlag) {
jobQueue.splice(i, 0, newJob);
insertedFlag = true;
}
};
if (i === (jobQueueLength - 1)) {
if (!insertedFlag) {
jobQueue.push(newJob);
insertedFlag = true;
}
}
};
};
if ((!startedFlag) && (!inProcess)) {
start();
};
return true;
}
else {
return false;
};
};
var stopCurrent = function () {
if (timerID >= 0) {
if (!inProcess) {
clearTimeout(timerID);
timerID = -1;
if (currentJob) {
jobQueue.unshift(currentJob);
};
};
startedFlag = false;
};
};
return instance;
};
function animateCSS(element, duration, animation, whendone) {
var frame = 0,
elapsedTime = 0,
timePercent = 0,
startTime = new Date().getTime(),
endTime = startTime + duration,
fps = 0,
averageRenderTime = 1000,
normalRenderTime = 1000 / 25,
myJobManager = JobManager();
var inQueue = myJobManager.add(JobType({
"fn": displayNextFrame,
"delay": 0,
"startTime": (new Date).getTime(),
"comment": "start new animation"
}));
function playFrame() {
for (var cssprop in animation) {
try {
element.style[cssprop] = animation[cssprop].call(element, timePercent, frame);
} catch (e) { }
};
};
function displayNextFrame() {
elapsedTime = (new Date().getTime()) - startTime;
timePercent = elapsedTime / duration;
if (elapsedTime >= duration) {
playFrame();
if (whendone) {
whendone(element);
};
return;
};
playFrame();
frame++;
averageRenderTime = elapsedTime / frame;
fps = 1000 / averageRenderTime;
inQueue = myJobManager.add(JobType({
"fn": displayNextFrame,
"delay": (fps < 15 ? 0 : normalRenderTime - averageRenderTime),
"startTime": (new Date).getTime(),
"comment": frame
}));
}
};
(function () {
if (this.addEventListener) {
this.addEventListener("load", init, false)
}
else {
window.onload = init;
}
}());
// By Plain Javascript
// this code will work on most of browsers.
function hasClass(ele, clsName) {
var el = ele.className;
el = el.split(' ');
if(el.indexOf(clsName) > -1){
var cIndex = el.indexOf(clsName);
el.splice(cIndex, 1);
ele.className = " ";
el.forEach(function(item, index){
ele.className += " " + item;
})
}
else {
el.push(clsName);
ele.className = " ";
el.forEach(function(item, index){
ele.className += " " + item;
})
}
}
var btn = document.getElementById('btn');
var ele = document.getElementById('temp');
btn.addEventListener('click', function(){
hasClass(ele, 'active')
})
I did not test but the code below should work.
<script>
function toggleClass(){
var element = document.getElementById("a");
element.classList.toggle("b");
}
document.getElementById("c").addEventListener('click', toggleClass )
</script>

D3JS Treemap renders but the colors don't show

So the colors are not showing up on the individual nodes in the treemap until I move the slider. I was hoping maybe someone else has ran into this problem before.
Here is the JS behind it. The css file is pretty slim if you want me to post that too.
$(function () {
// Load templates
$('.template').each(function () {
var me = $(this);
var src = me.attr('src');
var data = $.get(src, function (template) {
me.html(template);
});
});
var slider = $('#sliderControl').slider({
formatter: function (value) {
return "Show errors over " + value.toFixed(0) + "% in red";
}
});
var width = 0,
height = 0;
function calcDim() {
var container = $('#graph');
width = container.width();
height = width * 0.5;
container.height(height);
};
calcDim();
var canvas = d3.select('#graph');
var scaleArr = buildColorScaleDomain();
var color = d3.scale.linear().domain(scaleArr).range(['#62A35D', '#D4FFD5', '#FEC5C7', '#D36461']).clamp(true);
var sizes = d3.scale.linear().domain([0, 10000]).range([1, 1000]).clamp(true);
// Use sig to scale from 0+ to decrease/increase the fidelity (higher) or speed (lower) of the graph
var sig = 5;
var resolution = Math.pow(10, sig);
var params = 'map?';
//if (provider.length > 0)
// params += 'provider=' + provider + '&';
//if (version.length > 0)
// params += 'version=' + version + '&';
//if (type.length > 0)
// params += 'type=' + type + '&';
//if (dateBeg.length > 0)
// params += 'dateBeg=' + dateBeg + '&';
//if (dateEnd.length > 0)
// params += 'dateEnd=' + dateEnd + '&';
//Envision.Init();
var _url = '/api/report/' + params;
var urlParts = document.location.href.split("/");
_url = "/" + urlParts[3] + _url;
d3.json(_url, function (data) {
var treemap = d3.layout.treemap().size([100 * resolution, 100 * resolution]).value(getSelectedPerformanceValue()).sort(function (a, b) {
return a.total - b.total;
}).sticky(true);
var node = canvas.data([{
children: data
}]).selectAll('.node').data(treemap).enter().append('div').attr('class', 'node').style('background', function (d) {
return color(1 - d.quality_of_messages_received);
}).call(position).attr('title', function (d) {
return d.provider_desc;
}).attr('data-content', function (d) {
return "" + d.sending_facility + "<br>AA: " + d.AA_count + "<br>AE: " + d.AE_count + "<br>AR: " + d.AR_count + "<br>Total: " + d.total + "<br>Quality: " + ((d.quality_of_messages_received) * 100).toFixed(2) + "%<br>Errors: " + ((1 - d.quality_of_messages_received) * 100).toFixed(2) + "%<br>Grade: " + calcGrade(d);
}).html(function (d) {
return d.sending_facility;
});
slider.on('slide', function (ev) {
var me = $(this);
var scaleArr = buildColorScaleDomain();
color.domain(scaleArr);
canvas.selectAll('.node').style('background', function (d) {
return color(1 - d.quality_of_messages_received);
});
});
$(".node").popover({
html: true,
trigger: 'hover',
placement: 'auto right',
container: 'body'
});
$('#dataSelect').on('change', function (e) {
node.data(treemap.value(getSelectedPerformanceValue()).nodes).call(position);
});
$(window).on('resize', function (e) {
calcDim();
});
ko.applyBindings(new function () {
var self = this;
this.data = data;
this.getDataRows = function () {
return self.data;
};
this.getProviderName = function (data) {
return data.provider_desc;
};
this.getProviderVolume = function (data) {
return data.total;
};
this.getProviderErrors = function (data) {
return "" + ((1 - data.quality_of_messages_received) * 100).toFixed(0) + "%";
};
this.getProviderGrade = function (data) {
return calcGrade(data);
};
});
});
function position() {
this.style('left', function (d) {
if (d.children) return;
return (d.x / resolution) + '%';
}).style('top', function (d) {
if (d.children) return;
return (d.y / resolution) + '%';
}).style('width', function (d) {
if (d.children) return;
return (d.dx / resolution) + '%';
}).style('height', function (d) {
if (d.children) return;
return (d.dy / resolution) + '%';
}).style('font-size', function (d) {
if (d.children) return;
return (Math.min(d.dx, d.dy) / resolution) + "%";
});
}
function getSelectedPerformanceValue() {
var fn = function (value) {
return function (d) {
return d[value];
}
};
var me = $('#dataSelect :selected');
var val = me.val().toLowerCase().trim();
switch (val) {
case "total":
fn = fn('total');
break;
case "aa":
fn = fn('AA_count');
break;
case "ae":
fn = fn('AE_count');
break;
case "ar":
fn = fn('AR_count');
break;
case "quality":
fn = function (d) {
return d.quality_of_messages_received;
};
break;
case "errors":
fn = function (d) {
return 1 - d.quality_of_messages_received;
};
break;
default:
fn = fn('total');
break;
}
return fn;
}
function buildColorScaleDomain() {
var slideValue = slider.data('slider').getValue();
var outerLimits = 10;
var bottom = 0.001;
var a0 = Math.max(slideValue - (outerLimits * 2), 0); // greener
var a1 = Math.max(slideValue - outerLimits, bottom);
var a2 = Math.max(slideValue, bottom * 2); // redder
var arr = [a0 / 100, a1 / 100, a1 / 100, a2 / 100];
return arr;
}
function calcGrade(data) {
var quality = Math.floor(data.quality_of_messages_received * 10).toFixed(0);
switch (quality) {
case '10':
case '9':
return "A";
case '8':
return "B";
case '7':
return "C";
case '6':
return "D";
default:
return "F";
};
}
})
I believe I have a cleaner solution for you. Check out my video here. I run through a couple other neat features of D3Js as well. Here is a great tutorial I found as well when I first started with D3JS https://www.dashingd3js.com/table-of-contents
function buildColorScaleDomain() {
var slideValue = slider.data('slider').getValue();
//The value was NaN, had to initialize it
if (!slideValue)
slideValue = .05;
var outerLimits = 10;
var bottom = 0.001;
var a0 = Math.max(slideValue - (outerLimits * 2), 0); // greener
var a1 = Math.max(slideValue - outerLimits, bottom);
var a2 = Math.max(slideValue, bottom * 2); // redder
var arr = [a0 / 100, a1 / 100, a1 / 100, a2 / 100];
return arr;
}

; Missing Error after Packing Prototype

After using Packer (http://dean.edwards.name/packer/) I end up throwing a
missing ; after (the long packer string). I have no idea of the what and why.
possible fix and explanation please?
jQuery.fn.extend({
ImageRotate:function(parameters)
{
if (this.Wilq32&&this.Wilq32.PhotoEffect) return;
return (new Wilq32.PhotoEffect(this.get(0),parameters))._temp;
},
rotate:function(parameters)
{
if (this.length===0) return;
if (typeof parameters=="undefined") return;
if (typeof parameters=="number") parameters={angle:parameters};
var returned=[];
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (typeof element.Wilq32 == "undefined")
returned.push($($(element).ImageRotate(parameters)));
else
{
element.Wilq32.PhotoEffect._rotate(parameters.angle);
}
}
return returned;
},
rotateAnimation:function(parameters)
{
if (this.length===0) return;
if (typeof parameters=="undefined") return;
if (typeof parameters=="number") parameters={angle:parameters};
var returned=[];
for (var i=0,i0=this.length;i<i0;i++)
{
var element=this.get(i);
if (typeof element.Wilq32 == "undefined")
returned.push($($(element).ImageRotate(parameters)));
else
{
element.Wilq32.PhotoEffect._parameters.animateAngle = parameters.angle;
element.Wilq32.PhotoEffect._parameters.callback = parameters.callback ||
function()
{
};
element.Wilq32.PhotoEffect._animateStart();
}
}
return returned;
}
});
Wilq32={};
Wilq32.PhotoEffect=function(img,parameters)
{
this._IEfix=img;
this._parameters=parameters;
this._parameters.className=img.className;
this._parameters.id=img.getAttribute('id');
if (!parameters) this._parameters={};
this._angle=0;
if (!parameters.angle) this._parameters.angle=0;
this._temp=document.createElement('span');
this._temp.Wilq32 =
{
PhotoEffect: this
};
var image=img.src;
img.parentNode.insertBefore(this._temp,img);
this._img= new Image();
this._img.src=image;
this._img._ref=this;
jQuery(this._img).bind("load", function()
{
this._ref._Loader.call(this._ref);
});
if (jQuery.browser.msie) if (this._img.complete) this._Loader();
}
Wilq32.PhotoEffect.prototype._Loader=
(function()
{
if (jQuery.browser.msie)
return function()
{
var src=this._IEfix.src;
this._IEfix.parentNode.removeChild(this._IEfix);
this._temp.setAttribute('id',this._parameters.id);
this._temp.className=this._parameters.className;
var width=this._img.width;
var height=this._img.height;
this._img._widthMax=this._img._heightMax=Math.sqrt((height)*(height) + (width) * (width));
this._img._heightMax=Math.sqrt((height)*(height) + (width) * (width));
this._vimage = document.createElement('v:image');
this._vimage._ref=this;
this._vimage.style.height=height;
this._vimage.style.width=width;
this._vimage.style.position="relative";
this._temp.style.display="inline-block";
this._temp.style.width=this._temp.style.height=this._img._heightMax;
this._vimage.src=src;
this._vimage.rotate=0;
this._temp.appendChild(this._vimage);
var self = this;
this._parameters.animateAngle=0;
if (this._parameters.bind)
{
for (var a in this._parameters.bind) if (this._parameters.bind.hasOwnProperty(a))
for (var b in this._parameters.bind[a]) if (this._parameters.bind[a].hasOwnProperty(b))
jQuery(this._temp).bind(b,this._parameters.bind[a][b]);
}
this._rotate(this._parameters.angle);
}
else
return function ()
{
this._IEfix.parentNode.removeChild(this._IEfix);
this._temp.setAttribute('id',this._parameters.id);
this._temp.className=this._parameters.className;
var width=this._img.width;
var height=this._img.height;
this._img._widthMax=this._img._heightMax=Math.sqrt((height)*(height) + (width) * (width));
this._canvas=document.createElement('canvas');
this._canvas._ref=this;
this._canvas.height=height;
this._canvas.width=width;
this._canvas.setAttribute('width',width);
this._temp.appendChild(this._canvas);
var self = this;
this._parameters.animateAngle=0;
if (this._parameters.bind)
{
for (var a in this._parameters.bind) if (this._parameters.bind.hasOwnProperty(a))
for (var b in this._parameters.bind[a]) if (this._parameters.bind[a].hasOwnProperty(b))
jQuery(this._canvas).bind(b,this._parameters.bind[a][b]);
}
this._cnv=this._canvas.getContext('2d');
this._rotate(this._parameters.angle);
}
})();
Wilq32.PhotoEffect.prototype._animateStart=function()
{
if (this._timer) clearTimeout(this._timer);
this._animate();
}
Wilq32.PhotoEffect.prototype._animate=function()
{
var temp=this._angle;
if (typeof this._parameters.animateAngle!="undefined") this._angle-=(this._angle-this._parameters.animateAngle)*0.1;
if (typeof this._parameters.minAngle!="undefined") if (this._angle<this._parameters.minAngle) this._angle=this._parameters.minAngle;
if (typeof this._parameters.maxAngle!="undefined") if (this._angle>this._parameters.maxAngle) this._angle=this._parameters.maxAngle;
if (Math.round(this._angle * 100 - temp * 100) == 0 && this._timer)
{
clearTimeout(this._timer);
if (this._parameters.callback)
this._parameters.callback();
}
else
{
this._rotate(this._angle);
var self = this;
this._timer = setTimeout(function()
{
self._animate.call(self);
}, 10);
}
}
Wilq32.PhotoEffect.prototype._rotate = (function()
{
if (jQuery.browser.msie)
return function(angle)
{
this._vimage.style.rotation=angle;
var radians=angle*Math.PI/180;
this._vimage.style.top= (this._img._heightMax - this._img.height)/2- (this._vimage.offsetHeight-this._img.height)/2 +"px";
this._vimage.style.left= (this._img._widthMax - this._img.width)/2- (this._vimage.offsetWidth-this._img.width)/2 +"px";
}
else
return function(angle)
{
if (!this._img.width) return;
if (typeof angle!="number") return;
angle=(angle%360)* Math.PI / 180;
var width=this._img.width;
var height=this._img.height;
var widthAdd = this._img._widthMax - width;
var heightAdd = this._img._heightMax - height;
this._canvas.width = width+widthAdd;
this._canvas.height = height+heightAdd;
this._cnv.save();
this._cnv.translate(widthAdd/2,heightAdd/2);
this._cnv.translate(width/2,height/2);
this._cnv.rotate(angle);
this._cnv.translate(-width/2,-height/2);
this._cnv.drawImage(this._img, 0, 0);
this._cnv.restore();
}
})();
Packer jams everything onto one line if I'm not mistaken so that any missing semicolons that would have been originally parsed OK turn into hard errors.
There are a few missing semicolons in your js for example
return function(angle)
{
this._vimage.style.rotation=angle;
var radians=angle*Math.PI/180;
this._vimage.style.top= (this._img._heightMax - this._img.height)/2- (this._vimage.offsetHeight-this._img.height)/2 +"px";
this._vimage.style.left= (this._img._widthMax - this._img.width)/2- (this._vimage.offsetWidth-this._img.width)/2 +"px";
}
is missing a semicolon. there are more.
Here's a nice site which will tell you what is wrong with your javascript: http://jslint.com/
So paste your code there, click on the JSLint button and observe the errors and warnings you get. Once you fix them you may be confident that when packed your javascript will work.

Categories

Resources