bad quality of a surface content after scaling or as a result of Z-translate with perspective option - famo.us

var mainContext = Engine.createContext();
mainContext.setPerspective(500);
var surface = new Surface({
content: 'im a content',
size: [200, 200]
});
var modifier = new StateModifier();
mainContext.add(modifier).add(surface);
in onClick event the following code results in very bad quality of displayed content 'im a content':
1) modifier.setTransform(Transform.translate(0, 0, 300));
or
2) modifier.setTransform(Transform.scale(3, 3, 1));
What Im doing wrong here?
How to force famo.us to rerender content after transformations for better quality?

This is not so much an issue of Famo.us as it is the browser. See the issue here.
Windows Chrome browser?
I tested it using this code. Example jsBin
Chrome (39.0.2171.95) Not Working
Firefox (31) Working
IE (11.0.15) Working
var mainContext = Engine.createContext();
mainContext.setPerspective(1000);
var surface = new Surface({
content: 'Famous Application',
size: [200, 200],
transform: Transform.scale(1, 1, 1),
properties: {
fontSize: '2em',
backgroundColor: 'rgba(0, 0, 0, 0.4)'
}
});
var modifier = new Modifier({
origin: [0, 0],
align: [0, 0]
});
mainContext.add(modifier).add(surface);
surface.on('click', function() {
console.log('clicked');
if (!surface.clicked) {
//modifier.setTransform(Transform.translate(0, 0, 300));
modifier.setTransform(Transform.scale(3, 3, 1), {duration: 300}, function(){surface.setContent('');surface.setContent('<div>Scaled Now!</div>');});
}
else {
modifier.setTransform(Transform.scale(1, 1, 1), {duration: 300}, function(){surface.setContent('');surface.setContent('Famous Application');});
}
surface.clicked = !surface.clicked;
});

Related

