This node does not have access to a size component - javascript

My code looks like this
var FamousEngine = require('famous/core/FamousEngine');
var DOMElement = require('famous/dom-renderables/DOMElement');
var Position = require('famous/components/Position');
var Transitionable = require('famous/transitions/Transitionable');
var Size = require('famous/components/Size')
var Tile = require('./Tile.js');
var Card = require('./Card.js');
var Selector = require('./Selector.js');
var ChannelCard = require('./ChannelCard.js');
var PanelCard = require('./PanelCard.js');
var KeyCodes = require('../utils/KeyCodes.js');
function App(selector, data) {
this.context = FamousEngine.createScene(selector);
this.rootNode = this.context.addChild();
this.tilesData = data.tilesData;
this.selectedTileIndex = 0;
this.tiles = [];
var firstNode = this.rootNode.addChild(new Card('url(images/tile-01-vidaa.png)','#9a105f', FIRST_X_POSITION, Y_POSITION));
}.bind(this));
module.exports = App;
where Card.js looks like this :
var DOMElement = require('famous/dom-renderables/DOMElement');
var FamousEngine = require('famous/core/FamousEngine');
var Transitionable = require('famous/transitions/Transitionable');
var Node = require('famous/core/Node');
var FIRST_X_POSITION = 100;
var Y_POSITION = 200;
function Card(bgUrl, bgColor, xpos, ypos) {
Node.call(this);
console.log("xpos + " + xpos);
console.log("ypos + " + ypos);
this.setSizeMode('absolute', 'absolute');
this.setAbsoluteSize(250, 250);
this.setPosition(xpos, ypos);
this.nodeDomElement = new DOMElement(this);
this.nodeDomElement.setProperty('backgroundImage', bgUrl);
this.nodeDomElement.setProperty('background-color', bgColor);
}
Card.prototype = Object.create(Node.prototype);
Card.prototype.constructor = Card;
module.exports = Card;
However, when I run in using famous dev, I get the following error
Uncaught Error: This node does not have access to a size component
setSizeMode # Node.js:1061Card # Card.js:11App # App.js:43
Please help me figure out what is causing the error and how to fix.

Your Node needs a context. If you have not yet added the node to a scene (or there is not yet a scene), add it before running any methods on the components. In the example of my 3D Asteroids game, I had to do the following to avoid the error:
function Game(scene, world) {
Node.call(this);
scene.addChild(this);
this._domElement = new DOMElement(this);
this.world = world;
this.asteroids = [];
this.bullets = [];
this.setProportionalSize(1, 1, 1);
this.addUIEvent('click');
this.addUIEvent('keydown');
}
If you have not yet created a scene, you can do so by running:
function Game() {
// ...
var context = FamousEngine.getContext('body');
context.addChild(this);
}

I believe the issue was a bug in Famous Engine and there were 2 manifestations of it.
The first manifestation was fixed by the following PR :
https://github.com/Famous/engine/pull/349
The second manifestation was fixed by the following PR :
https://github.com/Famous/engine/pull/350
However, at the time of writing this, these have not been merged to master so one needs to work off develop branch to have these fixes.

Related

HTML canvas measureText().width is too big

