I am building a site which requires a physics engine.
Having worked with a number of SPA apps i feel pretty confident with.
Unfortunately I am having trouble applying collision detection & walls to a physics simulation that famous has created.
You can see the editable example here.
https://staging.famous.org/examples/index.html?block=gravity3d&detail=false&header=false
What I would like to know is it possible to add collisions to the particles? I have tried this but it appears the collisions are not setup correctly. I was hoping someone has managed to do it successfully.
Thanks!
var FamousEngine = famous.core.FamousEngine;
var Camera = famous.components.Camera;
var DOMElement = famous.domRenderables.DOMElement;
var Gravity3D = famous.physics.Gravity3D;
var Gravity1D = famous.physics.Gravity1D;
var MountPoint = famous.components.MountPoint;
var PhysicsEngine = famous.physics.PhysicsEngine;
var Physics = famous.physics;
var Wall = famous.physics.Wall;
var Position = famous.components.Position;
var Size = famous.components.Size;
var Sphere = famous.physics.Sphere;
var Vec3 = famous.math.Vec3;
var Collision = famous.physics.Collision;
function Demo() {
this.scene = FamousEngine.createScene('#socialInteractive');
this.camera = new Camera(this.scene);
this.camera.setDepth(1000);
this.simulation = new PhysicsEngine();
this.items = [];
this.collision = new Collision();
var Wall = famous.physics.Wall;
var rightWall = new Wall({
direction: Wall.LEFT
}); // bodies coming from the left will collide with the wall
rightWall.setPosition(1000, 0, 0);
var ceiling = new Wall({
normal: [0, 1, 0],
distance: 300,
restitution: 0
});
var floor = new Wall({
normal: [0, -1, 0],
distance: 300,
restitution: 0
});
var left = new Wall({
normal: [1, 0, 0],
distance: 350,
restitution: 0
});
var right = new Wall({
normal: [-1, 0, 0],
distance: 350,
restitution: 0
});
var node = this.scene.addChild();
var position = new Position(node);
// this.simulation.attach([right, left, floor, ceiling])
// this.items.push([ceiling,position]);
for (var i = 0; i < 10; i++) {
var node = this.scene.addChild();
var size = new Size(node).setMode(1, 1);
var position = new Position(node);
if (i === 0) {
createLogo.call(this, node, size, position);
}
if (i !== 0) {
node.id = i;
createSatellites.call(this, node, size, position);
}
}
FamousEngine.requestUpdateOnNextTick(this);
console.log(this.collision)
for (var i = 0; i < this.collision.length; i++) {
this.simulation.attach(collision, balls, balls[i]);
}
this.simulation.addConstraint(this.collision);
}
Demo.prototype.onUpdate = function(time) {
this.simulation.update(time);
this.collision.update(time, 60);
if (this.items.length > 0) {
for (var i = 0; i < this.items.length; i++) {
var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
}
}
FamousEngine.requestUpdateOnNextTick(this);
};
function createLogo(node, size, position) {
size.setAbsolute(50, 50);
var mp = new MountPoint(node).set(0.5, 0.5);
var el = new DOMElement(node, {
tagName: 'img',
attributes: {
src: './images/famous-logo.svg'
}
});
var sphere = new Sphere({
radius: 100,
mass: 10000,
restrictions: ['xy'],
position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 5)
});
this.gravity = new Gravity3D(sphere);
this.simulation.add(sphere, this.gravity);
this.items.push([sphere, position]);
}
function createSatellites(node, size, position, i) {
size.setAbsolute(20, 20);
var radius = 200;
var x = Math.floor(Math.random() * radius * 2) - radius;
var y = (Math.round(Math.random()) * 2 - 1) * Math.sqrt(radius * radius - x * x);
var color = 'rgb(' + Math.abs(x) + ',' + Math.abs(Math.round(y)) + ',' + (255 - node.id) + ')';
var el = new DOMElement(node, {
properties: {
'background-color': color,
'border-radius': '50%'
}
});
var satellite = new Sphere({
radius: 20,
mass: 5,
position: new Vec3(x + window.innerWidth / 2, y + window.innerHeight / 2, 0)
});
satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
this.gravity.addTarget(satellite);
this.simulation.add(satellite);
this.items.push([satellite, position]);
this.collision.addTarget(satellite);
}
// Boilerplate
FamousEngine.init();
// App Code
var demo = new Demo();
Thanks for your help Talves, I think i found a solution that works with physics Spring instead of gravity3d. This also has the 4 walls included which seems to work well.
var famous = famous;
var FamousEngine = famous.core.FamousEngine;
var Camera = famous.components.Camera;
var DOMElement = famous.domRenderables.DOMElement;
var Gravity3D = famous.physics.Gravity3D;
var MountPoint = famous.components.MountPoint;
var PhysicsEngine = famous.physics.PhysicsEngine;
var Position = famous.components.Position;
var Size = famous.components.Size;
var Wall = famous.physics.Wall;
var Sphere = famous.physics.Sphere;
var Vec3 = famous.math.Vec3;
var math = famous.math;
var physics = famous.physics;
var collision = famous.physics.Collision;
var gestures = famous.components.GestureHandler;
var Spring = famous.physics.Spring;
console.log(famous)
var anchor = new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0);
//Create Walls
var rightWall = new Wall({
direction: Wall.LEFT
}).setPosition(window.innerWidth - 20, 0, 0);
var leftWall = new Wall({
direction: Wall.RIGHT
}).setPosition(window.innerWidth + 20, 0, 0);
var topWall = new Wall({
direction: Wall.DOWN
}).setPosition(0, 20, 0);
var bottomWall = new Wall({
direction: Wall.UP
}).setPosition(0, window.innerHeight - 20, 0);
function Demo() {
this.scene = FamousEngine.createScene('body');
this.camera = new Camera(this.scene);
this.camera.setDepth(1000);
this.collision = new collision([rightWall, leftWall, topWall, bottomWall]);
this.simulation = new PhysicsEngine();
this.simulation.setOrigin(0.5, 0.5);
this.simulation.addConstraint(this.collision);
this.items = [];
this.walls = [];
//Create Items
for (var i = 0; i < 30; i++) {
var node = this.scene.addChild();
node.setMountPoint(0.5, 0.5);
var size = new Size(node).setMode(1, 1);
var position = new Position(node);
if (i === 0) {
createLogo.call(this, node, size, position);
}
if (i !== 0) {
node.id = i;
createSatellites.call(this, node, size, position);
}
}
//Create Walls
var node = this.scene.addChild();
createWalls(node);
FamousEngine.requestUpdateOnNextTick(this);
Demo.prototype.onUpdate = function(time) {
this.simulation.update(time);
//Postition walls
var wallPosition = topWall.getPosition();
node.setPosition(wallPosition.x, wallPosition.y);
//Position elements
if (this.items.length > 0) {
for (var i = 0; i < this.items.length; i++) {
var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
}
}
FamousEngine.requestUpdateOnNextTick(this);
};
}
function createWalls(wallNode) {
wallNode.setSizeMode('absolute', 'absolute', 'absolute').setAbsoluteSize(window.innerWidth, 10, 0);
var wallDOMElement = new DOMElement(wallNode, {
tagName: 'div'
}).setProperty('background-color', 'lightblue');
}
function createLogo(node, size, position) {
size.setAbsolute(50, 50);
var mp = new MountPoint(node).set(0.5, 0.5);
var el = new DOMElement(node, {
tagName: 'img',
attributes: {
src: './images/famous_logo.png'
}
});
var sphere = new Sphere({
radius: 100,
mass: 10000,
restrictions: ['xy'],
position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 5)
});
// this.gravity = new Gravity3D(sphere);
// this.simulation.add(sphere, this.gravity);
this.simulation.add(sphere);
this.items.push([sphere, position]);
}
function createSatellites(node, size, position, i) {
size.setAbsolute(50, 50);
var radius = 100;
var x = Math.floor(Math.random() * radius * 2) - radius;
var y = (Math.round(Math.random()) * 2 - 1) * Math.sqrt(radius * radius - x * x);
var color = 'rgb(' + Math.abs(x) + ',' + Math.abs(Math.round(y)) + ',' + (255 - node.id) + ')';
var el = new DOMElement(node, {
properties: {
'background-color': color,
'border-radius': '50%'
}
});
var satellite = new Sphere({
radius: 25,
mass: 10,
position: new Vec3(x + window.innerWidth / 2, y + window.innerHeight / 2, 0)
});
// Attach the box to the anchor with a `Spring` force
var spring = new Spring(null, satellite, {
stiffness: 95,
period: 0.6,
dampingRatio: 1.0,
anchor: anchor
});
//console.log(color);
// satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
satellite.setVelocity(0.5, 0.5, 0);
// this.gravity.addTarget(satellite);
this.simulation.add(satellite, spring);
this.items.push([satellite, position]);
this.collision.addTarget(satellite);
}
// Boilerplate
FamousEngine.init();
// App Code
var demo = new Demo();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Famous :: Seed Project</title>
<link rel="icon" href="favicon.ico?v=1" type="image/x-icon">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
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;
-webkit-perspective: 0;
perspective: none;
overflow: hidden;
}
</style>
</head>
<body>
<script src="http://code.famo.us/famous/0.6.2/famous.min.js"></script>
</body>
</html>
Related
I want to create polygonfaceset wall using xbim toolkit library. Please let me know what I am doing wrong. It will be great help to me if anybody can provide sample code or some approach regarding polygonfaceset wall.
Below I provide scrennshot and samplecode.
static private IfcWallStandardCase CreateWall(IfcStore model, double length, double width, double height)
{
//
//begin a transaction
using (var txn = model.BeginTransaction("Create Wall"))
{
var wall = model.Instances.New();
wall.Name = "A Standard rectangular wall";
//represent wall as a rectangular profile
var rectProf = model.Instances.New<IfcRectangleProfileDef>();
rectProf.ProfileType = IfcProfileTypeEnum.AREA;
rectProf.XDim = width;
rectProf.YDim = length;
var insertPoint = model.Instances.New<IfcCartesianPoint>();
insertPoint.SetXY(0, 400); //insert at arbitrary position
rectProf.Position = model.Instances.New<IfcAxis2Placement2D>();
rectProf.Position.Location = insertPoint;
var polyfaceset = model.Instances.New<IfcPolygonalFaceSet>();
var coordinates2 = model.Instances.New<IfcIndexedPolygonalFace>();
//var coordinates = model.Instances.New<IfcCartesianPointList3D>(pl => {
// pl.CoordList.GetAt(0).AddRange(new IfcLengthMeasure[] { 0, 0, 0 });
// pl.CoordList.GetAt(1).AddRange(new IfcLengthMeasure[] { 1, 0, 0 });
// pl.CoordList.GetAt(2).AddRange(new IfcLengthMeasure[] { 0, 1, 0 });
// pl.CoordList.GetAt(3).AddRange(new IfcLengthMeasure[] { 0, 0, 1 });
//});
polyfaceset.Closed = true;
polyfaceset.Coordinates = model.Instances.New<IfcCartesianPointList3D>(pl => {
pl.CoordList.GetAt(0).AddRange(new IfcLengthMeasure[] { 0, 0, 1000 });
pl.CoordList.GetAt(1).AddRange(new IfcLengthMeasure[] { 3000, 0, 1000 });
pl.CoordList.GetAt(2).AddRange(new IfcLengthMeasure[] { 3000, 2000, 10000 });
pl.CoordList.GetAt(3).AddRange(new IfcLengthMeasure[] { 1000, 3000, 1000 });
pl.CoordList.GetAt(4).AddRange(new IfcLengthMeasure[] { 0, 2000, 1000 });
});
//model as a swept area solid
var body = model.Instances.New<IfcExtrudedAreaSolid>();
body.Depth = height;
body.SweptArea = rectProf;
body.ExtrudedDirection = model.Instances.New<IfcDirection>();
body.ExtrudedDirection.SetXYZ(0, 0, 1);
//parameters to insert the geometry in the model
var origin = model.Instances.New<IfcCartesianPoint>();
origin.SetXYZ(0, 0, 0);
body.Position = model.Instances.New<IfcAxis2Placement3D>();
body.Position.Location = origin;
//Create a Definition shape to hold the geometry
var shape = model.Instances.New<IfcShapeRepresentation>();
var modelContext = model.Instances.OfType<IfcGeometricRepresentationContext>().FirstOrDefault();
shape.ContextOfItems = modelContext;
shape.RepresentationType = "SweptSolid";
shape.RepresentationIdentifier = "Body";
shape.Items.Add(body);
//create visual style
model.Instances.New<IfcStyledItem> (styleItem => {
styleItem.Item = body;
styleItem.Styles.Add(model.Instances.New<IfcSurfaceStyle>(style => {
style.Side = IfcSurfaceSide.BOTH;
style.Styles.Add(model.Instances.New<IfcSurfaceStyleRendering>(rendering => {
rendering.SurfaceColour = model.Instances.New<IfcColourRgb>(colour => {
colour.Name = "Orange";
colour.Red = 1.0;
colour.Green = 0.5;
colour.Blue = 0.0;
});
}));
}));
});
//Create a Product Definition and add the model geometry to the wall
var rep = model.Instances.New<IfcProductDefinitionShape>();
rep.Representations.Add(shape);
wall.Representation = rep;
//now place the wall into the model
var lp = model.Instances.New<IfcLocalPlacement>();
var ax3D = model.Instances.New<IfcAxis2Placement3D>();
ax3D.Location = origin;
ax3D.RefDirection = model.Instances.New<IfcDirection>();
ax3D.RefDirection.SetXYZ(0, 1, 0);
ax3D.Axis = model.Instances.New<IfcDirection>();
ax3D.Axis.SetXYZ(0, 0, 1);
lp.RelativePlacement = ax3D;
wall.ObjectPlacement = lp;
// Where Clause: The IfcWallStandard relies on the provision of an IfcMaterialLayerSetUsage
var ifcMaterialLayerSetUsage = model.Instances.New<IfcMaterialLayerSetUsage>();
var ifcMaterialLayerSet = model.Instances.New<IfcMaterialLayerSet>();
var ifcMaterialLayer = model.Instances.New<IfcMaterialLayer>();
ifcMaterialLayer.LayerThickness = 10;
ifcMaterialLayerSet.MaterialLayers.Add(ifcMaterialLayer);
ifcMaterialLayerSetUsage.ForLayerSet = ifcMaterialLayerSet;
ifcMaterialLayerSetUsage.LayerSetDirection = IfcLayerSetDirectionEnum.AXIS2;
ifcMaterialLayerSetUsage.DirectionSense = IfcDirectionSenseEnum.NEGATIVE;
ifcMaterialLayerSetUsage.OffsetFromReferenceLine = 150;
// Add material to wall
var material = model.Instances.New<IfcMaterial>();
material.Name = "some material";
var ifcRelAssociatesMaterial = model.Instances.New<IfcRelAssociatesMaterial>();
ifcRelAssociatesMaterial.RelatingMaterial = material;
ifcRelAssociatesMaterial.RelatedObjects.Add(wall);
ifcRelAssociatesMaterial.RelatingMaterial = ifcMaterialLayerSetUsage;
// IfcPresentationLayerAssignment is required for CAD presentation in IfcWall or IfcWallStandardCase
var ifcPresentationLayerAssignment = model.Instances.New<IfcPresentationLayerAssignment>();
ifcPresentationLayerAssignment.Name = "some ifcPresentationLayerAssignment";
ifcPresentationLayerAssignment.AssignedItems.Add(shape);
// linear segment as IfcPolyline with two points is required for IfcWall
var ifcPolyline = model.Instances.New<IfcPolyline>();
var startPoint = model.Instances.New<IfcCartesianPoint>();
var midpoint = model.Instances.New<IfcCartesianPoint>();
var midpoint2 = model.Instances.New<IfcCartesianPoint>();
startPoint.SetXYZ(3000, 0, 1000);
midpoint.SetXYZ(3000, 2000, 1000);
midpoint2.SetXYZ(1000, 3000, 1000);
var endPoint = model.Instances.New<IfcCartesianPoint>();
endPoint.SetXYZ(0, 2000, 1000);
ifcPolyline.Points.Add(startPoint);
ifcPolyline.Points.Add(midpoint);
ifcPolyline.Points.Add(midpoint2);
ifcPolyline.Points.Add(endPoint);
var shape2D = model.Instances.New<IfcShapeRepresentation>();
shape2D.ContextOfItems = modelContext;
shape2D.RepresentationIdentifier = "Axis";
shape2D.RepresentationType = "Curve2D";
shape2D.Items.Add(ifcPolyline);
rep.Representations.Add(shape2D);
txn.Commit();
return wall;
}
}
This CreateWall function create Ifc wall. Please go throw it above code.
trying to extend a chart, so that i can draw lines up to the data point, but this is happening before the default animation. it would look smoother if it applied after.
i have got most of it to work.. but how do i get this to apply after chart animation.
var originalLineDraw = Chart.controllers.line.prototype.draw;
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw: function () {
originalLineDraw.apply(this, arguments);
var chart = this.chart;
var ctx = chart.chart.ctx;
var index = chart.config.data.lineAtIndex;
if (index) {
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-1']
var points = this.chart.getDatasetMeta(this.index).data;
for (var i = 0; i < points.length; i++) {
// var point_x = points[i]._model.x;
var point_y = points[i]._model.y;
ctx.beginPath();
ctx.setLineDash([5, 5]);/*dashes are 5px and spaces are 3px*/
ctx.moveTo(xaxis.getPixelForValue(undefined, i), point_y);
ctx.strokeStyle = '#fff';
ctx.lineTo(xaxis.getPixelForValue(undefined, i), yaxis.bottom);
ctx.stroke();
}
}
}
});
Update...
altho the darw is incorrect it still is playing after animation
var verticalLinePlugin = {
renderVerticalLine: function (chartInstance) {
var chart = chartInstance;
var ctx = chart.chart.ctx;
var maxpoint = [];
//loop the datasets
for (var y = 0; y < chart.config.data.datasets.length; y++) {
var dataset = chart.config.data.datasets[y];
if (dataset.hidden)
continue;
var points = chart.getDatasetMeta(y).data;
for (var i = 0; i < points.length; i++) {
var point_y = points[i]._model.y;
if (point_y < 0)
continue;
var point = maxpoint[i];
if (point == undefined) {
maxpoint.push({ id: i, y: point_y });
} else {
if (point.y > point_y) {
point.y = point_y;
}
}
}
}
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-1']
chart.data.datasets.forEach(function (dataset, i) {
var ds = dataset;
var meta = chart.getDatasetMeta(i);
meta.data.forEach(function (element, index) {
var value = maxpoint[i];
ctx.beginPath();
ctx.setLineDash([5, 5]);
ctx.moveTo(xaxis.getPixelForValue(undefined, i), value.y);
ctx.strokeStyle = '#fff';
ctx.lineTo(xaxis.getPixelForValue(undefined, i), yaxis.bottom);
ctx.stroke();
});
});
},
afterRender: function (chart) {
this.renderVerticalLine(chart);
}
};
Chart.plugins.register(verticalLinePlugin);
I made some small changes (non-intuitive!), and the vertical lines now appear after the animation.
Get the x values from the metadata instead of the data.
Either:
var x_point = element._model.x;
or:
var position = element.tooltipPosition();
var x_point = position.x;
Wrap the drawing in if(!hidden){}, then the vertical lines will disapear and reappear with the data. (The ternary assignment fixes a clash if the data starts hidden)
Do you need the value=max[i]? If just drawing the line up to the points, can get the y_point the same as for x.
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-1'];
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.getDatasetMeta(i);
var hidden = (meta.hidden != undefined) ? meta.hidden : dataset.hidden
if(!hidden){
meta.data.forEach(function (element, index) {
//var value = maxpoint[i];
var x_point = element._model.x;
var y_point = element._model.y;
ctx.beginPath();
ctx.save();
ctx.setLineDash([5, 5])
ctx.strokeStyle = '#fff';
ctx.moveTo(x_point, y_point); // or value.y
ctx.lineTo(x_point, yaxis.bottom)
ctx.stroke();
ctx.restore();
});
}
});
I have been trying to create a custom brush paint with an image file using fabric JS . I have tried using the fabric.PatternBrush but this is not the exact thing that I was looking for because this creates a background pattern kind of paint and what I am trying to do is repeat the image wherever the mouse is dragged.
Can anyone please direct me towards the right way? It will be fine for me to switch to any other drawing library that does what I am looking for.
I found a solution to this problem. We can create a custom brush using fabric.BaseBrush as follows:
fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
opacity: .2,
width: 30,
_baseWidth: 5,
_drips: [],
_dripThreshold: 15,
_inkAmount: 0,
_interval: 20,
_lastPoint: null,
_point: null,
_strokeId: 0,
brush: null,
brushCol : '/static/img/creation_room/textures/texture2.png',
initialize: function(canvas, opt) {
var context = this;
opt = opt || {};
this.canvas = canvas;
this.width = opt.width || canvas.freeDrawingBrush.width;
this.opacity = opt.opacity || canvas.contextTop.globalAlpha;
this.color = opt.color || canvas.freeDrawingBrush.color;
this.canvas.contextTop.lineJoin = "round";
this.canvas.contextTop.lineCap = "round";
this._reset();
fabric.Image.fromURL(this.brushCol, function(brush) {
console.log(brush);
context.brush = brush;
context.brush.filters = [];
context.changeColor(context.color || this.color);
}, { crossOrigin: "anonymous" });
},
changeColor: function(color) {
this.color = color;
this.brush.filters[0] = new fabric.Image.filters.Tint({ color: color });
this.brush.applyFilters(this.canvas.renderAll.bind(this.canvas));
},
changeOpacity: function(value) {
this.opacity = value;
this.canvas.contextTop.globalAlpha = value;
},
onMouseDown: function(pointer) {
this._point = new fabric.Point(pointer.x, pointer.y);
this._lastPoint = this._point;
this.size = this.width + this._baseWidth;
this._strokeId = +new Date();
this._inkAmount = 0;
this.changeColor(this.color);
this._render();
},
onMouseMove: function(pointer) {
this._lastPoint = this._point;
this._point = new fabric.Point(pointer.x, pointer.y);
},
onMouseUp: function(pointer) {
},
_render: function() {
var context = this;
setTimeout(draw, this._interval);
function draw() {
var point, distance, angle, amount, x, y;
point = new fabric.Point(context._point.x || 0, context._point.y || 0);
distance = point.distanceFrom(context._lastPoint);
angle = point.angleBetween(context._lastPoint);
amount = (100 / context.size) / (Math.pow(distance, 2) + 1);
context._inkAmount += amount;
context._inkAmount = Math.max(context._inkAmount - distance / 10, 0);
if (context._inkAmount > context._dripThreshold) {
context._drips.push(new fabric.Drip(context.canvas.contextTop, point, context._inkAmount / 2, context.color, context._strokeId));
context._inkAmount = 0;
}
x = context._lastPoint.x + Math.sin(angle) - context.size / 2;
y = context._lastPoint.y + Math.cos(angle) - context.size / 2;
context.canvas.contextTop.drawImage(context.brush._element, x, y, context.size, context.size);
if (context.canvas._isCurrentlyDrawing) {
setTimeout(draw, context._interval);
} else {
context._reset();
}
}
},
_reset: function() {
this._drips.length = 0;
this._point = null;
this._lastPoint = null;
}
});
Now, we just need to use this brush in the canvas.
var canvas = new fabric.Canvas('canvas');
canvas.freeDrawingBrush = new fabric.SprayBrush(canvas, { width: 70,opacity: 0.6, color: "transparent" });
If I have some bodies that are repulsed and also have a distance. Right now they bounce back and forth endlessly. Is there a way to add a resistance to the physics engine so that they may come to rest?
var context = Engine.createContext();
var contextSize = context.getSize();
var handler = new EventHandler();
var physicsEngine = new PhysicsEngine();
function addBall(color, i) {
var ball = new Surface ({
size: [50,50],
properties: {
backgroundColor: color,
borderRadius: '100px'
}
});
ball.state = new StateModifier({origin:[0.5,0.5]});
ball.particle = new Circle({radius:50, mass: 20 + i * 1});
return ball;
}
var leftWall = new Wall({normal : [1,0,0], distance : contextSize[0]/2.0, restitution : 0.7});
var rightWall = new Wall({normal : [-1,0,0], distance : contextSize[0]/2.0, restitution : 0.7});
var topWall = new Wall({normal : [0,1,0], distance : contextSize[1]/2.0, restitution : 0.7});
var bottomWall = new Wall({normal : [0,-1,0], distance : contextSize[1]/2.0, restitution : 0.7});
var walls = [leftWall,rightWall,bottomWall,topWall];
var bodies = [];
_.each(['yellow', 'blue','green', 'red', 'orange', 'purple','gray', 'black'],function(color, index) {
var body = addBall(color, index);
bodies.push(body);
});
_.each(bodies, function (body) {
physicsEngine.addBody(body.particle);
context.add(body.state).add(body);
});
var particles = _.map(bodies, function(body){
return body.particle;
});
_.each(particles, function(particle, index){
var r = new Repulsion({strength: 61});
var d = new Distance({length: 80, minLength: 0});
physicsEngine.attach(r, [particles[(index + 4) % 8]], particle);
physicsEngine.attach(r, [particle], particles[(index + 4) % 8]);
physicsEngine.attach(d, [particles[(index + 1) % 8]], particle);
if (index == 0) {
physicsEngine.attach(d, [particle], particles[7]);
} else {
physicsEngine.attach(d, [particle], particles[(index - 1) % 8]);
}
particle.setVelocity([0.004101*index,0.004101*index,0 ]);
});
_.each(walls, function(wall) {
physicsEngine.attach(wall);
});
Engine.on('prerender', function(){
_.each(bodies, function(body) {
body.state.setTransform(body.particle.getTransform());
});
});
I was looking for Drag!
var drag = new Drag({strength: 0.1})
physicsEngine.attach(drag, [particle]);
Hi,
i have a european raphael map.Now I would like to plot points on
certain cities in the map.i tried by converting latitude n longitude
to plot points in it.But unfortunately it is plotting somewhere
else.is it like we should have world map to plot points??here is my
code.
script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var rsr = Raphael('map', '631', '686');
var attr = {
fill: "#C0C0C0",
stroke: "#666",
"stroke-width": 1,
"stroke-linejoin": "round"
};
var world = {};
world.Portugal = rsr.path("56,0.133-1.32,0.527c-0.661,1.321-0.264,2.906- 0.925,4.228c-0.528,1.057-3.698,5.415-3.434,6.868c0.132,0.526,1.056-0.529,1.584-0.529c0.792-0.132,1.585,0.133,2.377,0c0.396,0,0.792-0.396,1.188-0.264
c2.113,0.527,8.981,5.019,9.906,4.887c0.396,0,4.49-1.981,4.754-2.113C57.876,621.536,58.537,621.536,59.197,621.536L59.197,621.536
z").attr(attr);
world.Spain = rsr.path(" M194.57,552.728c0.924,0.396,1.981,0.63.434,4.754c-,0,0.792,0 c0.661,0.133,1.453,0.133,1.849,0.528c0.66,0.528,0.264,1.717,0.924,2.113v0.132C190.74,552.066,190.476,553.916,194.57,552.728
L194.57,552.728z").attr(attr);
var current = null;
for(var country in world) {
(function (st, country) {
country = country.toLowerCase();
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill:"#808080", stroke: "#ccc"}, 500);
};
st[0].onmouseout = function () {
st.animate({fill: "#C0C0C0", stroke: "#666"}, 500);
st.toFront();
R.safari();
};
st[0].onclick = function () {
st.toFront();
st.animate({
fill: '#808080',
transform: 's1.5 '
}, 1000);
};
})(world[country], country);
}
});
var cities = {};//here i define the cities with lat n long but both draws in thesame point all time
cities.rome = plot(55.70466,13.19101,1);
cities.copenhagen = plot(55.676097,12.568337,1);
var city_attr = {
fill:"#FF7F50",
stroke:"#666",
opacity: .3
};
function plot(lat,lon,size) {
size = size * .5 + 4;
return rsr.circle(lon2x(lon),lat2y(lat),size).attr(city_attr);
}
function lon2x(lon) {
var xfactor = 1.5255;
var xoffset = 263.58;
var x = (lon * xfactor) + xoffset;
return x; } function lat2y(lat) {
var yfactor = -1.5255;
var yoffset = 130.5;
var y = (lat * yfactor) + yoffset;
return y; }
});
var myMarker = rsr.ellipse(513.859,35.333, 7, 7).attr({
stroke: "none",
opacity: .7,
fill: "#f00"
});
The coordinates in which the map is coded seem rather arbitrary. If that is so, there is no [easy] way to determine the mapping automatically. I would suggest taking a bounding box of the vector image in it's own coordinate system and a corresponding bounding box in lat/long coordinates on a regular map and deriving the mapping from that, at least as a first approximation.