I'm working on a script that recalculates the coordinates of the area attributes inside the imagemap. When loading the page for the first time, the function is initialised so that the area's coordinates adjust to the width of the users browser. The fist time everything goes well.
I've added a 'resize' event listener on the window element. The function fires (same as the init function), and the coordinates are adjusted as expected. So that works. But there is one problem; I keep getting the error you can see below every time I resize the window (The error doesn't occur while innit fires for the first time).
Error:
Uncaught TypeError: Cannot set property 'coords' of undefined
at http://localhost:3000/js/index.js:78697:33
at Array.forEach (native)
at Object.resize (http://localhost:3000/js/index.js:78696:23)
at Object.start (http://localhost:3000/js/index.js:78691:25)
at Object.init (http://localhost:3000/js/index.js:78679:27)
at Object.start (http://localhost:3000/js/index.js:78724:27)
at init (http://localhost:3000/js/index.js:78720:19)
JavaScript
/* ALL IMPORTANT CONFIG DATA
------------------------------------------------ */
const config = {
allMaps: [],
actualMap: document.getElementsByTagName('map')[0],
allAreas: false,
areaCoords: [],
vector: false,
};
/* RECALCULATION FUNCTIONALITY
------------------------------------------------ */
const RecalculateImageMap = {
init() {
/* AUTOMATICALLY UPDATE COORDINATES ON RESIZED WINDOW
------------------------------------------------ */
window.addEventListener('resize', ImageMapSetup.init);
if (!config.actualMap.newSize) {
RecalculateImageMap.start();
}
},
start() {
config.allAreas = config.actualMap.getElementsByTagName('area');
config.vector = document.getElementById('interactive_vector');
/* ALL COORDINATES TO ARRAY
------------------------------------------------ */
for (let i = 0; i < config.allAreas.length; i++) {
const coords = config.allAreas[i].coords;
config.areaCoords.push(coords.replace(/ *, */g, ',').replace(/ +/g, ','));
}
RecalculateImageMap.resize();
},
resize() {
/* FOR EACH AREA => RESIZE THE COORDINATES
------------------------------------------------ */
config.areaCoords.forEach(function(area, i) {
config.allAreas[i].coords = RecalculateImageMap.scale(area);
});
},
scale(area) {
const allValues = area.split(',');
/* CHECK FOR DIFFERENCE IN SCREENSIZE
------------------------------------------------ */
let totalScale = config.vector.width / config.vector.naturalWidth;
let newArea = [];
/* CHANGE EACH COORDINATE BASED ON THE NEW SCALE (DIFFERENCE SINCE LAST WIDTH)
------------------------------------------------ */
allValues.map(function(coordinate) {
let result = Math.round(Number(coordinate) * totalScale);
newArea.push(result);
});
return newArea;
}
};
/* INITIALIZE RESIZING
------------------------------------------------ */
const ImageMapSetup = {
init() {
ImageMapSetup.start(config.actualMap);
},
start(element) {
if (element) {
RecalculateImageMap.init(element);
config.allMaps.push(element);
}
}
};
ImageMapSetup.init();
Does anyone see what goes wrong when firing the init function on the resize event? I've been looking for a solution for a while now.. But without succes.
Thanks in advance!
IMHO the problem is that you are initializing config.allAreas in start(), but you are always adding coords to config.areaCoords
start() {
config.allAreas = config.actualMap.getElementsByTagName('area');
...
for (let i = 0; i < config.allAreas.length; i++) {
const coords = config.allAreas[i].coords;
config.areaCoords.push(coords.replace(/ *, */g, ',').replace(/ +/g, ','));
}
Afterwards in resize() you are looping over config.areaCoords, which now contains much more elements than config.allAreas:
resize() {
/* FOR EACH AREA => RESIZE THE COORDINATES
------------------------------------------------ */
config.areaCoords.forEach(function(area, i) {
config.allAreas[i].coords = RecalculateImageMap.scale(area);
});
},
So I suppose that the error occurs here at the config.allAreas[i].coords = assignment because i is much greater than the length of the config.allAreas array.
Furthermore this would explain your statement "The weird thing is that the function works perfect for the first time".
An assignment like config.areaCoords = []; in the start() function should solve the problem.
Related
I set up a grid 16x16 which a white background now i want the divs (grid items) to change color every time i press and hold my mouse and move over them, and to stop changing color when i stop the mousedown event, like in paint. in my script:
let gridContainer = document.getElementById('grid-container');
let gridArray = [];
for(let i = 0; i < 256; i++){
let div = document.createElement('div');
div.setAttribute('class', 'grid-item');
gridContainer.append(div);
gridArray[i] = div;
}
gridContainer.addEventListener("mousedown", draw)
gridContainer.addEventListener("mouseup",stopDraw)
function draw(){
gridArray.forEach(item => item.addEventListener("mouseover", () => {
(item.classList.add('hover'))
}));
}
function stopDraw(){
gridArray.forEach(item => item.removeEventListener("mouseover", () => {
(item.classList.add('hover'))
}));
}
The hover class is used to change the background color to blue.
I tried multiple other approaches but i always end up at the same place, the draw function not working unless i click which runs the function then it doesnt stop, it keeps running even after i leave the mouse.
Im using vanilla JS, I am still learning the basics.
Here is my code for better understanding my problem: https://codepen.io/ahmedmk11/pen/VwrmyGW
EDIT: I just realized that i didnt explain my problem in a clear way, so the draw function works properly, but my problem is that it doesnt stop working, i need in to only work when im pressing and holding only, like a pen.
Using event listeners is a good approach, to keep with this I have changed your code to use an object. Using an object allows the state of the mouse to be temporarily stored. Using the "canDraw()" method we can read from the object to determine if the mouse event is still occurring. It is still occurring if the key "mousedown" is still present.
The events now just add or remove the key from "mouseEvent" object.
let gridContainer = document.getElementById('grid-container');
let gridArray = [];
let mouseEvent = {};
for(let i = 0; i < 256; i++){
let div = document.createElement('div');
div.setAttribute('class', 'grid-item');
div.addEventListener("mouseover", draw);
gridContainer.append(div);
gridArray[i] = div;
}
gridContainer.addEventListener("mousedown", () => mouseEvent.mouseDown = true)
gridContainer.addEventListener("mouseup", () => delete mouseEvent.mouseDown)
function canDraw() {
return mouseEvent.mouseDown;
}
function draw(e){
if (canDraw()) {
e.fromElement.classList.add('hover');
}
}
Looks like you say that the div's should be paint when the mouse button is pressed, but you never really say that the divs should not be painted when the mouse button is not pressed, this happen in this specifc part:
function draw(){
gridArray.forEach(item => item.addEventListener("mouseover", () => {
(item.classList.add('hover'))
}));
}
function stopDraw(){
// right here!
gridArray.forEach(item => item.removeEventListener("mouseover", () => {
(item.classList.add('hover'))
}));
}
You could change your code to make something like "hey, when my mouse is up and over the divs, I don't want to insert the class that paint them", like this:
function draw(){
gridArray.forEach(item => item.addEventListener("mouseover", () => {
item.classList.add('hover');
}));
}
function stopDraw(){
// now we have a event that removes the class
gridArray.forEach(item => item.addEventListener("mouseover", () => {
item.classList.remove('hover');
}));
}
I also did some refactor (changed let by const when necessary, corrected the layout and moved the use of the functions draw and stopDraw after his declarations), I tried make less changes as I could, the final solution is:
const gridContainer = document.getElementById('grid-container');
let gridArray = [];
for(let i = 0; i < 256; i += 1){
const div = document.createElement('div');
div.setAttribute('class', 'grid-item');
gridContainer.append(div);
gridArray.push(div);
}
function draw(){
gridArray.forEach(item => item.addEventListener("mouseover", () => {
item.classList.add('hover');
}));
}
function stopDraw(){
gridArray.forEach(item => item.addEventListener("mouseover", () => {
item.classList.remove('hover');
}));
}
gridContainer.addEventListener("mousedown", draw);
gridContainer.addEventListener("mouseup", stopDraw);
I would like to create a Chrome extension to change the color of the text for all events in a particular calendar. I am modifying the code in an extension called gcalcolor. Here is the code in the content.js file of the extension:
// Content script for the extension. Does all the work.
"use strict";
// Colorizes an event element. Finds the colored dot, then sets the
// overall color to that dot's color (which is its borderColor; the
// dot is just an empty 0x0 element with a circular border). Also
// hides the dot, since it is no longer needed to show the color, and
// reduces padding to help line up events and let you see more of
// their names.
function colorizeEvent(eventEl) {
let success = true;
// First try layout for month and multi-week (custom) views.
let dotEl = eventEl;
for (let i=0; i<3; i++) {
dotEl = dotEl.firstChild;
if (!dotEl) {
success = false;
break;
}
}
if (success) {
let color = dotEl.style.borderColor;
if (!color) {
success = false; // Probably not a timed event
}
else {
eventEl.firstChild.style.color = color;
eventEl.firstChild.style.padding = '0';
dotEl.style.display = 'none';
}
}
// if the above failed, try the Schedule (Agenda) layout
if (!success) {
let timeEl = eventEl.firstChild;
if (!timeEl) {
return;
}
let detailsEl = timeEl.nextSibling;
if (!detailsEl) {
return;
}
let dotContainer1El = detailsEl.nextSibling;
if (!dotContainer1El) {
return;
}
let dotContainer2El = dotContainer1El.firstChild;
if (!dotContainer2El) {
return;
}
let dotEl = dotContainer2El.firstChild;
if (!dotEl) {
return;
}
let color = dotEl.style.borderColor;
if (!color) {
return;
}
else {
detailsEl.style.color = color;
eventEl.style.height = '28px';
dotContainer1El.style.display = 'none';
}
}
}
// Colorizes all visible events.
function colorizeAll() {
let eventElements = document.querySelectorAll('[data-eventid]');
for (let eventElement of eventElements) {
colorizeEvent(eventElement);
}
}
// We don't have a precise way to know when Google Calendar has drawn
// some new events on the screen. Instead we use a MutationObserver to
// watch for DOM changes anywhere on the page. It would be really
// inefficient to run colorizeAll every time we got an observer
// callback, so instead we wait for a short delay to see if any more
// callbacks happen. If so, we reset the timer and wait again. We call
// colorizeAll only when the timer completes without another callback.
//
// Because there are a lot of irregularly timed screen updates when
// the page is first being loaded, we set the delay to a quarter second
// at first. After five seconds, we set it to 20 milliseconds for a
// faster response to small updates.
let timeoutId = null;
let observerDelay = 250;
setTimeout(() => { observerDelay = 20; }, 5000);
function postObserverCallbacks() {
timeoutId = null;
colorizeAll();
}
function observerCallback(mutationList) {
if (timeoutId)
clearTimeout(timeoutId);
timeoutId = setTimeout(postObserverCallbacks, observerDelay);
}
let observer = new MutationObserver(observerCallback);
observer.observe(
document.body,
{
childList: true,
attributes: true,
subtree: true
}
);
I have already modified the following line as follows:
Original line
let color = dotEl.style.borderColor;
My new line
let color = '#FA8072';
This modification causes the text of all events to change to the same color.
Now, I want to change the color of events only in a particular calendar. I know the id of the calendar. For sake of illustration, let's say the calendar id is abcdefg1234567. I think the line of code I need to modify to select only events from this calendar is this line:
let eventElements = document.querySelectorAll('[data-eventid]');
I have searched for a few hours to try and figure out how to modify this line, but I haven't been able to figure it out.
Simple answer:
Delete "use strict"; at top of page :)
I'm trying to scroll a greensock tween in pixi. I'm getting errors trying to hook the code that gets the mouse/arrow input (trackpad.value) with my tween.
Here's my working greensock test tween, to make sure I have greensock working in pixi: (have to tween the position element in pixi):
var t1 = new TimelineMax({onUpdate:animate, onUpdateScope:stage});
t1.to(bg.position, 3, {y:100});
Here's my code where I'm trying to hook trackpad.value into the greensock code (I'm getting the following error: Uncaught TypeError: bg.position is not a function):
trackpad = new Trackpad(document);
var t1 = new TimelineMax({paused:true, onUpdate:animate, onUpdateScope:stage});
t1.progress(bg.position( Math.abs( trackpad.value ) / 3240));
I then tried the following - it didn't work (but I didn't get an error):
var moveIt = trackpad.value / 3240;
t1.progress(bg.position, moveIt, {});
Here's the code where the trackpad value is defined:
/*
* param: the html element that will be scrolled
*/
Trackpad = function(target)
{
this.target = target;
this.value = 0;
this.easingValue = 00;
this.dragOffset = 0;
this.dragging;
this.speed= 0;
this.prevPosition = 0;
$(this.target).mousedown($.proxy(this.onMouseDown, this));
this.target.onmousewheel = $.proxy(this.onMouseWheel, this);
// not forgetting touchs!
this.target.ontouchstart = $.proxy(this.onTouchStart, this);
// stop dragging!
$(document).keydown( $.proxy(this.onArrow, this))//function(e){
//this.target.ondragstart = function(){return false;}
}
// set constructor
Trackpad.constructor = Trackpad;
// create the functions
Trackpad.prototype.unlock = function()
{
this.locked = false;
this.speed = 0;
this.easingValue = this.value;
}
Trackpad.prototype.lock = function()
{
this.locked = true;
}
Trackpad.prototype.update = function()
{
if(this.easingValue > 0)this.easingValue = 0;
if(this.easingValue < -10700)this.easingValue = -10700;
this.value = this.easingValue;
if(this.dragging)
{
var newSpeed = this.easingValue - this.prevPosition;
newSpeed *= 0.7;
this.speed += (newSpeed - this.speed) *0.5;//+= (newSpeed - this.speed) * 0.5;
this.prevPosition = this.easingValue;
}
else
{
this.speed *= 0.9;
this.easingValue += this.speed;
if(Math.abs(this.speed) < 1)this.speed = 0;
}
}
Trackpad.prototype.onArrow = function(event)
{
if (event.keyCode == 38) {
// UP
this.speed = 4;
return false;
}
else if (event.keyCode == 40) {
// UP
this.speed -= 4
return false;
}
}
Trackpad.prototype.onMouseWheel = function(event)
{
event.preventDefault();
this.speed = event.wheelDelta * 0.1;
}
Trackpad.prototype.startDrag = function(newPosition)
{
if(this.locked)return;
this.dragging = true;
this.dragOffset = newPosition - this.value;
}
Trackpad.prototype.endDrag = function(newPosition)
{
if(this.locked)return;
this.dragging = false;
}
Trackpad.prototype.updateDrag = function(newPosition)
{
if(this.locked)return;
this.easingValue = (newPosition - this.dragOffset);
}
/*
* MOUSE
*/
Trackpad.prototype.onMouseDown = function(event)
{
if(event)event.preventDefault();
event.returnValue = false;
$(document).mousemove($.proxy(this.onMouseMove, this));
$(document).mouseup($.proxy(this.onMouseUp, this));
this.startDrag(event.pageY);
}
Trackpad.prototype.onMouseMove = function(event)
{
if(event)event.preventDefault();
this.updateDrag(event.pageY);
}
Trackpad.prototype.onMouseUp = function(event)
{
//$(this.target).mousemove(null);
$(document).unbind('mousemove');
$(document).unbind('mouseup');
//this.target.onmousemove = null;
this.endDrag();// = false;
}
/*
* TOUCH!
*/
Trackpad.prototype.onTouchStart = function(event)
{
//event.preventDefault();
this.target.ontouchmove = $.proxy(this.onTouchMove, this);
this.target.ontouchend = $.proxy(this.onTouchEnd, this);
this.startDrag(event.touches[0].clientY);
}
Trackpad.prototype.onTouchMove = function(event)
{
event.preventDefault();
this.updateDrag(event.touches[0].clientY);
}
Trackpad.prototype.onTouchEnd = function(event)
{
this.target.ontouchmove = null;
this.target.ontouchend = null;
this.endDrag();
}
** edit
tl = new TimelineLite( { paused: true } );
// respond to scroll event - in this case using jquery
$(window).scroll();
//apply whatever math makes the most sense to progress the timeline progress from 0 to 1 within those parameters. Something like,
$(window).scroll( function() {
var st = $(this).scrollTop();
if ( st < someArbitraryValue ) { // someArbitraryValue, where to start
// Here, "someOtherArbitaryValue" would be the
// "height" of the scroll to react to
tl.progress( Math.abs( st ) / someOtherArbitaryValue );
}
});
Is this the kind of effect you were after?
JavaScript:
window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})(); //http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
var stageWidth=$(window).innerWidth();
var stageHeight=$(window).innerHeight();
var renderer=PIXI.autoDetectRenderer(stageWidth,stageHeight);
var bg,cat,moon,blue,trackpad,texture1,texture2,texture3;
document.body.appendChild(renderer.view);
texture1=PIXI.Texture.fromImage('https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/cat.jpg');
texture2=PIXI.Texture.fromImage('https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/moon.jpg');
texture3=PIXI.Texture.fromImage('https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/blue.jpg');
bg=new PIXI.Container();
cat=new PIXI.Sprite(texture1);
moon=new PIXI.Sprite(texture2);
blue=new PIXI.Sprite(texture3);
cat.anchor.x=cat.anchor.y=moon.anchor.x=moon.anchor.y=blue.anchor.x=blue.anchor.y=0;
cat.position.x=cat.position.y=moon.position.x=blue.position.x=bg.position.x=bg.position.y=0;
cat.width=moon.width=blue.width=stageWidth;
moon.position.y=1080;
blue.position.y=2160;
bg.addChild(cat);
bg.addChild(blue);
bg.addChild(moon);
bg.vy=bg.vx=0;//what are those?
trackpad=new Trackpad(document);
requestAnimFrame(animate);
function animate(){
requestAnimFrame(animate);
bg.position.y=trackpad.value;
trackpad.update();
renderer.render(bg);
}
Let me know if this is exactly the thing you were looking for & I'll then break it down for you in terms of what has changed in comparison to your code.
Notes:
First & foremost, I have used the latest version (v3.0.6) of Pixi.JS in my example above. This v3 update brought a few major changes. Couple of them prominent to your problem are:
No need for Stage object anymore for rendering purposes. Any Container type object can be used directly to be rendered on canvas.
Shortening of the name DisplayObjectContainer to simply Container. This is probably the reason why you are getting the error when trying to implement my code in your environment that you mentioned in comments because I presume you are using one of the old verions.
Read all about this update here, here & here.
I always prefer to use the latest & greatest of GSAP (v1.17.0). Even the dot releases of this framework brings major updates which is why I like to keep it up to date. Read an important note on this update here. Having said that, the current implementation doesn't really use TweenMax at all.
TweenMax bundles EasePack, CSSPlugin & a few other things. No need to load them in separately. Update your HTML accordingly. Use this handy GSAP CheatSheet by Peter Tichy to get such information and more about this tool.
Changes in Trackpad.js:
Inside the update method, there was a maximum scroll limit defined the page can scroll up to. That value previously was -10700. I changed it to -2160. You may want to set it to -3240 I think, based on what I have been able to understand so far as to what you are trying to achieve.
Formatting changes.
Changes in main.js (whatever name you gave to your main script file):
Added a requestAnimationFrame polyfill thanks to Paul Irish.
Removed the var stage= new PIXI.Stage(0xff00ff); line. Read #1 above for details.
Renamed DisplayObjectContainer to Container which was assigned to bg. Read #1 above for details.
Added bg.position.y=trackpad.value; in the animate loop. You were missing this. You will need to use trackpad.value in order to position your bg.
Added trackpad.update(); in the same animate loop. This is the big one and IMHO, this is the one you were failing to understand the purpose of. In summary, Trackpad.js needs to update its value on a timely basis & the only loop you have got running is the animate loop thanks to requestAnimFrame. Hence, the update(); method is called.
Rendering bg instead of stage. Read #1 above for details.
Formatting changes.
Let me know if anything is unclear.
T
I thought of editing the old answer but decided against it because I think it answers your original question.
Take a look at this Codepen demo for a new approach to the same problem. I am really hoping to listen to community on the approach I have taken here in terms of listening to events and using them to adjust a GSAP timeline.
There are 4 JS files used in my example: app.js, constants.js, timeline.js & listeners.js. Links to which can be found in the settings gear icon of the JavaScript editor of the demo. All of these files are heavily annotated with links to solutions I found over the internet to specific problems.
Among these files, code of app.js is as follows:
JavaScript:
function Application(){}
Application.prototype.init=function(){
this.constants=Constants.getInstance();
this.BASE_URL=this.constants.BASE_URL;
this.IMAGE_JS_URL=this.constants.IMAGE_JS_URL;
this.IMAGE_PIXI_URL=this.constants.IMAGE_PIXI_URL;
this.IMAGE_GSAP_URL=this.constants.IMAGE_GSAP_URL;
this.createPolyfillForBind();
this.setupRenderer();
this.loadImages();
};
Application.prototype.setupRenderer=function(){
this.stageWidth=window.innerWidth;
this.stageHeight=window.innerHeight;
//this.renderer=PIXI.autoDetectRenderer(this.stageWidth,this.stageHeight);
this.renderer=new PIXI.CanvasRenderer(this.stageWidth,this.stageHeight);
document.body.appendChild(this.renderer.view);
};
Application.prototype.loadImages=function(){
var self=this;
this.loader=new PIXI.loaders.Loader(this.BASE_URL,1,{crossOrigin:''}); // PIXI Loader class [http://pixijs.github.io/docs/PIXI.loaders.Loader.html]
this.loader.add(this.IMAGE_JS_URL); // Loader extends ResourceLoader [http://adireddy.github.io/docs/haxe-pixi/v3/types/pixi/plugins/resourceloader/ResourceLoader.html]
this.loader.add(this.IMAGE_PIXI_URL);
this.loader.add(this.IMAGE_GSAP_URL);
//this.loader.once('complete',function(){self.onImagesLoaded.apply(self);}); // Vanilla JS alternative to jQuery's proxy() method [http://stackoverflow.com/a/4986536]
this.loader.once('complete',this.onImagesLoaded.bind(this)); // bind() polyfill [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill]
this.loader.load();
};
Application.prototype.onImagesLoaded=function(){
this.setupSprites();
this.initTimeline();
this.initListeners();
this.startTicker();
};
Application.prototype.setupSprites=function(){
this.containerBg=new PIXI.Container();
this.spriteJS=new PIXI.Sprite(PIXI.utils.TextureCache[this.BASE_URL+this.IMAGE_JS_URL]); // TextureCache in action [http://www.html5gamedevs.com/topic/7674-load-textures-synchronously/?p=45836]
this.spritePIXI=new PIXI.Sprite(PIXI.utils.TextureCache[this.BASE_URL+this.IMAGE_PIXI_URL]); // PIXI.TextureCache became PIXI.utils.TextureCache in v3 [http://www.html5gamedevs.com/topic/14144-v3-utilstexturecache-utils-is-not-defined/?p=80524]
this.spriteGSAP=new PIXI.Sprite(PIXI.utils.TextureCache[this.BASE_URL+this.IMAGE_GSAP_URL]);
this.containerBg.addChild(this.spriteJS);
this.containerBg.addChild(this.spritePIXI);
this.containerBg.addChild(this.spriteGSAP);
this.spriteJS.anchor.x=this.spriteJS.anchor.y=this.spritePIXI.anchor.x=this.spritePIXI.anchor.y=this.spriteGSAP.anchor.x=this.spriteGSAP.anchor.y=0;
this.spriteJS.position.x=this.spriteJS.position.y=this.spritePIXI.position.x=this.spriteGSAP.position.x=this.containerBg.position.x=this.containerBg.position.y=0;
this.scaleImage(this.spriteJS);
this.scaleImage(this.spritePIXI);
this.scaleImage(this.spriteGSAP);
this.spritePIXI.alpha=this.spriteGSAP.alpha=0;
this.spriteJS.position.y=this.constants.GUTTER;
this.spritePIXI.position.y=this.spriteJS.height*2+this.constants.GUTTER;
this.spriteGSAP.position.y=this.spriteJS.height+this.spritePIXI.height*2+this.constants.GUTTER;
};
Application.prototype.scaleImage=function(sprite){
//var scale=Math.min(this.stageWidth/sprite.width,this.stageHeight/sprite.height); // resize with aspect ratio [http://community.createjs.com/discussions/createjs/547-resizing-canvas-and-its-content-proportionally-cross-platform#comment_27266530] and [https://opensourcehacker.com/2011/12/01/calculate-aspect-ratio-conserving-resize-for-images-in-javascript/]
var scale=this.stageWidth/sprite.width;
sprite.scale.x=sprite.scale.y=scale;
};
Application.prototype.initTimeline=function(){
this.timeline=new Timeline();
this.timeline.init(this.containerBg,this.spriteJS,this.spritePIXI,this.spriteGSAP,this.stageWidth,this.stageHeight);
};
Application.prototype.initListeners=function(){
var self=this;
//this.listeners=new Listeners();
//this.constants.setListenersObject(this.listeners);
//this.listeners.init();
this.listeners=Listeners.getInstance();
this.listeners.addListeners();
document.addEventListener(this.constants.SCROLLED,this.onScroll.bind(this),false);
document.addEventListener(this.constants.STARTED_DRAG,this.onStartDrag.bind(this),false);
document.addEventListener(this.constants.DRAGGED,this.onDrag.bind(this),false);
document.addEventListener(this.constants.END_DRAG,this.onEndDrag.bind(this),false);
};
Application.prototype.onScroll=function(e){ this.timeline.onScroll(e); };
Application.prototype.onStartDrag=function(e){ this.timeline.onStartDrag(e); };
Application.prototype.onDrag=function(e){ this.timeline.onDrag(e); };
Application.prototype.onEndDrag=function(e){ this.timeline.onEndDrag(e); };
Application.prototype.startTicker=function(){
var self=this;
//TweenLite.ticker.addEventListener('tick',function(){self.render.apply(self);},false); // Vanilla JS alternative to jQuery's proxy() method [http://stackoverflow.com/a/4986536]
TweenLite.ticker.addEventListener('tick',this.render.bind(this),false);
};
Application.prototype.render=function(){this.renderer.render(this.containerBg);};
Application.prototype.createPolyfillForBind=function(){ // [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill]
if(!Function.prototype.bind){
Function.prototype.bind=function(oThis){
if(typeof this!=='function'){
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs=Array.prototype.slice.call(arguments,1),
fToBind=this,
fNOP=function(){},
fBound=function(){
return fToBind.apply(this instanceof fNOP
?this
:oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype=this.prototype;
fBound.prototype=new fNOP();
return fBound;
};
}
};
//
var app=new Application();
app.init();
P.S. I have also heavily experimented with design patterns in this same example, mainly Prototype and Singleton patterns. I am also looking forward to comments on them as well from the community.
T
I have a lot to learn so could really use some pointers: http://jsfiddle.net/David_Knowles/9kDC3/
QUESTION
I am trying store iteratively the height values of bars in a bar
chart.
Then i set the height of all to zero
I then trigger an animation of the bars where I increase height towards the original values stored in array
Problem
It looks to me that the array is being overwritten instead of
increasingly filled
I don't know what the best way is to share the array values with the
other script I later trigger
//
$(function(){
// get the height of all the bars
var $theBars = $("#v-bars").children();
var BarsHeight = $theBars.each(function(index, element ) {
var origHeight = [];
origHeight.push($(this).attr("height"));
console.log (origHeight);
});
//
$("#svg-skills-expertise").click(function() {
$($theBars).each(function(){
$(this).css("MyH",$(this).attr("height")).animate(
{
MyH:400 // this value needs to be the array values so how
},
{
step:function(v1){
$(this).attr("height",v1)
}
})
})
console.log ("Yeap the clicked it! callback");
});
});
Updated!
Initialized origHeight outside of your function call, added parameter "i" to $($theBars).each function (passes the index to the each call), and set MyH: origHeight[i].
/* SVG ARRAY \\\\\\\\\ */
var origHeight = [];
$(function(){
var $theBars = $("#v-bars").children();
var BarsHeight = $theBars.each(function(index, element ) {
origHeight.push($(this).attr("height"));
console.log (origHeight);
});
$("#svg-skills-expertise").click(function() {
$($theBars).each(function(i){
$(this).css("MyH",$(this).attr("height")).animate(
{
MyH:origHeight[i]
},
{
step:function(v1){
$(this).attr("height",v1)
}
})
})
console.log ("Yeap clicked it!");
});
});
check out my code
It works but jsfiddle hates it for some reason.
but when it's ran in a browser i get NaN upon calculation
for some reason regardless of the parse it won't return an integer to perform calculations on.
any one have an idea why?
also
// JavaScript Document
var payment
/* requirement #2* Each input (years, loan amount, interest rate)
will have its own number pad for entry */
function getNum(id,span) {
var a;
a = parseInt(document.getElementById(id).value);
document.getElementById(span).innerHTML += a;
}
function clear1(span) {
document.getElementById(span).innerHTML = "";
}
/* requirment #7 Mortgage object with three variables: years, amount, rate */
function Mortgage(years, amount, rate) {
this.years = years;
this.amount = amount;
this.rate = rate;
/*Requirment #8. Object must have an internal function that resets all
values/variables to default and clears amounts displayed to user */
this.clearAll = function() {
document.getElementById(years).innerHTML = "";
document.getElementById(amount).innerHTML = "";
document.getElementById(rate).innerHTML = "";
}
/*gets the mortgage from spans*/
this.getCalc = function() {
/*Requirment # 9 Object must call at least 1 external function */
get();
}
}
function test() {
/*uses the params to call the spans id*/
var c = new Mortgage('yInput','lInput','rInput');
c.clearAll();
}
/* an external cunction to calculate mortgage*/
function get() {
var m = new Mortgage(parseInt(document.getElementById('yInput').innerHTML),
parseInt(document.getElementById('lInput').innerHTML),
parseInt(document.getElementById('rInput').innerHTML)
);
/* this is NaN?*/
document.write(m.years-m.rate);
}
function calculate() {
var c = new Mortgage();
c.getCalc();
}
http://jsfiddle.net/5qf7f/6/#run
In the part:
> /* this is NaN?*/
> document.write(m.years-m.rate);
Note that if the document has finished loading, a call to document.write will first call document.open, which clears the entire content of the document (including all scripts and the HTML element itself).
http://jsfiddle.net/5qf7f/6/#run
That "fiddle" doesn't work at all for me. Better to reduce your code to an absolute minimum that displays the issue and post that. The exercise will likely lead you to your problem.
It might help your investigation to know that parseInt('') returns NaN.