Legend and axis tooltip comes with black box with google chart (Firefox

I am currently working on Google Charts with below Version.
google.charts.load('upcoming', {packages: ['corechart']);
When i enter a mouse on axis and legend tooltip comes with black box as per attached image.
I also tried "Current" and "42" version but still getting a same issue as in attached image. I am facing this issue with Firefox.
Google Line Chart- Tooltip with balck box in Firefox
Is it a bug in Google Chart API or anything else?
tooltip seems to work fine here
any code / css / chart options you can share?
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var dataTable = new google.visualization.DataTable({
cols: [
{id: 'x', label: 'Date', type: 'date'},
{id: 'y', label: 'Fn', type: 'number'},
{id: 'z', label: 'Shade', type: 'number'}
]
});
var formatDate = new google.visualization.DateFormat({
pattern: 'MMM-dd-yyyy'
});
var oneDay = (1000 * 60 * 60 * 24);
var startDate = new Date(2016, 10, 27);
var endDate = new Date();
var ticksAxisH = [];
var dateRanges = [
{start: new Date(2017, 0, 1), end: new Date(2017, 0, 20)},
{start: new Date(2017, 1, 5), end: new Date(2017, 1, 10)}
];
var maxShade = 200;
for (var i = startDate.getTime(); i < endDate.getTime(); i = i + oneDay) {
// x = date
var rowDate = new Date(i);
var xValue = {
v: rowDate,
f: formatDate.formatValue(rowDate)
};
// y = 2x + 8
var yValue = (2 * ((i - startDate.getTime()) / oneDay) + 8);
// z = null or max shade
var zValue = null;
dateRanges.forEach(function (range) {
if ((rowDate.getTime() >= range.start.getTime()) &&
(rowDate.getTime() <= range.end.getTime())) {
zValue = maxShade;
}
});
// add data row
dataTable.addRow([
xValue,
yValue,
zValue
]);
// add tick every 7 days
if (((i - startDate.getTime()) % 7) === 0) {
ticksAxisH.push(xValue);
}
}
var container = document.getElementById('chart_div');
var chart = new google.visualization.ChartWrapper({
chartType: 'ComboChart',
dataTable: dataTable,
options: {
chartArea: {
bottom: 64,
top: 48
},
hAxis: {
slantedText: true,
ticks: ticksAxisH
},
legend: {
position: 'top'
},
lineWidth: 4,
series: {
// line
0: {
color: '#00acc1'
},
// area
1: {
areaOpacity: 0.6,
color: '#ffe0b2',
type: 'area',
visibleInLegend: false
},
},
seriesType: 'line'
}
});
chart.draw(container);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

famo.us - RenderController and draggable surfaces

I have two surfaces. One is draggable and one is 'full screen' (size: [undefined, undefined]). I'd like to drag the first surface (yellow in my example) right and have the second (green)surface appear. When I click on the green surface, I'd like show the first surface again back in the original starting point (center of screen).
I'd also like the green surface to be non-draggable.
I'm a famo.us novice, and any help is GREATLY appreciated!
fiddle here: http://jsfiddle.net/cjs123456/vfzy4j51/
// the position state
var position = [0, 0];
// create a Sync to listen to mouse events
var sync = new MouseSync();
var renderController = new RenderController();
var mySurface = new Surface({
size: [350, 200],
content: 'drag me right more than 100px to see other surface',
properties: {
backgroundColor: "hsl(" + (5 * 360 / 40) + ", 100%, 50%)",
lineHeight: '200px',
textAlign: 'center',
cursor: 'pointer'
}
});
// Surface provides events that the sync listens to
mySurface.pipe(sync);
// Syncs have `start`, `update` and `end` events. On `update` we increment the position state of the surface based
// on the change in x- and y- displacements
sync.on('update', function(data){
position[0] += data.delta[0];
position[1] += data.delta[1];
console.log(data.position[0]);
if (data.position[0] > 100) {
console.log("FULL");
renderController.show(fullSurface);
}
});
// this modifier reads from the position state to create a translation Transform that is applied to the surface
var positionModifier = new Modifier({
transform : function(){
return Transform.translate(position[0], position[1], 0);
}
});
// a modifier that centers the surface
var centerModifier = new Modifier({
origin : [0.5, 0.5],
align: [0.5, 0.5]
});
var fullSurface = new Surface({
size: [undefined, undefined],
content: 'Click me to show other surface',
properties: {
backgroundColor: "hsl(" + (9 * 360 / 40) + ", 100%, 50%)",
lineHeight: '400px',
textAlign: 'center'
}
});
fullSurface.on("click", function() {
renderController.show(mySurface);
});
renderController.show(mySurface);
var mainContext = Engine.createContext();
var node = mainContext.add(centerModifier).add(positionModifier);
node.add(renderController);
});
There are more than one way to solve this issue.
Control the dragging of the render controller
Create separate render controller and control views
Because your use case here is simple enough, I will show the creating of a separate render controller
Here is the jsFiddle Example of the Code
Create a background render controller
var renderController = new RenderController();
var backRenderController = new RenderController();
Change the node to be the center modifier. Add our draggable to the node. Add the background controller to the node.
var node = mainContext.add(centerModifier)
node.add(positionModifier).add(renderController);
node.add(backRenderController);
Control the draggable render contoller view (Line 42)
renderController.hide();
backRenderController.show(fullSurface);
Clicking on the background will reset the position of the draggable back to the origin, hide the background and show the draggable again.
// Set draggable position back to the origin
position = [0, 0];
// Hide the back render element
backRenderController.hide();
// Show the draggable
renderController.show(mySurface);
Full code:
// the position state
var position = [0, 0];
// create a Sync to listen to mouse events
var sync = new MouseSync();
var renderController = new RenderController();
var backRenderController = new RenderController();
var mySurface = new Surface({
size: [350, 200],
content: 'drag me right more than 100px to see other surface',
properties: {
backgroundColor: "hsl(" + (5 * 360 / 40) + ", 100%, 50%)",
lineHeight: '200px',
textAlign: 'center',
cursor: 'pointer'
}
});
// Surface provides events that the sync listens to
mySurface.pipe(sync);
// Syncs have `start`, `update` and `end` events. On `update` we increment the position state of the surface based
// on the change in x- and y- displacements
sync.on('update', function (data) {
position[0] += data.delta[0];
position[1] += data.delta[1];
console.log(data.position[0]);
if (data.position[0] > 100) {
console.log("FULL");
renderController.hide();
backRenderController.show(fullSurface);
}
//else {
// mySurface.setPosition([0,0,0], {
// curve: Easing.outBack,
// duration: 300
// });
//}
});
// this modifier reads from the position state to create a translation Transform that is applied to the surface
var positionModifier = new Modifier({
transform: function () {
return Transform.translate(position[0], position[1], 0);
}
});
// a modifier that centers the surface
var centerModifier = new Modifier({
origin: [0.5, 0.5],
align: [0.5, 0.5]
});
var fullSurface = new Surface({
size: [undefined, undefined],
content: 'Click me to show other surface',
properties: {
backgroundColor: "hsl(" + (9 * 360 / 40) + ", 100%, 50%)",
lineHeight: '400px',
textAlign: 'center'
}
});
fullSurface.on("click", function () {
// Set draggable position back to the origin
position = [0, 0];
// Hide the back render element
backRenderController.hide();
// Show the draggable
renderController.show(mySurface);
});
//var node = mainContext.add(myModifier);
//node.add(draggable).add(surface);
renderController.show(mySurface);
var mainContext = Engine.createContext();
//mainContext.add(myModifier).add(draggable).add(renderController);
var node = mainContext.add(centerModifier)
node.add(positionModifier).add(renderController);
node.add(backRenderController);

