I have created a Sphere and a Wall and added it to the physics engine. The Sphere was is also given a starting velocity.
I then created a circle and wall Node, added DOMElement components, and set some dimensions and color.
During the update loop, the Nodes sync their position with their physical counterparts -- Sphere and Wall.
I expected the sphere to collide with the wall, but the animation shows that the Sphere simply continues through the wall. I'm wondering what is wrong with my code that this is occurring.
'use strict';
var famous = require('famous');
var DOMElement = famous.domRenderables.DOMElement;
var FamousEngine = famous.core.FamousEngine;
var Node = famous.core.Node;
var math = famous.math;
var physics = famous.physics;
var Particle = physics.Particle;
var Sphere = physics.Sphere;
var Vec3 = math.Vec3;
var Box = physics.Box;
var Wall = physics.Wall;
// Create Simulation.
var simulation = new physics.PhysicsEngine();
// Create Scene.
var scene = FamousEngine.createScene();
/***************************************
* Add Bodies
***************************************/
// Create Sphere.
var mySphere = new Sphere({ mass: 10, radius: 50 });
// Give the sphere some velocity.
mySphere.setVelocity(100, 0)
.setPosition(0, 250, 0);
// Create Wall.
var rightWall = new Wall({
direction: Wall.LEFT,
size: [10, 500, 100]
});
rightWall.setPosition(500, 0, 0);
simulation.addBody(rightWall);
simulation.addBody(mySphere);
/***************************************
* Add Nodes + Components
***************************************/
// Create circleNode, which updates its position based on mySphere's position.
var circleNode = scene.addChild();
circleNode
.setSizeMode('absolute', 'absolute', 'absolute')
// Match size of sphere
.setAbsoluteSize(100, 100)
.setPosition(0, 250, 0)
.setMountPoint(0, 0);
// Add DOMElement component to circleNode.
var circleDOMElement = new DOMElement(circleNode, { tagName: 'div' })
.setProperty('background-color', 'pink')
.setProperty('border-radius', '50px');
// Create a wallNode, which will update its position based on rightWall's position.
var wallNode = scene.addChild();
wallNode
.setSizeMode('absolute', 'absolute', 'absolute')
.setAbsoluteSize(10, 500, 100);
var wallDOMElement = new DOMElement(wallNode, { tagName: 'div' })
.setProperty('background-color', 'lightblue');
/***************************************
* Create an Update Loop
***************************************/
var updateLoop = scene.addComponent({
onUpdate: function (time) {
// During update, sync cirlceNode position with sphere,
// and wallNode position with wall.
var spherePosition = mySphere.getPosition();
var wallPosition = rightWall.getPosition();
circleNode.setPosition(spherePosition.x, spherePosition.y);
wallNode.setPosition(wallPosition.x, wallPosition.y);
simulation.update(time);
scene.requestUpdateOnNextTick(updateLoop);
}
});
// Kick off loop.
scene.requestUpdate(updateLoop);
FamousEngine.init();
Constraints are needed to apply to the Wall and the Sphere. In this case, you can use Collision
var Collision = physics.Collision;
Replace
rightWall.setPosition(500, 0, 0);
simulation.addBody(rightWall);
simulation.addBody(mySphere);
With
rightWall.setPosition(500, 0, 0);
simulation.addBody(mySphere);
var collision = new Collision([mySphere,rightWall]);
simulation.addConstraint(collision);
Also, fix mount point of circle to the center
circleNode
.setSizeMode('absolute', 'absolute', 'absolute')
// Match size of sphere
.setAbsoluteSize(100, 100)
.setPosition(0, 250, 0)
.setMountPoint(0.5, 0.5);
Bonus: Add Left Wall to keep the particle on the screen
// Create Walls.
var rightWall = new Wall({
direction: Wall.LEFT
});
var leftWall = new Wall({
direction: Wall.RIGHT
});
leftWall.setPosition(0, 0, 0);
rightWall.setPosition(500, 0, 0);
simulation.addBody(mySphere);
var collision = new Collision([mySphere,rightWall,leftWall]);
simulation.addConstraint(collision);
Example Working Snippet
var FamousEngine = famous.core.FamousEngine;
var DOMElement = famous.domRenderables.DOMElement;
var Node = famous.core.Node;
var math = famous.math;
var physics = famous.physics;
var Sphere = physics.Sphere;
var Wall = physics.Wall;
var Collision = physics.Collision;
// Create Scene.
var scene = FamousEngine.createScene();
var rootNode = scene.addChild();
// Create Simulation.
var simulation = new physics.PhysicsEngine();
/***************************************
* Add Bodies
***************************************/
// Create Sphere.
var mySphere = new Sphere({
mass: 100,
radius: 50
});
// Give the sphere some velocity.
mySphere.setVelocity(500, 0)
.setPosition(0, 70, 0);
// Create Wall.
var rightWall = new Wall({
direction: Wall.LEFT
});
var leftWall = new Wall({
direction: Wall.RIGHT
});
leftWall.setPosition(0, 0, 0);
rightWall.setPosition(300, 0, 0);
//simulation.addBody(rightWall);
simulation.addBody(mySphere);
var collision = new Collision([mySphere, rightWall, leftWall]);
simulation.addConstraint(collision);
/***************************************
* Add Nodes + Components
***************************************/
// Create circleNode, which updates its position based on mySphere's position.
var circleNode = scene.addChild();
circleNode
.setSizeMode('absolute', 'absolute', 'absolute')
// Match size of sphere
.setAbsoluteSize(100, 100)
.setPosition(0, 70, 0)
.setMountPoint(0.5, 0.5);
circleNode.addUIEvent('click');
circleNode.addComponent({
onReceive: function(type, event) {
if (type === 'click') {
console.log('setting velocity');
mySphere.setVelocity(1000, 0);
}
},
});
// Add DOMElement component to circleNode.
var circleDOMElement = new DOMElement(circleNode, {
tagName: 'div'
})
.setProperty('background-color', 'lightblue')
.setProperty('text-align', 'center')
.setProperty('line-height', '100px')
.setProperty('border-radius', '50px');
circleDOMElement.setContent('click');
// Create a wallNode, which will update its position based on rightWall's position.
var wallNode = scene.addChild();
wallNode
.setSizeMode('absolute', 'absolute', 'absolute')
.setAbsoluteSize(10, 130, 0);
var wallDOMElement = new DOMElement(wallNode, {
tagName: 'div'
})
.setProperty('background-color', 'lightblue');
/***************************************
* Create an Update Loop
***************************************/
var updateLoop = rootNode.addComponent({
onUpdate: function(time) {
// During update, sync cirlceNode position with sphere,
// and wallNode position with wall.
var spherePosition = mySphere.getPosition();
var wallPosition = rightWall.getPosition();
circleNode.setPosition(spherePosition.x, spherePosition.y);
wallNode.setPosition(wallPosition.x, wallPosition.y);
simulation.update(time);
rootNode.requestUpdateOnNextTick(updateLoop);
}
});
// Kick off loop.
rootNode.requestUpdate(updateLoop);
FamousEngine.init();
html,
body {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
}
body {
position: absolute;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
background-color: black;
-webkit-perspective: 0;
perspective: none;
overflow: hidden;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Physics Famous0.6.2</title>
<link rel="icon" href="favicon.ico?v=1" type="image/x-icon">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="http://code.famo.us/famous/0.6.2/famous.min.js"></script>
<style>
</style>
</head>
<body>
</body>
</html>
Related
To start, I am not the most advanced javascript developer. I have only now started to undertake a more serious study of the subject.
So one of my first forays in this subject is to draw some text to the canvas using the three.js library.But for the life of me, I can't get this sucker to work. I have looked on google and even through the three.js documentation. When I inspect the page in chrome, the page doesn't show any errors either. Here is my code for reference:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth /
window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xdddddd);
var spotlight = new THREE.SpotLight(0xffffff,);
spotlight.castShadow = true;
spotlight.position.set(30,60,60);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
var textGeo = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
} );
var color = new THREE.Color();
color.setRGB(255, 250, 250);
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
var textMaterial = new THREE.MeshBasicMaterial({ color: color });
var mesh = new THREE.Mesh(textGeo, textMaterial);
mesh.position.x = textGeo.boundingBox.max.x / 2;
mesh.position.y = textGeo.boundingBox.max.y / 2;
mesh.castShadow = true;
scene.add(mesh);
} );
var render = function (){
requestAnimationFrame(render);
renderer.render(scene, camera);
}
camera.lookAt(scene.position);
render();
Also, for some background if it's needed, I am running this in debug mode in an asp.net application.
Thanks everyone.
I had my camera directly on the scene, so I couldn't see anything. Thanks prisoner for comment.
I want to know how to draw bezier curve randomly that change every second with animation.
That's a very specific question. To generic answer is that each draw command on the graphics class returns an object. You can use this object to change the properties (x, y, color, width, ...) of the draw command later. This example should give you an idea:
import 'dart:html' as html;
import 'package:stagexl/stagexl.dart';
void main() {
var canvas = html.querySelector('#stage');
var stage = new Stage(canvas, width: 800, height: 600);
var renderLoop = new RenderLoop();
renderLoop.addStage(stage);
var shape = new Shape();
var movetoCommand = shape.graphics.moveTo(100, 100);
var bezierCommand = shape.graphics.bezierCurveTo(500, 200, 200, 500, 500, 500);
var strokeCommand = shape.graphics.strokeColor(Color.Red, 15);
stage.addChild(shape);
stage.juggler.translation(500, 200, 5.0, Transition.sine).listen((v) {
// change "controlX1" of the bezier draw command in an animation
bezierCommand.controlX1 = v.toDouble();
});
stage.juggler.translation(200, 500, 5.0, Transition.sine).listen((v) {
// change "controlX2" of the bezier draw command in an animation
bezierCommand.controlX2 = v.toDouble();
});
stage.juggler.translation(15, 50, 15.0, Transition.sine).listen((v) {
// change "width" of the stroke draw command in an animation
strokeCommand.width = v.toDouble();
});
}
I won't describe how to make the positions of the bezier curve random, that's just a specialized case of the example shown above.
I created a standalone map to test this out for myself. I took a heap snapshot, using Chrome Developer Tools, of the page upon loading it and found it was using 882MB of memory. I'm looking to plot about an hours worth of lightning data and I would like for the user to be able to interact with it so Openlayers makes sense here. However its taking up a ton of memory and need a solution that is much more memory efficient.
Below is the code I used to do this:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.6.0/ol.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.6.0/ol.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="md-12">
<div id="map" class="map"></div>
</div>
</div>
<div id="span12">
</div>
</div>
<script>
var iconInfo = [{
points: 4,
radius: 3,
radius2: 0,
angle: 0
}, {
points: 4,
radius: 3,
radius2: 0,
angle: 0
}, {
points: 4,
radius: 3,
radius2: 0,
angle: 0
}, {
points: 4,
radius: 3,
radius2: 0,
angle: 0
}];
var i;
var iconCount = iconInfo.length;
var icons = new Array(iconCount);
for (i = 0; i < iconCount; ++i) {
var info = iconInfo[i];
icons[i] = new ol.style.RegularShape({
points: info.points,
radius: info.radius,
radius2: info.radius2,
angle: info.angle,
fill: new ol.style.Fill({color: 'rgba(0, 0, 0, 0.9)'}),
stroke: new ol.style.Stroke({width: 2, color: 'rgba(0, 0, 0, 0.9)'}),
});
}
var featureCount = 350000;
var features = new Array(featureCount);
var feature, geometry;
var e = 25000000;
for (i = 0; i < featureCount; ++i) {
geometry = new ol.geom.Point(
[2 * e * Math.random() - e, 2 * e * Math.random() - e]);
feature = new ol.Feature(geometry);
feature.setStyle(
new ol.style.Style({
image: icons[i % (iconCount - 1)]
})
);
features[i] = feature;
}
var vectorSource = new ol.source.Vector({
features: features
});
var vector = new ol.layer.Vector({
source: vectorSource
});
var map = new ol.Map({
layers: [vector],
target: document.getElementById('map'),
view: new ol.View({
center: [0, 0],
zoom: 5
})
});
var overlayFeatures = [];
for (i = 0; i < featureCount; i += 30) {
var clone = features[i].clone();
clone.setStyle(null);
overlayFeatures.push(clone);
}
var featureOverlay = new ol.layer.Vector({
map: map,
source: new ol.source.Vector({
features: overlayFeatures
}),
style: new ol.style.Style({
image: icons[iconCount - 1]
})
});
map.on('click', function(evt) {
var info = document.getElementById('info');
info.innerHTML =
'Hold on a second, while I catch those butterflies for you ...';
window.setTimeout(function() {
var features = [];
map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
features.push(features);
return false;
});
if (features.length === 1) {
info.innerHTML = 'Got one butterfly';
} else if (features.length > 1) {
info.innerHTML = 'Got ' + features.length + ' butterflies';
} else {
info.innerHTML = 'Couldn\'t catch a single butterfly';
}
}, 1);
});
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
var pixel = map.getEventPixel(evt.originalEvent);
var hit = map.hasFeatureAtPixel(pixel);
map.getTarget().style.cursor = hit ? 'pointer' : '';
});
</script>
</body>
</html>
Any suggestions on how I could achieve better memory efficiency?
Short answer
OpenLayers 3 uses about 2 kB per Point feature (see below), so while there are some optimizations possible you have to keep the number of features down. 400 000 features will require about 800 MB of memory.
Load your features dynamically, or use MultiPoint geometries.
Move the style from the geometry to the layer.
Longer answer
Style
When i tested, removing the style from the feature and replacing it with a simple property reduced the memory footprint by 290 B per feature. See http://jsfiddle.net/vkm2rg46/3/:
var vector = new ol.layer.Vector({
source: vectorSource,
style: function (feature, resolution) {
var i = feature.getProperties().styleId;
return [new ol.style.Style({
image: icons[i]
})];
}
});
and to help the style function:
feature.set('styleId', i % (iconCount - 1));
Spatial index
You could set useSpatialIndex to false on the vector source. The source keep a spatial index to quickly retrieve features within a given extent, which seems to need about 200-250 bytes per feature. However, removing the index could have bad performance consequences with this amount of features.
Reduce feature count##
Your best bet is probably to load fewer features. There are several solutions to this.
Load on demand
It's most commonly solved by letting the server take care of the data, and dynamically load it when needed. You probably don't want to display 400 000 points at lower zoom levels, and the users wont pan everywhere.
This could be done by vector tiles or with a normal vector source using a bbox or tile.
It could also be done client side, by creating features/geometries from your own dataset in the vector source loader function.
Multipoints
A MultiPoint geometry with 10 or 100 points hardly take any more space than a single Point geometry. If you group you lightning strikes into MultiPoint geometries, memory could be a non-issue. You would however loose some semantics, and the possibility to attach metadata to each single point.
JsFiddle: http://jsfiddle.net/vkm2rg46/8/
Memory usage
I created http://jsfiddle.net/g7qduy1w/3/ to test the memory use of the geometry, features and source. You can take snapshot at the different stages (notably, the event listening data increases when adding a geometry to a feature, and a feature to a source).
With a simple point geometry added to a feature without extra properties, and added to a source, the memory use per feature is:
288 B geometry event listener
424 B rest of geometry data
752 B feature event listeners
184 B rest of feature data
261 B source (share of total memory using 100 000 features)
Have a look at this example from camptocamp
https://www.camptocamp.com/en/actualite/drawing-large-amounts-of-points-with-openlayers-3-and-webgl
OpenLayers Symbols with WebGL:
http://openlayers.org/en/master/examples/symbol-atlas-webgl.html
It displays 100k points very efficiently!
I am trying to use Three.js to make some graphics. At the beginning stage, I found out: till now on ios7.0, I cannot use WebGL. So instead, I use CanvasRenderer. However, it seems that the size of CanvasRenderer will seriously affect the performance. Could someone give share some thoughts? Or provide a good resolution for CanvasRenderer on ios devices?
Note: I displayed the resolution of chrome on the iPhone5s: 980x1544.
If I set resolution to 640*1024, it works fine.
If I use smaller resolution: (window.innerWidth/2 , window.innerHeight/2), that works fine as well.
However, if I use full width and full height, the cube will not display. Even if I set height to (640,1025), the spinning cube will be really slow.
My question is : how does the size of CanvasRenderer impact on the performance? (Specifically for iPhone5 browsers in this case)
The following is the simple code I wrote to render a cube:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(40, window.innerWidth/window.innerHeight, 0.1, 1000);
document.getElementById("debug").innerHTML = window.innerWidth + " " + window.innerHeight;
renderer = webglAvailable() ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer();
renderer.setSize(640, 1024);
document.getElementById("body").appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
For reference, you could try to use your iPhone to load these two pages. You can easily see the performance difference.
Resolution 640*1024: http://shawnfandev.com/Testing/workingResolution/Cube.php
Resolution 640*1200: http://shawnfandev.com/Testing/higherResolution/Cube.php
Any thoughts is appreciated!
I made a simple simulation that can change resolution and calculates FPS.
The simulation renders 100 cubes to lower FPS to make it easy to compare.
FPS monitor is provided by stats.js.
This is jsfiddle.
HTML:
<div id="renderer"></div>
<div id="input_fileds">
width: <input type="text" id="width" value="200">
height: <input type="text" id="height" value="200">
</div>
javascript:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(40, 1, 0.1, 1000);
var renderer = new THREE.CanvasRenderer();
renderer.setSize(200, 200);
container = document.getElementById('renderer');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.domElement);
var geometry = new THREE.BoxGeometry(.3, .3, .3);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cubes = [];
for (var i = 0; i < 100; i++) {
var cube = new THREE.Mesh(geometry, material);
cube.position.x = Math.random() * 6 - 3;
cube.position.y = Math.random() * 6 - 3;
cubes.push(cube);
scene.add(cube);
}
camera.position.z = 10;
var render = function() {
cubes.forEach(function(cube) {
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
});
stats.update();
renderer.render(scene, camera);
setTimeout(render, 1000 / 60);
};
render();
var width_input = document.getElementById('width');
var height_input = document.getElementById('height');
width_input.addEventListener("keyup", function() {
resize();
});
height_input.addEventListener("keyup", function() {
resize();
});
function resize() {
camera.aspect = width_input.value / height_input.value;
camera.updateProjectionMatrix();
renderer.setSize(width_input.value, height_input.value);
}
css:
#renderer{
margin-top:50px;
}
#renderer canvas{
background-color: #000000;
}
#input_fileds{
position:fixed !important;
top:0px;
padding-left:100px;
}
#stats{
position:fixed !important;
}
Result on my iPhone5s
19 FPS on 600x600
19 FPS on 800x800
19 FPS on 1000x1000
19 FPS on 1024x1024
5 FPS on 1025x1025
FPS and resolution are not directly proportional to each other, but when resolution is greater than some point, FPS falls sharply.
Is it possible to work with client chosen images on client PC without uploading image to server.
If yes, what web programming language can do that?
You can use HTML5 Canvas, no need to use plugins or such.
Load the image, change the canvas size, and draw image. It's also possible to extract the result as a dataUrl.
<!DOCTYPE HTML>
<html>
<head>
<style>
body { margin: 0px; padding: 0px; }
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw cropped image
var sourceX = 150;
var sourceY = 0;
var sourceWidth = 150;
var sourceHeight = 150;
var destWidth = sourceWidth;
var destHeight = sourceHeight;
var destX = canvas.width / 2 - destWidth / 2;
var destY = canvas.height / 2 - destHeight / 2;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
</script>
</body>
</html>
All credit goes to:
http://www.html5canvastutorials.com/tutorials/html5-canvas-image-crop/
This can also be done with javascript libraries like jQuery, MooTools, Prototype and script.aculo.us:
http://www.bitrepository.com/image-cropping-with-jquery-mootools-prototype-scriptaculous.html
This can only be done with Flash, Silverlight or a custom Plugin/ActiveX depending on the target browser.
If you are looking for a image cropper by javascript, take a look at: https://github.com/supnate/icropper . It provides the user interface for cropping but not real cropping the image.