I try to find out the width of a text in a html canvas.
I'm using the measureText method but it gives me a value the is more than double as expected. I generate the Text by using the toSting method. If I just hard code the return from toSting into measureText it works fine...
console.log("--->width "+this.ctx.measureText("-100").width);
returns 22
console.log(labels[i]);
returns "-100"
console.log("->width "+this.ctx.measureText(labels[i]).width);
returns 48
Any ideas why?
thanks for help!
Here is the whole code: https://jsfiddle.net/falkinator/Lze1rnm5/4/
function createGraph(){
this.canvas = document.getElementById("graph");
this.ctx = this.canvas.getContext("2d");
this.options={};
this.datasets=[];
this.options.fontSize=11;
this.ctx.font=this.options.fontSize+"px Arial";
this.ctx.textAlign="left";
this.ctx.textBaseline="middle";
this.datasetLength=500;
this.dataset=function(options){
/*this.strokeColor=options.strokeColor;
this.signalName=options.signalName;
this.signalMin=options.signalMin;
this.signalMax=options.signalMax;
this.signalUnit=options.signalUnit;*/
this.data=[];
this.min;
this.max;
};
this.buildYLabels = function(scaleMin, scaleMax){
var labels = [];
var maxLabelWidth=0;
console.log("--->width "+this.ctx.measureText("-100").width);
for(i=10;i>=0;i--){
labels.push((scaleMin+((scaleMax-scaleMin)/10)*i).toString());
console.log((scaleMin+((scaleMax-scaleMin)/10)*i).toString());
console.log("->width "+this.ctx.measureText(labels[i]).width);
if(maxLabelWidth<this.ctx.measureText(labels[i]).width){
maxLabelWidth=this.ctx.measureText(labels[i]).width;
}
}
return {labels: labels,
maxLabelWidth: maxLabelWidth};
};
this.buildXLabels = function(x){
};
this.draw = function (){
var _this=this;
each(this.datasets,function(dataset, index){
//plot data
if(index>0)return;
//draw scale
var canvasHeight = _this.canvas.height;
console.log("canvas height="+canvasHeight);
var yLabels = _this.buildYLabels(-100, 500);
var currX = _this.options.fontSize/2;
var scaleHeight = canvasHeight-_this.options.fontSize*1.5;
var maxLabelWidth=yLabels.maxLabelWidth;
console.log(yLabels.maxLabelWidth);
each(yLabels.labels,function(label, index){
_this.ctx.fillText(label,0,currX);
console.log(label);
currX+=(scaleHeight/10);
});
_this.ctx.beginPath();
_this.ctx.moveTo(maxLabelWidth,0);
_this.ctx.lineTo(maxLabelWidth,canvasHeight);
_this.ctx.stroke();
});
};
this.addSignal = function(){
var dataset = new this.dataset({});
this.datasets.push(dataset);
};
this.pushData = function(data){
var _this=this;
if(data.length!=this.datasets.length){
console.error("the number of pushed data is diffrent to the number of datasets!");
return;
}
each(data,function(data, index){
_this.datasets[index].data.push(data);
if(_this.datasets[index].data.length>_this.datasetLength){
_this.datasets[index].data.shift();
}
});
};
this.calculateScaling = function(dataset){
var range = dataset.max - dataset.min;
var decStep = Math.pow(10,Math.floor(Math.log10(range)));
var scaleMin = roundTo(dataset.min/*+(decStep*10)/2*/, decStep);
var scaleMax = roundTo(dataset.max/*+(decStep*10)/2*/, decStep);
var scaleStep = (scaleMax - scaleMin)/10;
};
var minx=-34, maxx=424;
var range = maxx - minx;
var decStep = Math.pow(10, Math.floor(Math.log10(range)));
var scaleMin = roundTo(minx-(decStep/2), decStep);
var scaleMax = roundTo(maxx+(decStep/2), decStep);
var scaleStep = (scaleMax - scaleMin)/10;
console.log(this.buildYLabels(scaleMin,scaleMax));
console.log("range="+range);
console.log("log="+Math.floor(Math.log10(range)));
console.log("scaleStep="+scaleStep);
console.log("decStep="+decStep);
console.log("scaleMin="+scaleMin);
console.log("scaleMax="+scaleMax);
}
graph = new createGraph();
graph.addSignal();
graph.addSignal();
graph.addSignal();
graph.pushData([1,2,3]);
graph.pushData([1,2,3]);
graph.draw();
function each(array, callback){
console.log(callback);
for(i in array){
callback(array[i], i);
}
}
function roundTo(num, to){
return Math.round(num/to)*to;
}
<canvas id="graph"></canvas>
In your code that generates the labels, the loop index i is going from 10 to 0. Each time though the loop you are pushing a new label to the array (i.e. labels[0], labels[1], ...) but you are attempting to measure the labels using the loop index i (i.e. labels[10], labels[9], ...). Thus, the first few measurments are of the text "undefined".
Change...
console.log("->width "+this.ctx.measureText(labels[i]).width);
if(maxLabelWidth<this.ctx.measureText(labels[i]).width){
maxLabelWidth=this.ctx.measureText(labels[i]).width;
to...
console.log("->width "+this.ctx.measureText(labels[labels.length-1]).width);
if(maxLabelWidth<this.ctx.measureText(labels[labels.length-1]).width){
maxLabelWidth=this.ctx.measureText(labels[labels.length-1]).width;

Uncaught TypeError: this._queue[1] is not a function

My index.js looks like this
'use strict';
// Famous dependencies
var DOMElement = require('famous/dom-renderables/DOMElement');
var FamousEngine = require('famous/core/FamousEngine');
var CustomNode = require('./CustomNode');
var Animation = require('./components/Animation');
// Boilerplate code to make your life easier
FamousEngine.init();
var scene = FamousEngine.createScene('body');
var rootNode = scene.addChild();
var plane = rootNode.addChild(new CustomNode('url(images/plane_100x100.png)', '#B3E5FC', 200, 200, 100, 100));
var animation = new Animation(plane);
animation.start();
where CustomNode.js is
var DOMElement = require('famous/dom-renderables/DOMElement');
var FamousEngine = require('famous/core/FamousEngine');
var Transitionable = require('famous/transitions/Transitionable');
var Size = require('famous/components/Size');
var Node = require('famous/core/Node');
function CustomNode(bgUrl, bgColor, xpos, ypos, width, height) {
Node.call(this);
this.setSizeMode('absolute', 'absolute')
.setAbsoluteSize(width, height)
.setPosition(xpos,ypos);
this.nodeDomElement = new DOMElement(this);
this.nodeDomElement.setProperty('backgroundImage', bgUrl);
this.nodeDomElement.setProperty('zIndex', '2');
this.nodeDomElement.setProperty('background-color', bgColor);
}
CustomNode.prototype = Object.create(Node.prototype);
CustomNode.prototype.constructor = CustomNode;
module.exports = CustomNode;
And Animation.js looks like this
var FamousEngine = require('famous/core/FamousEngine');
var Transitionable = require('famous/transitions/Transitionable');
// A component that will animate a node's position in x.
function Animation (node) {
// store a reference to the node
this.node = node;
// get an id from the node so that we can update
this.id = node.addComponent(this);
// create a new transitionable to drive the animation
this.xPosition = new Transitionable(100);
}
Animation.prototype.start = function start () {
// request an update to start the animation
this.node.requestUpdate(this.id);
// begin driving the animation
this.xPosition.from(100).to(1000, {duration: 1000});
this.node.requestUpdate(this.id);
};
Animation.prototype.onUpdate = function onUpdate () {
// while the transitionable is still transitioning
// keep requesting updates
if (this.xPosition.isActive()) {
// set the position of the component's node
// every frame to the value of the transitionable
this.node.setPosition(this.xPosition.get());
this.node.requestUpdateOnNextTick(this.id);
}
};
module.exports = Animation;
But when I run famous dev, I get the following error
Uncaught TypeError: this._queue[1] is not a function
Please note that I am working off of the develop branch of famous/engine
This code is posted on github
https://github.com/codesdk/famous_engine_issue_debug_animation
for easy cloning
Please use the instructions in the README
Be sure to pass the correct arguments into Transitionable#to:
this.xPosition.from(100).to(1000, 'linear', 1000);
You may have mixed up the set and to methods of Transitionable.
this.xPosition.from(100).to(1000, {duration: 1000});
Should be:
this.xPosition.from(100).to(1000, 'linear', 1000);
Animation.prototype.start = function start () {
// request an update to start the animation
this.node.requestUpdate(this.id);
// begin driving the animation
this.xPosition.from(100).to(1000, 'linear', 1000);
this.node.requestUpdate(this.id);
};
Remember that setPosition of a node takes all three axis setPosition(x,y,z)
Animation.prototype.onUpdate = function onUpdate () {
// while the transitionable is still transitioning
// keep requesting updates
if (this.xPosition.isActive()) {
// set the position of the component's node
// every frame to the value of the transitionable
this.node.setPosition(this.xPosition.get(), 0, 0);
this.node.requestUpdateOnNextTick(this.id);
}
};

Famo.us IframeSurface

I tried implementing an iframe within a surface.
/* globals define */
define(function(require, exports, module) {
'use strict';
// import dependencies
var Engine = require('famous/core/Engine');
var Modifier = require('famous/core/Modifier');
var Transform = require('famous/core/Transform');
var Surface = require('famous/core/Surface');
var mainContext = Engine.createContext();
var content = 'abc';
var logo = new Surface({
size: [undefined, undefined],
content: '<iframe width=1024 height=768 src="http://www.bbc.com"></iframe>'
});
var centerModifier = new Modifier({
origin: [0, 0]
});
centerModifier.setTransform(Transform.scale(.5,.5,0));
mainContext.add(centerModifier).add(logo);
});
The scroll seems to freez up if i scale it.
Anyone had used iframe surface with Famou.us.
Its not included in the library yet.
It looks like you are scaling the z infinitesimally small with..
centerModifier.setTransform(Transform.scale(.5,.5,0));
It should be changed to..
centerModifier.setTransform(Transform.scale(.5,.5,1));
Good Luck!
You can easily create new elements:
define(function(require, exports, module) {
var Surface = require('famous/core/Surface');
function IFrameSurface(options) {
this._url = undefined;
Surface.apply(this, arguments);
}
IFrameSurface.prototype = Object.create(Surface.prototype);
IFrameSurface.prototype.constructor = IFrameSurface;
IFrameSurface.prototype.elementType = 'iframe';
IFrameSurface.prototype.elementClass = 'famous-surface';
IFrameSurface.prototype.setContent = function setContent(url) {
this._url = url;
this._contentDirty = true;
};
IFrameSurface.prototype.deploy = function deploy(target) {
target.src = this._url || '';
};
IFrameSurface.prototype.recall = function recall(target) {
target.src = '';
};
module.exports = IFrameSurface;
});
Usage:
new IFrameSurface({content: 'url here'})
The z-transform as mentioned is an issue. Just for the record iframes work fine in famo.us. I'm using multiple animating iframes without issue. Almost any HTML can go in a surface so there's no need for a specialist iframe surface really.

EaselJs: Objects, Classes, and Making A Square Move

Although I have used Javascript extensively in the past, I have never used classes and objects in my programs. This is also the first for me using the HTML5 canvas element with an extra Javascript library. The library I'm using is EaselJS.
Short and sweet, I'm trying to make a square move with keyboard input, using object-oriented programming. I've already looked over sample game files, but I've never been able to properly get one to work.
The following is my classes script:
/*global createjs*/
// Shorthand createjs.Shape Variable
var Shape = createjs.Shape;
// Main Square Class
function square(name) {
this.name = name;
this.vX = 0;
this.vY = 0;
this.canMove = false;
this.vX = this.vY = 0;
this.canMove = false;
this.body = new Shape();
this.body.graphics.beginFill("#ff0000").drawRect(0, 0, 100, 100);
}
And below is my main script:
/*global createjs, document, window, square, alert*/
// Canvas and Stage Variables
var c = document.getElementById("c");
var stage = new createjs.Stage("c");
// Shorthand Create.js Variables
var Ticker = createjs.Ticker;
// Important Keycodes
var keycode_w = 87;
var keycode_a = 65;
var keycode_s = 83;
var keycode_d = 68;
var keycode_left = 37;
var keycode_right = 39;
var keycode_up = 38;
var keycode_down = 40;
var keycode_space = 32;
// Handle Key Down
window.onkeydown = handleKeyDown;
var lfHeld = false;
var rtHeld = false;
// Create Protagonist
var protagonist = new square("Mr. Blue");
// Set Up Ticker
Ticker.setFPS(60);
Ticker.addEventListener("tick", stage);
if (!Ticker.hasEventListener("tick")) {
Ticker.addEventListener("tick", tick);
}
// Init Function, Prepare Protagonist Placement
function init() {
protagonist.x = c.width / 2;
protagonist.y = c.height / 2;
stage.addChild(protagonist);
}
// Ticker Test
function tick() {
if (lfHeld) {
alert("test");
}
}
// Handle Key Down Function
function handleKeyDown(event) {
switch(event.keyCode) {
case keycode_a:
case keycode_left: lfHeld = true; return false;
case keycode_d:
case keycode_right: rtHeld = true; return false;
}
}
This is the error I get in the Developer Tools of Chrome:
Uncaught TypeError: undefined is not a function
easeljs-0.7.0.min.js:13
In case you're wondering, the order of my script tags is the EaselJS CDN, followed by my class, followed by the main script file.
I would really like closure on this question. Thank you in advance.
I figured it out. I was adding the entire protagonist instance to the stage. I've fixed by adding the protagonist.body to the stage.

ipad safari stops running code events (canvases with 1 image object) out of memory

(Yeah I'm from sweden so my english might not be perfect ;)
I have troubles with memory on the ipad. This code does not crash the broser, but it just stops. At some point it never goes in to any of the event handlers on the Image object. I have no clue why..? I have searched the forum and googled for a couple of days about workarounds. But they don't really fit what I am trying to achieve(?). (Because I only have 1 Image object).
What I have created is as follows:
1 main canvas which is visible to the user.
16 other canvases which I draw on.
1 Image Object which I load images with.
all images are pngs with alpha and have the following dimension 900x373 px. All the canvases have the same dimensions.
On the 16 other canvases there are drawn 8 images.
The purpose of this is to be able to rotate an object which has interchangable layers.
(1 angle is an object from a different angle, so it will look like it's rotating when the main loop runs.) The rotation is supposed to be controlled by touch/mouse but this should demonstrate what I want to achieve.
I know that this is a lot of code to look through and it might not be the best written code either since I'm a novice at javascript. However it does work fine on my laptop in chrome.
I've read something about events holding references to imageObjects and therefore they would not get GC'd. But does that imply here when I only have one Image Object ?
I also tried adding and removing the listeners with jquery syntax but no success.
It would be much appreciated if anyone would take the time to answer this.
Regards Oscar.
initialization of variables:
var drawingCanvas = null;
var context = null;
var numAngles = 8;
var angleStep = 32/ numAngles;
var canvasAngles = [];
var loadStatus = {};
var basePath = "assets_900/";
var layerPaths = [];
var layerPathsA = ["black/","v16/","f86/","fA00049/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsB = ["red/","v16/","f86/","fA00049/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsC = ["black/","v16/","f86/","fR134/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsD = ["red/","v16/","f86/","fR134/","fA00340/","fTG02/","fTG02/","fTJ02/"];
var layerPathsArr = [layerPathsA,layerPathsB,layerPathsC,layerPathsD];
layerPathsCounter = 0;
var numLayers = layerPaths.length;
var imageInit = null;
var SW = 900; //1920
var SH = 373; //796
var loopcounter = 0;
first setup of canvases and other stuf:
layerPaths = layerPathsArr[0];
drawingCanvas = document.getElementById('myDrawing');
context = drawingCanvas.getContext('2d');
for(var i = 0; i < numAngles; i++){
var canvas = document.createElement('canvas');
var canvasContext = canvas.getContext('2d');
canvasContext.createImageData(SW, SH);
canvas.height = SH;
canvas.width = SW;
canvasAngles.push(canvas);
}
this will init the loop, and then it will never stop, it will jsut continue until mobile safari crashes:
loadImage(0,0,0);
this is a loop that loads images:
when it has loaded 8 images it draws them on one of the 16 canvases and then that canvas gets drawn on the visible canvas. then it loads a new angle and 8 new images , and so on...
function loadImage(pathIndex,layerIndex,angleIndex){
if(layerIndex < layerPaths.length ){
//logger.log("path :" + pathIndex +" lajr : "+ layerIndex + " angl: " + angleIndex);
imageInit = new Image();
imageInit.onload = function(){
var canvas = canvasAngles[angleIndex];
var canvasContext = canvas.getContext('2d');
canvasContext.drawImage(imageInit,0, 0);
imageInit.onload = null;
imageInit.onerror = null;
imageInit.onabort = null;
imageInit.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
imageInit = null;
delete imageInit;
loadImage(pathIndex,layerIndex+1,angleIndex);
}
imageInit.onerror = function(){
logger.log("Error loading, retrying....");
loadImage(pathIndex,layerIndex,angleIndex);
}
imageInit.onabort = function(){
logger.log("Error loading (aborted)");
}
var path = "";
if(pathIndex < 10){
path = basePath + layerPaths[layerIndex] + "img000"+ pathIndex + ".png";
}else{
path = basePath + layerPaths[layerIndex] + "img00"+ pathIndex + ".png";
}
imageInit.src = path;
}else{
displayAngle(angleIndex);
if(angleIndex > numAngles-2){
logger.log("turns : " + loopcounter++ +" C: " + layerPathsCounter);
clearCanvases();
loadImage(0,0,0);
layerPathsCounter++;
if(layerPathsCounter > layerPathsArr.length-1){
layerPathsCounter = 0;
}
layerPaths = layerPathsArr[layerPathsCounter];
}else{
loadImage(pathIndex+angleStep,0,angleIndex+1);
}
}
}
heres a couple of helper functions :
function clearCanvases(){
for(var i = 0; i < numAngles; i++){
var canvas = canvasAngles[i];
var canvasContext = canvas.getContext('2d');
canvasContext.clearRect(0,0,drawingCanvas.width, drawingCanvas.height);
}
}
function displayAngle(index){
context.clearRect(0,0,drawingCanvas.width, drawingCanvas.height);
var canvas = canvasAngles[index];
context.drawImage(canvas,0,0);
}
HTML :
<body >
<canvas id="myDrawing" width="900" height="373">
<p>Your browser doesn't support canvas. (HEHE)</p>
</canvas>
</body>
It seems like you can only load ~6.5 mb in one tab. And as far as I know there is no way to free up this memory (?)
this will load about 13 500kb imqages on an ipad and then stop..,
http://www.roblaplaca.com/examples/ipadImageLoading/img.html

Categories

Resources