Do famo.us layouts like SequentialLayout participate in the render tree?

When using a SequentialLayout in trying to apply StateModifiers to Surface objects that had been added to a layout, it looks like some unexpected behavior happens:
When applying transformations via setTransform on a StateModifier, I expect to see the transformation applied from the origin of the Surface in question.
Instead, the transform is applied from an origin of 0,0 in relation to the parent SequentialLayout
Given the code below, the above behavior seems to make no logical sense (for context, I am working on a sorting algorithms demo, using famo.us):
/* 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 StateModifier = require('famous/modifiers/StateModifier');
var SequentialLayout = require('famous/views/SequentialLayout');
// create the main context
var mainContext = Engine.createContext();
// your app here
var surfaces = [];
// Sorter
var Sort = require('sort');
var arr = [100,25,20,15,30,-20,-10,10,0];
var min = Math.min.apply(null, arr);
var base_dims = [ 50, 50 ];
arr.forEach(function(el) {
surfaces.push(new Surface({
content: el,
size: base_dims.map(function(d) { return d + (el - min); }),
properties: {
backgroundColor: 'rgb(240, 238, 233)',
textAlign: 'center',
padding: '5px',
border: '2px solid rgb(210, 208, 203)',
marginTop: '50px',
marginLeft: '50px'
}
}));
});
var sequentialLayout = new SequentialLayout({
direction: 0,
itemSpacing:20
});
sequentialLayout.sequenceFrom(surfaces);
mainContext.add(sequentialLayout);
var swap_modifiers = [
new StateModifier({}), new StateModifier({})
];
Sort.bubble_sort_iterative(arr, function(first_swap_index, second_swap_index) {
swap_modifiers[0].setTransform(
Transform.translate(300, 0, 0),
{ duration : 750, curve: 'linear' }
);
swap_modifiers[1].setTransform(
Transform.translate(300, 0, 0),
{ duration : 750, curve: 'linear' }
);
mainContext.add(swap_modifiers[0]).add(surfaces[first_swap_index]);
mainContext.add(swap_modifiers[1]).add(surfaces[second_swap_index]);
});
});
A surface has no origin, a (state-)modifier has an origin. Since you don't provide any origin vaue, the default value is set up, which is [0, 0]. See more:
http://famo.us/university/lessons/#/famous-101/positioning/8
Think of your SequentialLayout as a Render Node in your tree. Adding surfaces to SequentialLayout is in essence adding individual nodes to that tree branch. SequentialLayout happens to be adding each item at the same level in the tree.
Sort.bubble_sort_iterative(... changes the location of the surfaces by adding them to the mainContext of your application. This is the same level as the sequentialLayout and makes their origin the same origin as the sequentialLayout. Not what you wanted!
Remember: Adding a modifier to a context will make that context the parent node.
Without knowing the specifics of the above code, we know that we can add a View rather than surfaces to the sequentialLayout and could transition the View's modifiers within each of those items without changing their location in the render tree.
A simple code example of views in the sequential layout:
arr.forEach(function(el) {
var surfSize = base_dims.map(function(d) { return d + (el - min); });
console.log(size);
var view = new View();
view.mod = new StateModifier({ size: surfSize });
view.surface = new Surface({
content: el,
size: [undefined, undefined],
properties: {
backgroundColor: 'rgb(240, 238, 233)',
textAlign: 'center',
padding: '5px',
border: '2px solid rgb(210, 208, 203)',
marginTop: '50px',
marginLeft: '50px'
}
});
view.add(view.mod).add(view.surface);
surfaces.push(view);
});
Trying to swap out the views from one to the other will give you some unexpected results. It would be better to just swap out the options and content values.

Famo.us scrollview positioning

In my context I have a scroll view, and I'm trying to position the child elements within the view using origin/align properties in a state modifier. However for some reason, when I scroll to the bottom, the last surface isn't displayed correctly.
I can see this is because I'm using origin/align but I'm not sure on the correct way to position child elements within a scroll view? If someone could point me in the right direction that would be great.
Thanks
Code:
main.js
// Create the main context
var mainContext = Engine.createContext();
// Create scroll view
var scrollView = new Scrollview();
var surfaces = [];
scrollView.sequenceFrom(surfaces);
// Create logo
var logoNode = new RenderNode();
var logo = new ImageSurface({
size: [150, 112],
content: 'img/logo.png',
classes: ['logo']
});
// Center logo within context, center and set opacity
var modifier = new StateModifier({
align: [0.5, 0.05],
origin: [0.5, 0.05],
});
logoNode.add(modifier).add(logo);
logo.pipe(scrollView);
surfaces.push(logoNode);
var tribesLength = Object.keys(tribes).length;
for (var t = 0; t < tribesLength; t++) {
var tribe = new TribesView({tribes: tribes, tribe: t});
tribe.pipe(scrollView);
surfaces.push(tribe);
}
mainContext.add(scrollView);
TribesView.js
function TribesView() {
View.apply(this, arguments);
_displayTribe.call(this);
}
TribesView.prototype = Object.create(View.prototype);
TribesView.prototype.constructor = TribesView;
TribesView.DEFAULT_OPTIONS = {
tribes: {},
tribe: 0,
};
function _displayTribe() {
var tribes = this.options.tribes;
var tribe = this.options.tribe;
var node = new RenderNode();
var surface = new Surface({
size: [, 100],
content: tribes[tribe]['name'],
properties: {
background: tribes[tribe]['bg'],
color: 'blue'
}
});
var modifier = new StateModifier({
origin: [0, 0.1],
align: [0, 0.1]
});
node.add(modifier).add(surface);
surface.pipe(this._eventOutput);
this.add(node);
}
module.exports = TribesView;
The problem comes as you suspected, from the use of..
var modifier = new StateModifier({
origin: [0, 0.1],
align: [0, 0.1]
});
in the _displayTribe function. You have to remember that TribeView although labeled a view is nothing representative of something visual on screen. That means when you add this modifier to a surface inside a view, view thinks it is one place, which will be laid out in scrollview, and the modifier will put it in another place (in your case too low on screen).
It is difficult to give you a clear example, because I do not have the data or images or anything to make this look halfway good. If you want to use modifiers within your TribeViews, take a look at chain modifier. I have found it helpful for creating a sort of container surface without using a containerSurface.
Here is what I did to _displayTribe to give the content text an offset relative to the view..
function _displayTribe() {
var tribes = this.options.tribes;
var tribe = this.options.tribe;
var surface = new Surface({
size: [undefined, 100],
properties: {
color: 'blue',
border:'1px solid black'
}
});
this.add(surface)
var text = new Surface({
size:[undefined,true],
content: "Helloo",
})
chain = new ModifierChain()
var containerModifier = new StateModifier({
size: [undefined, 100],
});
var modifier = new StateModifier({
origin: [0, 0.1],
align: [0, 0.1]
});
chain.addModifier(modifier)
chain.addModifier(containerModifier)
this.add(chain).add(text);
surface.pipe(this._eventOutput);
}
I removed anything 'asset' related since it was not available to me. The first surface I added to the view completely unmodified. This allows us to see where scrollview is placing our view. For the text surface, I am using true sizing, and creating a ModifierChain to simulate the container as I previously mentioned. You do this by defining two modifiers, one for the size of the container, and the other for positioning in the container, then chain them together.
Lots of information, Hope this helps!

famo.us: can I animate the header/footer heights of a header footer layout?

I want to have my header and footer almost take up the entire screen (there will just be a thin line left in the middle which will contain a textbox. If the user enters the right password, I want the textbox to disappear and the header and footer to gradually get shorter (making more room for content to appear in the center of the screen).
Is it possible to apply a transition to the height of the header and footer on a HeaderFooterLayout?
How do I show a typical password box where the characters all show as *'s?
Like many animations that are not supported by default, you can add a transition by using the Transitionable class.. Here is an example that expands the header when you click it..
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var HeaderFooterLayout = require("famous/views/HeaderFooterLayout");
var Transitionable = require("famous/transitions/Transitionable");
var Easing = require("famous/transitions/Easing");
var mainContext = Engine.createContext();
var layout = new HeaderFooterLayout({
headerSize: 100,
footerSize: 50
});
var header = new Surface({
size: [undefined, undefined],
content: "Header",
classes: ["red-bg"],
properties: {
lineHeight: "100px",
textAlign: "center"
}
})
var open = false;
header.on("click",function(){
var transition = {duration: 400, curve: Easing.inOutQuad };
var start = open ? 200 : 100 ;
var end = open ? 100 : 200 ;
open = !open;
var transitionable = new Transitionable(start);
var prerender = function(){ layout.setOptions({ headerSize: transitionable.get()} ) };
var complete = function(){ Engine.removeListener('prerender', prerender) };
Engine.on('prerender', prerender);
transitionable.set(end, transition, complete);
});
layout.header.add(header);
layout.content.add(new Surface({
size: [undefined, undefined],
content: "Content",
classes: ["grey-bg"],
properties: {
lineHeight: window.innerHeight - 150 + 'px',
textAlign: "center"
}
}));
layout.footer.add(new Surface({
size: [undefined, 50],
content: "Footer",
classes: ["red-bg"],
properties: {
lineHeight: "50px",
textAlign: "center"
}
}));
mainContext.add(layout);
As for the password field, you simply create an InputSurface and set it's type to password..
inputSurface = new InputSurface({
size:[200,60],
type: 'password'
});
^ Watch out for performance issues when using Transitionable on headerSize. Especially iPhones with iOS 7 seem to be acting glitchy.
You can also animate header / footer size via CSS transitions, although it's a bit of a bubblegum fix and has it's pitfalls:
var headerContainer = new ContainerSurface({
size: [undefined, 50],
classes: ['my-header']
});
layout.header.add(headerContainer);
headerContainer.setSize([undefined,300]);
Then in CSS:
.my-header { transition: 200ms all; }