In order to set colors upon many objects in the forge viewer, I made an extension which sets the color upon material and connect the objects to it. This way I only update the viewer once instead of multiple times. However I would like to have no transparancy, but I keep on getting it, even I have set the material transparancy to false. How can I fix this?
void setColorMaterial(material, viewer)
{
var mesh_material = this.addMaterial(material, viewer)
for (var i=0; i< material.dbIds.length; i++) {
var dbid = material.dbIds[i]
var it = viewer.model.getData().instanceTree
it.enumNodeFragments(dbid, function (fragId) {
var renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId)
renderProxy.meshProxy = new THREE.Mesh(renderProxy.geometry, renderProxy.material)
renderProxy.meshProxy.matrix.copy(renderProxy.matrixWorld)
renderProxy.meshProxy.matrixWorldNeedsUpdate = true
renderProxy.meshProxy.matrixAutoUpdate = false
renderProxy.meshProxy.frustumCulled = false
viewer.impl.addOverlay(material.name, renderProxy.meshProxy)
}, false)
}
this.materialHolder.push(material)
viewer.impl.invalidate(true)
}
void addMaterial(material, viewer)
{
var mesh_material = new THREE.MeshPhongMaterial({
color: #007dfa,
opacity: 1,
transparent: false,
name: 'materialName'
})
viewer.impl.matman().addMaterial(this.newGuid(), mesh_material)
viewer.impl.createOverlayScene(material.name, mesh_material, mesh_material)
}
First, thank you for your replies, unfortunately the transparancy is still there.
Alex: I removed the opacity.
Bryan: I fixed the code in according to your suggestions (as I understood them). Below is updated code.
As you can see from the picture in the link that the transparancy is still there. Any other suggestions would be greatly appreciated.
setColorMaterial(material, viewer) {
var mesh_material = this.addMaterial(material, viewer)
for (var i=0; i< material.dbIds.length; i++) {
var dbid = material.dbIds[i]
//from dbid to node, to fragid
var it = viewer.model.getData().instanceTree
it.enumNodeFragments(dbid, function (fragId) {
var renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId)
renderProxy.meshProxy = new THREE.Mesh(renderProxy.geometry, mesh_material)
renderProxy.meshProxy.matrix.copy(renderProxy.matrixWorld)
renderProxy.meshProxy.matrixWorldNeedsUpdate = true
renderProxy.meshProxy.matrixAutoUpdate = false
renderProxy.meshProxy.frustumCulled = false
viewer.impl.addOverlay(material.name, renderProxy.meshProxy)
}, false)
}
viewer.impl.invalidate(true)
}
addMaterial(material, viewer) {
var mesh_material = new THREE.MeshPhongMaterial({
color: material.color,
transparent: false,
blendEquationAlpha: false,
name: material.name
})
viewer.impl.matman().addMaterial(this.newGuid(), mesh_material)
viewer.impl.createOverlayScene(material.name, mesh_material)
return mesh_material
}
Transparency still there image
When using a model as a source to an entity, say gltf, is there a way we know the original size? Since the scale attribute works on relative size, it seems to be a trial an error to fit the model to our desired size. I tried using the geometry.getComputingBox() of the mesh of the model but it returns null. Wondering if there is a component that is available that lets us specify the scale in absolute terms.
Ah, figured it out.
var model = this.el.object3D;
var box = new THREE.Box3().setFromObject( model );
var size = box.getSize();
gives you the size. then using the above any desired size can be set.
Created a simple component that can be conveniently used
AFRAME.registerComponent('resize', {
schema: {
axis: {
type: 'string',
default: 'x'
},
value: {
type: 'number',
default: 1
}
},
init: function() {
var el = this.el;
var data = this.data;
var model = el.object3D;
el.addEventListener('model-loaded', function(e) {
var box = new THREE.Box3().setFromObject( model );
var size = box.getSize();
var x = size.x;
var y = size.y;
var z = size.z;
if(data.axis === 'x') {
var scale = data.value / x;
}
else if(data.axis === 'y') {
var scale = data.value / y;
}
else {
var scale = data.value / z;
}
el.setAttribute('scale', scale + ' ' + scale + ' ' + scale);
});
}
});
And it can be used as to proportionately resize the model with x axis length as 0.5
<a-entity resize='axis:x; value:0.5' gltf-model='#model`></a-entity>
(This would have come as a comment but as I don't have enough rep points this is coming as an answer.)
I found that the model doesn't have a size directly after the model-loaded event listener so I trigger the rescale from the update method. Funnily enough though if you don't have the model-loaded event listener then the size of the model will be 0 even after the first update is fired.
This is my variant of the above code with the difference being that the dimension is set in meters:
/**
* Scales the object proportionally to a set value given in meters.
*/
AFRAME.registerComponent("natural-size", {
schema: {
width: {
type: "number",
default: undefined, // meters
},
height: {
type: "number",
default: undefined, // meters
},
depth: {
type: "number",
default: undefined, // meters
},
},
init() {
this.el.addEventListener("model-loaded", this.rescale.bind(this));
},
update() {
this.rescale();
},
rescale() {
const el = this.el;
const data = this.data;
const model = el.object3D;
const box = new THREE.Box3().setFromObject(model);
const size = box.getSize();
if (!size.x && !size.y && !size.z) {
return;
}
let scale = 1;
if (data.width) {
scale = data.width / size.x;
} else if (data.height) {
scale = data.height(size.y);
} else if (data.depth) {
scale = data.depth / size.y;
}
el.setAttribute("scale", `${scale} ${scale} ${scale}`);
},
remove() {
this.el.removeEventListener("model-loaded", this.rescale);
},
});
Then:
<a-entity natural-size='width:0.72' gltf-model='#model`></a-entity>
box.getSize has changed, I combined what I found here with what I found in another answer and noticed in the console to produce a more minimalist answer just to determine the size itself of a model:
getDimensions(object3d) {
// e.g., object3d = document.querySelector('#goban').object3D
var box = new THREE.Box3().setFromObject( object3d );
var x = box.max.x - box.min.x
var y = box.max.y - box.min.y
var z = box.max.z - box.min.z
return {x,y,z}
}
I'm trying to create a morphing object based on a number of particles, I have 4 objects, 2 normal three js shapes (cube and sphere) and 2 OBJ objects.
When I hover the related name of the object it changes to that one.
The problem here is that when I try to hover the name of the obj object the console.log returns the following error at the last line where I try to get newParticles.vertices[i].x, etc:
Uncaught TypeError: Cannot read property 'x' of undefined
Code:
// Particle Vars
var particleCount = numberOfParticles;
let spherePoints,
cubePoints,
rocketPoints,
spacemanPoints;
var particles = new Geometry(),
sphereParticles = new Geometry(),
cubeParticles = new Geometry(),
rocketParticles = new Geometry(),
spacemanParticles = new Geometry();
var pMaterial = new PointsMaterial({
color: particleColor,
size: particleSize,
map: new TextureLoader().load(particleImage),
blending: AdditiveBlending,
transparent: true
});
// Objects
var geometry = new SphereGeometry( 5, 30, 30 );
spherePoints = GeometryUtils.randomPointsInGeometry(geometry, particleCount)
var geometry = new BoxGeometry( 9, 9, 9 );
cubePoints = GeometryUtils.randomPointsInGeometry(geometry, particleCount)
// Custom (OGJ) Objects
const codepenAssetUrl = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/605067/';
var objLoader = new OBJLoader();
objLoader.setPath('./upload/');
objLoader.load( 'Nymph.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof Mesh ) {
let scale = 0.2; //era 2.1 per il razzo
let area = new Box3();
area.setFromObject( child );
let yOffset = (area.max.y * scale) / 2;
child.geometry.scale(scale,scale,scale);
rocketPoints = GeometryUtils.randomPointsInBufferGeometry(child.geometry, particleCount);
createVertices(rocketParticles, rocketPoints, yOffset, 2);
}
});
});
var objLoader = new OBJLoader();
objLoader.setPath(codepenAssetUrl);
objLoader.load( 'Astronaut.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof Mesh ) {
let scale = 4.6;
let area = new Box3();
area.setFromObject( child );
let yOffset = (area.max.y * scale) / 2;
child.geometry.scale(scale,scale,scale);
spacemanPoints = GeometryUtils.randomPointsInBufferGeometry(child.geometry, particleCount);
createVertices(spacemanParticles, spacemanPoints, yOffset, 3);
}
});
});
// Particles
for (var p = 0; p < particleCount; p++) {
var vertex = new Vector3();
vertex.x = 0;
vertex.y = 0;
vertex.z = 0;
particles.vertices.push(vertex);
}
createVertices (sphereParticles, spherePoints, null, null)
createVertices (cubeParticles, cubePoints, null, 1)
function createVertices (emptyArray, points, yOffset = 0, trigger = null) {
for (var p = 0; p < particleCount; p++) {
var vertex = new Vector3();
vertex.x = points[p]['x'];
vertex.y = points[p]['y'] - yOffset;
vertex.z = points[p]['z'];
emptyArray.vertices.push(vertex);
}
if (trigger !== null) {
triggers[trigger].setAttribute('data-disabled', false)
}
}
var particleSystem = new Points(
particles,
pMaterial
);
particleSystem.sortParticles = true;
// Add the particles to the scene
scene.add(particleSystem);
// Animate
const normalSpeed = (defaultAnimationSpeed/100),
fullSpeed = (morphAnimationSpeed/100)
let animationVars = {
speed: normalSpeed
}
function animate() {
particleSystem.rotation.y += animationVars.speed;
particles.verticesNeedUpdate = true;
window.requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
setTimeout(toSphere, 500);
function toSphere () {
handleTriggers(0);
morphTo(sphereParticles);
}
function toCube () {
handleTriggers(1);
morphTo(cubeParticles);
}
function toRocket () {
handleTriggers(2);
morphTo(rocketParticles);
}
function toSpaceman () {
handleTriggers(3);
morphTo(spacemanParticles);
}
function morphTo (newParticles, color = '0xffffff') {
TweenMax.to(animationVars, .3, {ease:
Power4.easeIn, speed: fullSpeed, onComplete: slowDown});
particleSystem.material.color.setHex(color);
for (var i = 0; i < particles.vertices.length; i++){
TweenMax.to(particles.vertices[i], 4, {ease:
Elastic.easeOut.config( 1, 0.75), x: newParticles.vertices[i].x, y: newParticles.vertices[i].y, z: newParticles.vertices[i].z})
}
}
P.S. note that I'm using webpack.
I'm facing a performance problem with Leaflet (version 0.7.3). I'm working with an OSM map that I use to display a bunch of CircleMarkers linked by decorated Polylines (with arrow pattern every 25px). Loading take a little time but the main problem is that when I zoom the map I start facing severe lag (from the zoom level 16) and, beyond a certain limit (say 18 most of the time), browser just freeze and eventually crash (tested with chrome and firefox). I tried with a bunch of 1,000 linked markers, then I dropped to a set of around 100, but still the same concern... Of course, with 10 markers or less I don't have any problem.
Did you already face a similar trouble? How can I optimize Leaflet performances so that I can use an accurate zoom (beyond level 16) with more than 100 linked CircleMarkers ? I also wonder why performances are dropping so badly when zooming, while marker amount stay the same...
Thank you in advance for your answers,
Lenalys.
Cannot get the PolylineDecorator plugin to work on jsfiddle.
But here is the code that generate markers :
Map initialization :
var map;
function initializeMap(){
"use strict";
var layer;
var layer2;
function layerUrl(key, layer) {
return "http://wxs.ign.fr/" + key
+ "/geoportail/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&"
+ "LAYER=" + layer + "&STYLE=normal&TILEMATRIXSET=PM&"
+ "TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg";
}
layer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png',
{
attribution: '© OpenStreetMap contributors',
maxZoom: 18
});
layer2 = L.tileLayer(
layerUrl(IGN_AMBIENTE_KEY, "GEOGRAPHICALGRIDSYSTEMS.MAPS"),
{attribution: '© IGN'}
);
var baseMaps = {
"Terrestre": layer,
"Bathymetrique": layer2
};
map = L.map('map', {
layers: [layer],
zoom: 8,
center: [42.152796, 9.139150],
zoomControl: false
});
L.control.layers(baseMaps).addTo(map);
//add zoom control with your options
L.control.zoom({
position:'topright' //topleft
}).addTo(map);
L.control.scale({
position:'bottomleft',
imperial : false
}).addTo(map);
}
Data Sample :
var jsonData ={"12":[{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.42362","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 15:37:12"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.42365","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 16:42:16"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.4236933333333","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 17:47:21"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.4237383333333","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 19:57:23"}],
"13":[{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.61683","longitude":"9.4804633333333","temperature":"17.45","pulse":null,"battery":"80","date_time":"2015-04-08 07:45:20"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.538858333333","longitude":"9.48169","temperature":"14.37","pulse":null,"battery":"80","date_time":"2015-04-08 08:00:29"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.458748333333","longitude":"9.500225","temperature":"14.46","pulse":null,"battery":"80","date_time":"2015-04-08 08:15:49"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.3302","longitude":"9.5374583333333","temperature":"15.19","pulse":null,"battery":"80","date_time":"2015-04-08 08:31:05"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.170133333333","longitude":"9.5272116666667","temperature":"15.48","pulse":null,"battery":"80","date_time":"2015-04-08 08:46:20"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07959","longitude":"9.47688","temperature":"15.97","pulse":null,"battery":"80","date_time":"2015-04-08 09:01:31"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.076163333333","longitude":"9.4828633333333","temperature":"20.42","pulse":null,"battery":"80","date_time":"2015-04-08 09:16:59"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07194","longitude":"9.4908866666667","temperature":"17.36","pulse":null,"battery":"80","date_time":"2015-04-08 09:32:17"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072583333333","longitude":"9.4901516666667","temperature":"17.36","pulse":null,"battery":"80","date_time":"2015-04-08 09:47:32"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07238","longitude":"9.4904266666667","temperature":"19.38","pulse":null,"battery":"80","date_time":"2015-04-08 10:02:42"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072298333333","longitude":"9.4904983333333","temperature":"17.46","pulse":null,"battery":"80","date_time":"2015-04-08 10:17:55"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.095093333333","longitude":"9.5148383333333","temperature":"17.47","pulse":null,"battery":"80","date_time":"2015-04-08 10:33:12"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112881666667","longitude":"9.5133133333333","temperature":"19.3","pulse":null,"battery":"80","date_time":"2015-04-08 10:48:23"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112875","longitude":"9.513285","temperature":"22.71","pulse":null,"battery":"80","date_time":"2015-04-08 11:03:57"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.141096666667","longitude":"9.5078216666667","temperature":"23.73","pulse":null,"battery":"80","date_time":"2015-04-08 11:19:12"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.282186666667","longitude":"9.5505183333333","temperature":"18.97","pulse":null,"battery":"80","date_time":"2015-04-08 11:34:28"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.405126666667","longitude":"9.531145","temperature":"20.71","pulse":null,"battery":"80","date_time":"2015-04-08 11:49:42"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.482063333333","longitude":"9.480665","temperature":"21.7","pulse":null,"battery":"80","date_time":"2015-04-08 12:05:07"}]}
var oJSON = JSON.parse(jsonData);
var colors = [
"#400080",
"#008000",
"#EC7600",
"#E40341",
"#0D5E5E",
"#919191",
"#FF3C9D",
"#A70A0E",
"#00BFBF",
"#7171FF"
];
var classes = [
"color1",
"color2",
"color3",
"color4",
"color5",
"color6",
"color7",
"color8",
"color9",
"color10"
];
var lastMarkers = [];
var layers = new Array();
var polyline;
var decorator;
window.graphicsDevices = [];
var offsetLatitude = 0.003333;
var offsetLongitude = 0.011666;
Marker instanciation :
function printGPSOnMap(oJSON){
var nbKeys = 0;
for (var key in oJSON) {
nbKeys++;
var classe = classes[(key-1)%classes.length];
var color = colors[(key-1)%colors.length];
var positionInfo = [];
if (oJSON.hasOwnProperty(key)) {
var aInfo = oJSON[key];
var marker;
var latlngs = Array();
var startMarker = lastMarkers[key];
if(startMarker !== undefined && startMarker != null) {
var myIcon = L.divIcon({className: "myCircle "+classe, iconSize : [ 20, 20 ] });
startMarker.setIcon(myIcon);
latlngs.push(startMarker.getLatLng());
}
for(var i = 0; i < aInfo.length; i++) {
var oInfos = aInfo[i];
var sIdIndividual = oInfos["id_individual"];
var sLongitude = oInfos["longitude"];
var sLatitude = oInfos["latitude"];
var sTemperature = oInfos["temperature"];
var sPulse = oInfos["pulse"];
var sBattery = oInfos["battery"];
var sDatetime = oInfos["date_time"];
var sIndividualName = oInfos["individual_name"];
var id_device = oInfos["id_stm_device"];
var popupMsg = "...";
latlngs.push(L.marker([sLatitude,sLongitude]).getLatLng());
marker = new MyCustomMarker([sLatitude,sLongitude], {
icon : L.divIcon({
className : "myCircle "+classe + ((i == aInfo.length-1) ? ' myCircleEnd' : ''),
iconSize : [ 20, 20 ]
})
});
marker.bindPopup(popupMsg, {
showOnMouseOver: true
});
marker.bindLabel(key, {
noHide: true,
direction: 'middle',
offset: [offset[0], offset[1]]
});
positionInfo.push(marker);
}
lastMarkers[key] = marker;
}
if(latlngs.length > 1)
{
polyline = L.polyline(latlngs, {className: classe, weight: 2,opacity: 0.4}).addTo(map);
decorator = L.polylineDecorator(polyline, {
patterns: [
// define a pattern of 10px-wide arrows, repeated every 20px on the line
{offset: 0, repeat: '25px', symbol: new L.Symbol.arrowHead({pixelSize: 10, pathOptions: {fillOpacity:
0.76, color: color, weight: 1}})}
]}).addTo(map);
}
if(!window.graphicsDevices.hasOwnProperty(key))
window.graphicsDevices[key] = [];
for(var i = 0; i < positionInfo.length; i++) {
window.graphicsDevices[key].push(positionInfo[i]);
positionInfo[i].addTo(map);
if(latlngs.length > 1){
window.graphicsDevices[key].push(polyline);
polyline.addTo(map);
window.graphicsDevices[key].push(decorator);
decorator.addTo(map);
}
}
}//foreach key
}
Code for the custom marker :
var MyCustomMarker = L.Marker.extend({
bindPopup: function(htmlContent, options) {
if (options && options.showOnMouseOver) {
// call the super method
L.Marker.prototype.bindPopup.apply(this, [htmlContent, options]);
// unbind the click event
this.off("click", this.openPopup, this);
// bind to mouse over
this.on("mouseover", function(e) {
// get the element that the mouse hovered onto
var target = e.originalEvent.fromElement || e.originalEvent.relatedTarget;
var parent = this._getParent(target, "leaflet-popup");
// check to see if the element is a popup, and if it is this marker's popup
if (parent == this._popup._container)
return true;
// show the popup
this.openPopup();
}, this);
// and mouse out
this.on("mouseout", function(e) {
// get the element that the mouse hovered onto
var target = e.originalEvent.toElement || e.originalEvent.relatedTarget;
// check to see if the element is a popup
if (this._getParent(target, "leaflet-popup")) {
L.DomEvent.on(this._popup._container, "mouseout", this._popupMouseOut, this);
return true;
}
// hide the popup
this.closePopup();
}, this);
}
},
_popupMouseOut: function(e) {
// detach the event
L.DomEvent.off(this._popup, "mouseout", this._popupMouseOut, this);
// get the element that the mouse hovered onto
var target = e.toElement || e.relatedTarget;
// check to see if the element is a popup
if (this._getParent(target, "leaflet-popup"))
return true;
// check to see if the marker was hovered back onto
if (target == this._icon)
return true;
// hide the popup
this.closePopup();
},
_getParent: function(element, className) {
var parent = null;
if(element != null) parent = element.parentNode;
while (parent != null) {
if (parent.className && L.DomUtil.hasClass(parent, className))
return parent;
parent = parent.parentNode;
}
return false;
}
});
Have you gauged performance in canvas mode?
Use L_PREFER_CANVAS = true before initializing your leaflet map container.Might be able to help you possibly.
I'm trying to create an open curtain animation on a Scrollview, so when an item in a Scrollview is clicked, it and item to its left move left, and all items after it move to the right. when the item is clicked again, the curtain closes. Thinking of doing it by moving items out from the Scrollview to 2 SequentialLayouts and once the curtain closes, move them back into the Scollview. Can this be done? Can you move nodes / views around in the render tree from one node to another?
Any other design approaches I should consider?
Here is my version of the curtains you described. It was hard to know exactly what you wanted, but I took a stab at it.
define('main', function(require, exports, module) {
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 Utility = require("famous/utilities/Utility");
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({
direction: Utility.Direction.X
});
var views = [];
scrollview.sequenceFrom(views);
function _resize(index, views, event) {
console.log(index, event);
var itsMe = (index === event.index);
if (itsMe) {
this.trans.halt();
if (this.open)
this.trans.set(100, snap);
else
this.trans.set(400, snap);
this.open = !this.open;
scrollview.goToPage(index);
} else {
if (event.isOpen) {
this.trans.halt();
this.trans.set(100, snap);
} else {
this.trans.halt();
this.trans.set(20, snap);
}
this.open = false;
}
}
function _resizeChosen(index, views, event) {
scrollview._eventOutput.emit('itemChosen', {
index: index,
isOpen: views[index].surface.open
});
}
function _surfaceSize() {
return [this.trans.get(), undefined];
}
for (var i = 0; i < 20; i++) {
var node = new RenderNode();
node.surface = new Surface({
content: (i + 1),
size: [undefined, undefined],
properties: {
backgroundColor: "hsl(" + (i * 360 / 20) + ", 90%, 50%)",
lineHeight: "50px",
textAlign: "center"
}
});
node.surface._index = i;
node.surface.open = false;
node.surface.state = new Modifier();
node.surface.trans = new Transitionable(50);
node.surface.state.sizeFrom(_surfaceSize.bind(node.surface));
node.add(node.surface.state).add(node.surface);
node.surface.pipe(scrollview);
node.surface._eventOutput.subscribe(scrollview._eventOutput);
node.surface.on('click', _resizeChosen.bind(node.surface, i, views));
node.surface.on('itemChosen', _resize.bind(node.surface, i, views));
views.push(node);
}
mainContext.add(scrollview);
});
require(['main']);
<script src="http://requirejs.org/docs/release/2.1.16/minified/require.js"></script>
<script src="http://code.famo.us/lib/requestAnimationFrame.js"></script>
<script src="http://code.famo.us/lib/classList.js"></script>
<script src="http://code.famo.us/lib/functionPrototypeBind.js"></script>
<link rel="stylesheet" type="text/css" href="http://code.famo.us/famous/0.3.5/famous.css" />
<script src="http://code.famo.us/famous/0.3.5/famous.min.js"></script>