2

If i create a famo.us surface giving a size of [true, true] and put some arbitrary html content into it, is there a clean way to retrieve the size of the object?

surface.getSize() just returns the same [true,true]

I noticed there are some apparently private methods such as: s._currTarget.clientHeight but it seems asking for trouble to use those!

dcsan
  • 11,333
  • 15
  • 77
  • 118

3 Answers3

3

There are a couple of ways to solve this issue. Famo.us is aware of this limitation and it should be pretty high on the priority list..

In this example, a new surface class is created that emits an event in the deploy function or when the surface is rendered. I am sure to grab the reference to the original deploy function during construction, so that can be called normally later on. Once you receive the render event you can edit the surface any way you wish..

Good Luck!

var Engine            = require('famous/core/Engine');
var Surface           = require('famous/core/Surface');
var StateModifier     = require('famous/modifiers/StateModifier');
var EventHandler      = require('famous/core/EventHandler');


function MySurface(options) {
    Surface.apply(this, arguments);
    this._superDeploy = Surface.prototype.deploy;
}

MySurface.prototype = Object.create(Surface.prototype);
MySurface.prototype.constructor = MySurface;


MySurface.prototype.deploy = function deploy(target) {
  this._superDeploy(target);
  this.eventHandler.trigger('surface-has-rendered', this);
};

var context = Engine.createContext();

var event_handler = new EventHandler();

event_handler.on('surface-has-rendered', function(surface){

  var size = surface.getSize();
  var width = (size[0] == true) ? surface._currTarget.offsetWidth : size[0] ;
  var height = (size[1] == true) ? surface._currTarget.offsetHeight : size[1] ;

  surface.setSize([width,height]);

  console.log(surface.getSize());

})

var surface = new MySurface({
  size: [true,true],
  content: "Hello",
  properties: {
    color: 'white',
    textAlign: 'center',
    padding: '20px',
    backgroundColor: 'green'
  }
})

surface.pipe(event_handler);

context.add(new StateModifier({origin:[0.5,0.5]})).add(surface);
johntraver
  • 3,612
  • 18
  • 17
  • thanks for the quick reply. It's a bit involved for getting the width of a surface. I'm getting `Exception in queued task: TypeError: Cannot read property 'clientWidth' of null` even when setting a timeout before calling the peek function, presumably since its evaluated before its called? your more elaborate solution should take care of this. – dcsan Apr 27 '14 at 05:22
  • Yes.. if you look at the normal deploy function for any of the surface classes.. you can see that it takes a target as the first parameter. This could be done in the core code for Surface, but it's best just to subclass. – johntraver Apr 27 '14 at 05:26
  • The event makes it a bit more elaborate as well. You could always apply the same logic in the overridden deploy function and not worry about the eventing. – johntraver Apr 27 '14 at 05:28
  • thanks for the detailed reply. i guess this is the only way currently >. – dcsan Apr 28 '14 at 00:27
  • It is unfortunately! It has been mentioned a lot on the IRC channel, Seems like something that will be fixed soon! – johntraver Apr 28 '14 at 00:30
2

Passing true into .getSize currently returns the DOM size of the Surface.

surface.getSize(true)

dmvaldman
  • 413
  • 2
  • 13
2

The easiest way to get the actual size of a surface is surface.getSize(true). You don't need to subclass Surface.

However, you will get an error if the surface isn't rendered to DOM yet. When a surface is rendered, it will emit a 'deploy' event. You can listen for it like this:

surface.on('deploy', function () {
    // Your Code Here
}.bind(this));

More than likely you will also have to wrap your code in a Timer.setTimeout() too. This is because the surface.getSize(true) method will execute faster than the next render cycle (60 frames per second or ~16 milliseconds per cycle). The final code will look like this:

// With the rest of your require statements
var Timer = require('famous/utilities/Timer');

surface.on('deploy', function () {
    Timer.setTimeout( function () {
        // Your code here
        // this.surface.getSize(true)
    }.bind(this), 16);
}.bind(this));

I'm new to Famo.us too but I have had to implement this fix for a few different situations in my project and it seems to work perfectly.

Let me know if it works for you.

ajlin500
  • 41
  • 4