I'm new to Famo.us and I am trying to expand on the Timbre sample app by adding a scrollview to the PageView where the image would be (in the _createBody function). In other words, I'm trying to add a feed similar to Facebook or Tango, etc. I found two pieces of code online that's been working with (links below). I get no errors on the console log, yet the scrollview won't display, so I'm not sure what I am missing. Your guidance is much appreciated (would also love to know if there is a better way). Finally, this is my first post ever on StackOverflow, so please let me know if I can expose my issue in a better fashion.
Links I have been using for guidance:
StackOverflowFamo.us swipe on scrollview
JSFiddle
/*** AppView.js ***/
define(function(require, exports, module) {
var View = require('famous/core/View');
var Surface = require('famous/core/Surface');
var Modifier = require('famous/core/Modifier');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var Easing = require('famous/transitions/Easing');
var Transitionable = require('famous/transitions/Transitionable');
var GenericSync = require('famous/inputs/GenericSync');
var MouseSync = require('famous/inputs/MouseSync');
var TouchSync = require('famous/inputs/TouchSync');
GenericSync.register({'mouse': MouseSync, 'touch': TouchSync});
var PageView = require('views/PageView');
var MenuView = require('views/MenuView');
var StripData = require('data/StripData');
function AppView() {
View.apply(this, arguments);
this.menuToggle = false;
this.pageViewPos = new Transitionable(0);
_createPageView.call(this);
_createMenuView.call(this);
_setListeners.call(this);
_handleSwipe.call(this);
}
AppView.prototype = Object.create(View.prototype);
AppView.prototype.constructor = AppView;
AppView.DEFAULT_OPTIONS = {
openPosition: 276,
transition: {
duration: 300,
curve: 'easeOut'
},
posThreshold: 138,
velThreshold: 0.75
};
function _createPageView() {
this.pageView = new PageView();
this.pageModifier = new Modifier({
transform: function() {
return Transform.translate(this.pageViewPos.get(), 0, 0);
}.bind(this)
});
this._add(this.pageModifier).add(this.pageView);
}
function _createMenuView() {
this.menuView = new MenuView({ stripData: StripData });
var menuModifier = new StateModifier({
transform: Transform.behind
});
this.add(menuModifier).add(this.menuView);
}
function _setListeners() {
this.pageView.on('menuToggle', this.toggleMenu.bind(this));
}
function _handleSwipe() {
var sync = new GenericSync(
['mouse', 'touch'],
{direction : GenericSync.DIRECTION_X}
);
this.pageView.pipe(sync);
sync.on('update', function(data) {
var currentPosition = this.pageViewPos.get();
if(currentPosition === 0 && data.velocity > 0) {
this.menuView.animateStrips();
}
this.pageViewPos.set(Math.max(0, currentPosition + data.delta));
}.bind(this));
sync.on('end', (function(data) {
var velocity = data.velocity;
var position = this.pageViewPos.get();
if(this.pageViewPos.get() > this.options.posThreshold) {
if(velocity < -this.options.velThreshold) {
this.slideLeft();
} else {
this.slideRight();
}
} else {
if(velocity > this.options.velThreshold) {
this.slideRight();
} else {
this.slideLeft();
}
}
}).bind(this));
}
AppView.prototype.toggleMenu = function() {
if(this.menuToggle) {
this.slideLeft();
} else {
this.slideRight();
this.menuView.animateStrips();
}
};
AppView.prototype.slideLeft = function() {
this.pageViewPos.set(0, this.options.transition, function() {
this.menuToggle = false;
}.bind(this));
};
AppView.prototype.slideRight = function() {
this.pageViewPos.set(this.options.openPosition, this.options.transition, function() {
this.menuToggle = true;
}.bind(this));
};
module.exports = AppView;
});
/*** PageView.js ***/
define(function(require, exports, module) {
var View = require('famous/core/View');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var HeaderFooter = require('famous/views/HeaderFooterLayout');
var ImageSurface = require('famous/surfaces/ImageSurface');
var Scrollview = require('famous/views/Scrollview');
function PageView() {
View.apply(this, arguments);
_createBacking.call(this);
_createLayout.call(this);
_createHeader.call(this);
_createBody.call(this);
_setListeners.call(this);
}
PageView.prototype = Object.create(View.prototype);
PageView.prototype.constructor = PageView;
PageView.DEFAULT_OPTIONS = {
headerSize: 44
};
function _createBacking() {
var backing = new Surface({
properties: {
backgroundColor: 'black',
boxShadow: '0 0 20px rgba(0,0,0,0.5)'
}
});
this.add(backing);
}
function _createLayout() {
this.layout = new HeaderFooter({
headerSize: this.options.headerSize
});
var layoutModifier = new StateModifier({
transform: Transform.translate(0, 0, 0.1)
});
this.add(layoutModifier).add(this.layout);
}
function _createHeader() {
var backgroundSurface = new Surface({
properties: {
backgroundColor: 'black'
}
});
this.hamburgerSurface = new ImageSurface({
size: [44, 44],
content : 'img/hamburger.png'
});
var searchSurface = new ImageSurface({
size: [232, 44],
content : 'img/search.png'
});
var iconSurface = new ImageSurface({
size: [44, 44],
content : 'img/icon.png'
});
var backgroundModifier = new StateModifier({
transform : Transform.behind
});
var hamburgerModifier = new StateModifier({
origin: [0, 0.5],
align : [0, 0.5]
});
var searchModifier = new StateModifier({
origin: [0.5, 0.5],
align : [0.5, 0.5]
});
var iconModifier = new StateModifier({
origin: [1, 0.5],
align : [1, 0.5]
});
this.layout.header.add(backgroundModifier).add(backgroundSurface);
this.layout.header.add(hamburgerModifier).add(this.hamburgerSurface);
this.layout.header.add(searchModifier).add(searchSurface);
this.layout.header.add(iconModifier).add(iconSurface);
}
function _createBody() {
var surfaces = [];
this.scrollview = new Scrollview();
var temp;
for (var i = 0; i < 30; i++) {
temp = new Surface({
size: [undefined, 80],
content: 'Surface: ' + (i + 1),
properties: {
textAlign: 'left',
lineHeight: '80px',
borderTop: '1px solid #000',
borderBottom: '1px solid #fff',
backgroundColor: '#ffff00',
fontFamily: 'Arial',
backfaceVisibility: 'visible',
paddingLeft: '10px'
}
});
temp.pipe(this.scrollview);
surfaces.push(temp);
}
this.scrollview.sequenceFrom(surfaces);
this.bodyContent = new Surface({
size: [undefined, undefined],
properties: {
backgroundColor: '#f4f4f4'
}
});
this.layout.content.add(this.bodyContent);
}
function _setListeners() {
this.hamburgerSurface.on('click', function() {
this._eventOutput.emit('menuToggle');
}.bind(this));
//this.bodyContent.pipe(this._eventOutput);
this.scrollview.pipe(this._eventOutput);
}
module.exports = PageView;
});
You need to add this.scrollview to your layout.content element on the page. Put this in place of this.bodyContent. layout.content is the node for the content of the page.
//this.layout.content.add(this.bodyContent);
this.layout.content.add(this.scrollview);
Related
In my app I have a google map and I want to add many marker on it and so I load the data via ajax (I'm in Django). I have the probem with infocontent and the 'click' event on the marker load via ajax: When I do 'click' on the marker nothing happened. This is my code:
function initialize() {
var latlng = new google.maps.LatLng({{lat}}, {{long}});
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("mapCanvas"), myOptions);
var contentString = '<div id="content">{{name}}<br><span style="font-size:10px;">{{road}}</span><br><span style="font-size:10px;">{{city}} ({{prov}})</span></div>';
var infowindow_strutt = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: latlng,
map: map,
title: '{{name}}'
});
google.maps.event.addListener(marker, 'click', function() {
infowindow_strutt.open(map,marker);
});
var markers = [];
var markers_strutt = [];
var markers_concor = [];
var icon_strutt = {
url: 'http://icons.iconarchive.com/icons/graphicloads/colorful-long-shadow/24/Home-icon.png'
};
var icon_concor = {
url: 'http://icons.iconarchive.com/icons/graphicloads/100-flat/24/home-icon.png'
};
var marker_concor
var marker_strutt
map.addListener('bounds_changed', function() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
$.ajax({
url: '/api/get_marker/',
cache: false,
data: {
'fromlat': southWest.lat(),
'tolat': northEast.lat(),
'fromlng': southWest.lng(),
'tolng': northEast.lng()
},
dataType: 'json',
type: 'GET',
async: false,
success: function (data) {
if (data) {
$.each(data, function (i, item) {
if (item.type = 1) {
var marker_concor = new google.maps.Marker({
position: new google.maps.LatLng(item.lat, item.lng),
icon: icon_concor,
map: map,
draggable: false
});
} else if (item.type = 2) {
var marker_strutt = new google.maps.Marker({
position: new google.maps.LatLng(item.lat, item.lng),
icon: icon_strutt,
map: map,
draggable: false
});
//Create an infoWindow
var infowindow_strutt = new google.maps.InfoWindow();
//set the content of infoWindow (the name)
infowindow_strutt.setContent(item.name);
//add click listner to marker which will open infoWindow
map.addListener(marker_strutt, 'click', function() {
infowindow_strutt.open(marker_strutt); // click on marker opens info window
});
}
markers_concor.push(marker_concor);
markers_strutt.push(marker_strutt);
if (marker_strutt) {
marker_strutt.setMap(map);
}
if (marker_concor) {
marker_concor.setMap(map);
}
});
}
}
});
});
}
jQuery(document).ready(function(e) {
initialize();
});
Where is the issue? Thanks a lot
EDIT: View code
def view_get_marker(request):
id = 24
list_id = []
list_marker = []
list_id.append(id)
# type 1 data
A_list = tab_A.objects.filter(id_struttura=id).filter(lat__gt=request.GET.get('fromlat'), lat__lt=request.GET.get('tolat')).filter(lng__gt=request.GET.get('fromlng'), lng__lt=request.GET.get('tolng'))
for a in A_list:
list_marker.append([a.lat, a.lng, a.name, a.road, a.city, a.id, 1])
list_id.append(a.id)
# type 2 data
B_list = list(tab_B.objects.all().values_list('lat','lng','name','road','city','id').exclude(lng__isnull=True).exclude(id__in=lista_id).filter(lat__gt=request.GET.get('fromlat'), lat__lt=request.GET.get('tolat')).filter(lng__gt=request.GET.get('fromlng'), lng__lt=request.GET.get('tolng')))
for lat, lng, name, road, city, id in B_list:
list_marker.append([lat, lng, name, road, city, id, 2])
if request.is_ajax():
results = []
for row in list_marker:
h_json = {}
h_json['lat'] = row[0]
h_json['lng'] = row[1]
h_json['name'] = unicode(row[2])
h_json['road'] = unicode(row[3])
h_json['city'] = unicode(row[4])
h_json['id'] = row[5]
h_json['type'] = row[6]
results.append(h_json)
data = json.dumps(results)
else:
data = 'fail'
mimetype = 'application/json'
return HttpResponse(data, mimetype)
EDIT 2:
I found the solution. The problem was in the event 'click' declaration. The right way is this:
google.maps.event.addListener(marker_strutt, 'click', (function(marker_strutt, i) {
return function() {
infowindow.setContent('my content');
infowindow.open(map, marker_strutt);
}
})(marker_strutt, i));
In this way I have the popoup!
My goal is to mimic Z-translation in perspective mode by using multiple modifiers. I can not use just z-translation of a surface because a text of translated surface became blurred (at least at Chrome but also on another browsers). The idea of using concurrent modifiers is explained in my blog: https://ozinchenko.wordpress.com/2015/02/04/how-to-avoid-blurring-of-the-text-in-famo-us-during-transition-in-z-direction/
As a result I want to have smooth translation in Z direction surface with a smooth text scaling.
the codepen code is here:
http://codepen.io/Qvatra/pen/yyPMyK?editors=001
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var ImageSurface = famous.surfaces.ImageSurface;
var ContainerSurface = famous.surfaces.ContainerSurface;
var View = famous.core.View;
var Entity = famous.core.Entity;
var Modifier = famous.core.Modifier;
var StateModifier = famous.modifiers.StateModifier;
var Transform = famous.core.Transform;
var Transitionable = famous.transitions.Transitionable;
var TransitionableTransform = famous.transitions.TransitionableTransform;
var Easing = famous.transitions.Easing;
var Scrollview = famous.views.Scrollview;
var perspective = 1000;
var fontValue = 100; //initially font-size is 100%
var surfSize = [100,100];
var mainContext = Engine.createContext();
mainContext.setPerspective(perspective);
var transitionable = new Transitionable(0);
var mySurface = new Surface({
size: surfSize,
properties: {
backgroundColor: 'red',
textAlign: 'center',
color: 'white',
fontSize: fontValue + '%',
lineHeight: surfSize[1] + 'px'
},
content: 'Click Me'
});
var transitionModifier = new StateModifier({
origin: [.5, .5],
align: [.5, .5],
transform: Transform.translate(0,0,0.01)
});
mainContext.add(transitionModifier).add(mySurface);
function translateZ(dist, transition) {
transitionable.reset(0);
transitionable.set(dist, transition);
function prerender() {
var currentDist = transitionable.get();
//perspective formula: dist = perspective(1 - 1/scaleFactor)
var currentScale = 1 / (1 - currentDist / perspective);
var currentSize = [surfSize[0] * currentScale, surfSize[1] * currentScale];
var currentFontValue = fontValue * currentScale;
//f.e: bring closer => make projection scaleFactor times bigger
var transitionTransform = Transform.translate(0,0, currentDist);
//scaling back to avoid text blurring
var scaleTransform = Transform.scale(1/currentScale, 1/currentScale, 1);
transitionModifier.setTransform(Transform.multiply(transitionTransform, scaleTransform));
mySurface.setSize(currentSize); //resize to get correct projection size
mySurface.setOptions({
properties:{
fontSize: currentFontValue + '%', //resizing font;
lineHeight: currentSize[1] + 'px' //align text;
}
})
if (currentDist === dist) {
Engine.removeListener('prerender', prerender);
}
}
Engine.on('prerender', prerender);
}
Engine.on('click', function() {
translateZ(750, {curve: 'easeOutBounce', duration: 2000});
});
Why do I have the shaking of the image? How to avoid that?
The StateModifier is changing the size of your surface while you are setting the size of the surface. Because you are handling the size of the surface, there is no need to change (set) the StateModifier to scale. I am not sure your method will hold up in all cases, but this answers your question.
Here is a new translateZ function:
function translateZ(dist, transition) {
transitionable.reset(0);
transitionable.set(dist, transition);
function prerender() {
var currentDist = transitionable.get();
//perspective formula: dist = perspective(1 - 1/scaleFactor)
var currentScale = 1 / (1 - currentDist / perspective);
var currentSize = [surfSize[0] * currentScale, surfSize[1] * currentScale];
var currentFontValue = fontValue * currentScale;
mySurface.setSize(currentSize); //resize to get correct projection size
mySurface.setOptions({
properties:{
fontSize: currentFontValue + '%', //resizing font;
lineHeight: currentSize[1] + 'px' //align text;
}
})
if (currentDist === dist) {
Engine.removeListener('prerender', prerender);
}
console.log('trans')
}
Engine.on('prerender', prerender);
}
Another famo.us beginner question...
My question relates to this question and johntraver's excellent answer (provided below). I've been playing around with this for a bit, and I can't figure out how to access the other surfaces in the Scrollview when one is clicked.
For example, I'd like to re-size both 'Surface 2' AND 'Surface 3' when 'Surface 2' is clicked.
I've looked at the guides, examples, etc., and my confusion is with the RenderNode. I'm not entirely clear on the purpose it serves.
Thanks in advance for the help.
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var RenderNode = require("famous/core/RenderNode");
var Modifier = require("famous/core/Modifier");
var Scrollview = require("famous/views/Scrollview");
var Transitionable = require("famous/transitions/Transitionable");
var SnapTransition = require("famous/transitions/SnapTransition");
Transitionable.registerMethod('snap', SnapTransition);
var snap = { method: 'snap', period: 600, dampingRatio: 0.6 }
var mainContext = Engine.createContext();
var scrollview = new Scrollview();
var surfaces = [];
scrollview.sequenceFrom(surfaces);
for (var i = 0; i < 20; i++) {
var surface = new Surface({
content: "Surface: " + (i + 1),
size: [undefined, undefined],
properties: {
backgroundColor: "hsl(" + (i * 360 / 40) + ", 100%, 50%)",
lineHeight: "200px",
textAlign: "center"
}
});
surface.open = false;
surface.state = new Modifier();
surface.trans = new Transitionable(200);
surface.state.sizeFrom(function(){
return [undefined, this.trans.get()];
}.bind(surface));
surface.node = new RenderNode();
surface.node.add(surface.state).add(surface);
surface.pipe(scrollview);
surface.on('click',function(e){
if (this.open) {
this.trans.halt();
this.trans.set(200,snap);
} else {
this.trans.halt();
this.trans.set(400,snap);
}
this.open = !this.open;
}.bind(surface));
surfaces.push(surface.node);
}
mainContext.add(scrollview);
Think of the RenderNode as the view of the items being added to the scrollview. In the example, #johntraver is storing references to his node and surface modifiers onto the surface. This may be confusing you a bit. Although it is fine, we will need to use node (item) as our reference point. Also, the render node item purpose is to allow us to have a node branch where we have multiple items.
I changed the example to make it a little more accessible to be able to get to the surfaces stored in the items (views). I am now calling the surfaces collection views to help us understand what we are passing to the scrollview for rendering. Instead a RenderNode (node) is holding the reference to our surface as properties, so we can later access the surfaces.
Here is a running example on jsBin.
Building our view
Note: I moved the functions out of the loop, for easier reading.
for (var i = 0; i < 20; i++) {
var node = new RenderNode();
node.surface = new Surface({
content: "Surface: " + (i + 1),
size: [undefined, undefined],
properties: {
backgroundColor: "hsl(" + (i * 360 / 40) + ", 100%, 50%)",
lineHeight: "200px",
textAlign: "center"
}
});
node.surface.open = false;
node.surface.state = new Modifier();
node.surface.trans = new Transitionable(200);
node.surface.state.sizeFrom(_surfaceSize.bind(node.surface));
// Add the modifier and the surface to our view
node.add(node.surface.state).add(node.surface);
node.surface.pipe(scrollview);
node.surface.on('click', _resize.bind(node.surface, i, views));
views.push(node);
}
Function to access our multiple views and resize
function _resize(index, views, event){
console.log(index, views, event);
next = index+1 < views.length ? views[index+1].surface : views[0].surface;
if (this.open) {
this.trans.halt();
this.trans.set(200, snap);
next.trans.halt();
next.trans.set(200, snap);
} else {
this.trans.halt();
this.trans.set(400, snap);
next.trans.halt();
next.trans.set(400, snap);
}
this.open = !this.open;
next.open = this.open;
}
The full code
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var RenderNode = require("famous/core/RenderNode");
var Modifier = require("famous/core/Modifier");
var Scrollview = require("famous/views/Scrollview");
var Transitionable = require("famous/transitions/Transitionable");
var SnapTransition = require("famous/transitions/SnapTransition");
Transitionable.registerMethod('snap', SnapTransition);
var snap = { method: 'snap', period: 600, dampingRatio: 0.6 };
var mainContext = Engine.createContext();
var scrollview = new Scrollview();
var views = [];
scrollview.sequenceFrom(views);
function _resize(index, views, event){
console.log(index, views, event);
next = index+1 < views.length ? views[index+1].surface : views[0].surface;
if (this.open) {
this.trans.halt();
this.trans.set(200, snap);
next.trans.halt();
next.trans.set(200, snap);
} else {
this.trans.halt();
this.trans.set(400, snap);
next.trans.halt();
next.trans.set(400, snap);
}
this.open = !this.open;
next.open = this.open;
}
function _surfaceSize(){
return [undefined, this.trans.get()];
}
for (var i = 0; i < 20; i++) {
var node = new RenderNode();
node.surface = new Surface({
content: "Surface: " + (i + 1),
size: [undefined, undefined],
properties: {
backgroundColor: "hsl(" + (i * 360 / 40) + ", 100%, 50%)",
lineHeight: "200px",
textAlign: "center"
}
});
node.surface.open = false;
node.surface.state = new Modifier();
node.surface.trans = new Transitionable(200);
node.surface.state.sizeFrom(_surfaceSize.bind(node.surface));
node.add(node.surface.state).add(node.surface);
node.surface.pipe(scrollview);
node.surface.on('click', _resize.bind(node.surface, i, views));
views.push(node);
}
mainContext.add(scrollview);
If I have a surface that hase conent that includes an input. The input doesn't seem to gain focus on click.
Here is how I include my surface.
var ConfigureView = function() {
this.initialize.apply(this, arguments);
};
_.extend(ConfigureView.prototype, {
template: templates['config'],
initialize: function( options ) {
var position = new Transitionable([0, 0]);]
var sync = new GenericSync({
"mouse" : {},
"touch" : {}
});
this.surface = new Surface({
size : [200, 200],
properties : {background : 'red'},
content: this.template()
});
// now surface's events are piped to `MouseSync`, `TouchSync` and `ScrollSync`
this.surface.pipe(sync);
sync.on('update', function(data){
var currentPosition = position.get();
position.set([
currentPosition[0] + data.delta[0],
currentPosition[1] + data.delta[1]
]);
});
this.positionModifier = new Modifier({
transform : function(){
var currentPosition = position.get();
return Transform.translate(currentPosition[0], currentPosition[1], 0);
}
});
var centerModifier = new Modifier({origin : [0.5, 0.5]});
centerModifier.setTransform(Transform.translate(0,0));
},
addTo: function(context) {
context = Engine.createContext()
context.add(this.positionModifier).add(this.surface);
}
});
module.exports = ConfigureView;
What is necessary to make forms act normally with famo.us?
Or do i just need to have an inner surface that has a different listener?
This is templates['config']:
templates["config"] = Handlebars.template({"compiler":[5,">= 2.0.0"],"main":function(depth0,helpers,partials,data) {
return "<input type=\"text\" id=\"fontSize\" >";
},"useData":true});
What displays is an input I just can't seem to focus on it.
UPDATE
The reason I think I couldn't focus was because I wasn't using an inputSurface and the surface event was being pipe away. Using a scrollView I was able to make it work.
var ConfigureView = function() {
this.initialize.apply(this, arguments);
};
_.extend(ConfigureView.prototype, {
template: templates['config'],
initialize: function( options ) {
this.app = options.app;
var position = new Transitionable([0, 0, 1000]);
this.scrollView = new ScrollView();
var surfaces = [];
this.scrollView.sequenceFrom(surfaces);
// create a sync from the registered SYNC_IDs
// here we define default options for `mouse` and `touch` while
// scrolling sensitivity is scaled down
var sync = new GenericSync({
"mouse" : {},
"touch" : {}
});
this.surface = new Surface({
size : [200, 200],
properties : {background : 'red'},
content: this.template()
});
surfaces.push(this.surface);
this.offsetMod = new Modifier({ origin: [0.2,0,2]});
this.inner = new Surface({
size : [100, 100],
properties : {background : 'gray'},
content: this.template()
});
surfaces.push(this.inner);
// now surface's events are piped to `MouseSync`, `TouchSync` and `ScrollSync`
this.surface.pipe(sync);
this.inputsFontSize = new InputSurface({
classes: ['login-form'],
content: '',
size: [300, 40],
placeholder:'email',
properties: {
autofocus:'autofocus',
maxLength:'5',
textAlign: 'left'
}
});
sync.on('update', function(data){
var currentPosition = position.get();
position.set([
currentPosition[0] + data.delta[0],
currentPosition[1] + data.delta[1]
]);
});
this.positionModifier = new Modifier({
transform : function(){
var currentPosition = position.get();
return Transform.translate(currentPosition[0], currentPosition[1], 0);
}
});
var centerModifier = new Modifier({origin : [0.5, 0.5]});
centerModifier.setTransform(Transform.translate(0,0));//, y, z))
},
addTo: function(context) {
context = Engine.createContext();
context.add(this.positionModifier).add(this.scrollView);
}
});
module.exports = ConfigureView;
What's the best way with Famous to implement these well known mobile app design patterns?
!) "hamburger" and side-menu like this jasny example ?
2 )Table-View, transitioning to full-screen details page, a little like:
http://goratchet.com/examples/app-movies/
Thanks!
You should be aware that the famo.us university timbre menu lesson is now available. Here is a version I did long before that came out. It is more of the one file here are the critical issues implementations than the 27 class version. Following this I did eventually produce an abstraction of the menu into a generalized tool. There is actually very little difference between the menu below and a standard (one level deep) menu with the exception of what transitions you use. Here is a drag-to-uncover menu. You could of course trigger the open and/or close with a click as well... you can also see the code and play it live at codefamo.us.
/*globals define*/
define(function(require, exports, module) {
'use strict';
// import dependencies
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var Easing = require('famous/transitions/Easing');
var ContainerSurface = require('famous/surfaces/ContainerSurface');
var EventHandler = require('famous/core/EventHandler');
var MouseSync = require('famous/inputs/MouseSync');
var TouchSync = require('famous/inputs/TouchSync');
var Draggable = require('famous/modifiers/Draggable');
var mainContext = Engine.createContext();
// Content Page...
var coverState = true;
var coverPos = 0;
//var coverMod = new StateModifier();
var coverDrag = new Draggable({
projection: 'x'
});
var coverSurface = new Surface({
size:[undefined,undefined],
content:'click to open',
properties:{
color:'white',
backgroundColor:'#44f',
zIndex:'3'
}
});
//mainContext.add(coverMod).add(coverDrag).add(coverSurface);
mainContext.add(coverDrag).add(coverSurface);
coverDrag.activate();
function coverReset() {
coverDrag.setPosition([0,0],
{ duration : 100, curve: 'easeInOut' },
function() {
coverSurface.setContent('drag to open');
coverPos = 0;
}
);
coverState = true;
}
function coverDrawOut() {
coverDrag.setPosition([200,0],
{ duration : 600, curve: 'easeInOut' },
function() {
coverSurface.setContent('drag to close');
coverPos = 200;
}
);
coverState=false;
}
coverDrag.on('update',function(data) {
//console.log(data);
if(data.position[0]>60) {
menuFadeIn();
}
});
coverDrag.on('end',function(data) {
if(data.position[0]<100) {
coverReset();
menuFadeOut();
}else {
coverDrawOut();
menuFadeIn();
}
});
coverSurface.pipe(coverDrag);
// Menu Items...
var todaysSpecials = ['pizza','hamburger','french fries','ice cream'];
var itemSurfs = [];
var itemMod1 = [];
var itemMod2 = [];
// Create menu item surfaces, modifiers, etc.
for (var i=0;i<todaysSpecials.length;i++) {
itemSurfs[i] = new Surface({
size: [150, 30],
content: '<span class="entypo">☰</span>'+todaysSpecials[i],
properties: {
color: 'white',
textAlign: 'center',
backgroundColor: '#FA5C4F',
zIndex:'1'
}
});
itemSurfs[i].menuData = {
id:i,
text: todaysSpecials[i]
};
//console.log(itemSurfs[i]);
itemMod1[i] = new StateModifier();
itemMod2[i] = new StateModifier();
mainContext.add(itemMod1[i]).add(itemMod2[i]).add(itemSurfs[i]);
itemSurfs[i].on('click',function(mouseEventArgs){
alert('Buy some really good '+mouseEventArgs.origin.menuData.text);
});
};
var menuState=true;
// make menu go away
function menuFadeOut() {
if(menuState) {
for (var i=0;i<todaysSpecials.length;i++) {
itemMod1[i].setTransform(Transform.translate(-150, 200+i*40, 0));
itemMod2[i].setTransform(Transform.rotateZ(-Math.PI/5.5));
}
menuState=false;
}
}
// bring menu in
function menuFadeIn() {
if(!menuState) {
for (var i=0;i<todaysSpecials.length;i++) {
itemMod1[i].setTransform(Transform.translate(0,100+i*40, -1),{ duration : 300+i*200, curve: 'easeInOut' });
itemMod2[i].setTransform(Transform.rotateZ(-Math.PI/5.5));
}
menuState=true;
}
}
// app initial conditions...
coverReset();
menuFadeOut();
});