I am working with raphael.js, my question is: Is it possible to generate
a raphael drawing panel dynamically with a button? So far I've tried to
do that with createElement but it did not work.
Here is script using raphael.js
var g_masterPathArray;
var g_masterDrawingBox;
var g_masterPaper;
function initDrawing() {
var g_masterPaper = Raphael(10, 10, 700, 500);
var masterBackground = g_masterPaper.rect(10, 10, 600, 400);
masterBackground.attr("fill", "#eee");
masterBackground.mousemove(function (event) {
var evt = event;
var IE = document.all ? true : false;
var x, y;
if (IE) {
x = evt.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = evt.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
else {
x = evt.pageX;
y = evt.pageY;
}
// subtract paper coords on page
this.ox = x - 10;
this.oy = y - 10;
});
var start = function () {
g_masterPathArray = new Array();
},
move = function (dx, dy) {
if (g_masterPathArray.length == 0) {
g_masterPathArray[0] = ["M", this.ox, this.oy];
g_masterDrawingBox = g_masterPaper.path(g_masterPathArray);
g_masterDrawingBox.attr({ stroke: "#000000", "stroke-width": 3 });
}
else
g_masterPathArray[g_masterPathArray.length] = ["L", this.ox, this.oy];
g_masterDrawingBox.attr({ path: g_masterPathArray });
},
up = function () {
;
};
masterBackground.drag(move, start, up);
return g_masterPaper;
}
I've defined a generate() function but I am not sure about the
elements that I have to create so far. Any ideas?
Try this:
html:
<div id="container"></div>
<input type="button" id="button" value="Clear" />
<input type="button" id="generate" value="Generate" />
js:
function generate(){
var self = this;
self.CurrentFreeID = 0;
self.newCanvas = {};
self.Papers = [];
self.Container = document.getElementById('container');
self.doGenerate = function (){
self.newCanvas = document.createElement('div');
self.Container.appendChild(self.newCanvas);
self.newCanvas.id = 'someID'+self.CurrentFreeID.toString();
self.Papers.push(Raphael(self.newCanvas.id,200,200));
self.Papers[ self.CurrentFreeID].rect(10,10,10,10);
self.CurrentFreeID++;
};
self.Init=function (){
document.getElementById('generate').onclick = self.doGenerate;
};
}
var gener = new generate();
gener.Init();
http://jsfiddle.net/xNSVm/4/
Related
I want to have onclick and hover functionality simultaneously but if you have clicked somewhere then hover should not work until I click somewhere else. I have tried alot but I didn't find any working code. Kindly help
canvas.addEventListener('mousedown', function(evt) {
}, false);
canvas.onmousemove = function(evt) {
};
Well, I am not quite sure what you need and why you need it. But, in that short piece of code you wrote I saw the word "canvas" and thought "what the heck, that could be fun!". I have not much experience with the canvas element since earlier, so I realize there may be better ways of writing this code.
But, I hope what I wrote in the below example is at least close to what you were looking for. Otherwise, go nuts and change and adapt the way you like... and while you do that, try to learn something of it.
var Canvas = function() {
this.$canvas = $('canvas');
this.$currPos = $('#currPos');
this.$currClick = $('#currClick');
this.$clickInfo = $('#clickInfo');
this.canvsWidth = 150;
this.cavasHeight = 150;
this.ctx = ctx = this.$canvas[0].getContext('2d');
this.rect = this.$canvas[0].getBoundingClientRect();
this.squares = [];
this.sqm = 50;
this.tracker = 0;
this.latestHover = {};
this._events();
this._prepare();
};
Canvas.prototype._events = function() {
var self = this;
this.$canvas.on('mousemove', function(e) {
var posX = e.clientX - self.rect.left,
posY = e.clientY - self.rect.top,
newX = Math.floor(posX / self.sqm),
newY = Math.floor(posY / self.sqm);
if($.isEmptyObject(self.latestHover) || (self.latestHover.x !== newX || self.latestHover.y !== newY)) {
self.latestHover.x = newX;
self.latestHover.y = newY;
self.squares.map(function(k, v) {
let obj = self.squares[v];
if(!obj.fixedBackground) obj.reverseBackgroundColor();
});
var square = self.findObject(newX, newY)[0];
if(square) {
square.setBackgroundColor('#ff0000');
self.$currPos.html(newX +'x'+ newY);
self._redraw();
}
}
});
this.$canvas.on('click', function() {
if(self.tracker === 2) {
return self._reset();
}
if(!($.isEmptyObject(self.latestHover))) {
var x = self.latestHover.x,
y = self.latestHover.y;
var square = self.findObject(x, y)[0];
square.setFixedBackground();
self.$currClick.html(x +'x'+ y);
self.setTracker();
}
});
};
Canvas.prototype._prepare = function() {
for(var row = 0; row < 3; row++) {
for(var col = 0; col < 3; col++) {
this.squares.push(new Square(row, col, this.ctx, this.sqm));
}
}
};
Canvas.prototype._redraw = function() {
var self = this;
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.squares.filter(function(k, v) {
self.squares[v].draw();
});
};
Canvas.prototype.setTracker = function() {
this.tracker++;
if(this.tracker === 2) this.$clickInfo.html('Click one more time to start over');
};
Canvas.prototype.findObject = function(x, y) {
var self = this;
return square = self.squares.filter(function(k, v) {
var obj = self.squares[v];
if(obj.posX === x && obj.posY === y) return obj;
});
};
Canvas.prototype._reset = function() {
var self = this;
this.squares.map(function(k, v) {
let obj = self.squares[v];
obj.reverseBackgroundColor();
obj.unsetFixedBackground();
});
this.$currClick.html('');
this.$clickInfo.html('');
this.tracker = 0;
this._redraw();
};
var Square = function(x, y, ctx, sqm) {
this.ctx = ctx;
this.sqm = sqm;
this.posX = x;
this.posY = y;
this.background = '#fff';
this.strokeThickness = 1;
this.fixedBackground = false;
this.draw();
};
Square.prototype.setBackgroundColor = function(color) {
return this.background = color;
};
Square.prototype.reverseBackgroundColor = function() {
return this.background = '#fff';
};
Square.prototype.setFixedBackground = function() {
return this.fixedBackground = true;
};
Square.prototype.unsetFixedBackground = function() {
return this.fixedBackground = false;
};
Square.prototype.draw = function() {
this.ctx.fillStyle = this.background;
this.ctx.fillRect(this.posX * this.sqm, this.posY * this.sqm, this.sqm, this.sqm);
this.ctx.strokeRect(this.posX * this.sqm, this.posY * this.sqm, this.sqm, this.sqm);
};
window.Canvas = new Canvas();
canvas {
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas width="150" height="150"></canvas>
<div>
Current position: <span id="currPos"></span> <br/>
Last click: <span id="currClick"></span> <span id="clickInfo"></span>
</div>
I'm new to JavaScript, so this may be basic...
I'm trying to create an image dynamically and add it a event listener for "onclick". I add this img to a div.
I create the img like this:
function createNewSmiley()
{
var newSmiley = document.createElement("img");
newSmiley.src = "./smiley.jpg";
newSmiley.alt = "Smiley Image";
newSmiley.style.width = "64px";
newSmiley.style.height = "64px";
return newSmiley;
}
And then I add it to the div like using like this:
function positionNewSmiley(parent, smiley, x, y)
{
var newSmiley = createNewSmiley();
newSmiley.style.top = y + "px";
newSmiley.style.left = x + "px";
parent.appendChild(newSmiley);
}
And this is my main function:
function main(smileyCount)
{
var myDiv = document.getElementById("myDiv");
for (var i = 0; i < smileyCount;i++)
{
var x = Math.floor((Math.random() * 500));
var y = Math.floor((Math.random() * 500));
var smiley = createNewSmiley();
smiley.onclick = smileyClicked;
positionNewSmiley(myDiv, smiley, x, y);
}
}
function smileyClicked(ev) {
alert("OK");
}
But the onclick event will not fire!
however, if I add the event listener to the div - it will.
What am I doing wrong?
As mentioned in the above comment you're creating new smiley in the positionNewSmiley when you've to position the passed smiley instead :
var smiley = createNewSmiley();
smiley.onclick = smileyClicked;
positionNewSmiley(myDiv, smiley, x, y);
_________________________^^^^^^
Just use it in the position function :
function positionNewSmiley(parent, smiley, x, y)
{
smiley.style.top = y + "px";
smiley.style.left = x + "px";
parent.appendChild(smiley);
}
Hope this helps.
function createNewSmiley()
{
var newSmiley = document.createElement("img");
newSmiley.src = "http://cfile24.uf.tistory.com/image/163BB51F4BF9DF7431AB10";
newSmiley.alt = "Smiley Image";
newSmiley.style.width = "64px";
newSmiley.style.height = "64px";
return newSmiley;
}
function positionNewSmiley(parent, smiley, x, y)
{
smiley.style.top = y + "px";
smiley.style.left = x + "px";
parent.appendChild(smiley);
}
function main(smileyCount)
{
var myDiv = document.getElementById("myDiv");
for (var i = 0; i < smileyCount;i++)
{
var x = Math.floor((Math.random() * 500));
var y = Math.floor((Math.random() * 500));
var smiley = createNewSmiley();
smiley.onclick = smileyClicked;
positionNewSmiley(myDiv, smiley, x, y);
}
}
function smileyClicked(ev) {
alert("OK");
}
main(6);
<div id='myDiv'></div>
if you add the on click within the create function it will work
function createNewSmiley()
{
var newSmiley = document.createElement("img");
newSmiley.src = "./smiley.jpg";
newSmiley.alt = "Smiley Image";
newSmiley.style.width = "64px";
newSmiley.style.height = "64px";
newSmiley.addEventListener("click", smileyClicked);
return newSmiley;
}
I want to make a rectangular move by click on a button and stop it clicking on the same button. Here is a part of my code:
document.getElementById("startStop").addEventListener("click", changePlace);
function changePlace() {
nIntervMove = setInterval(movement, 100);
};
var tmp1 = 0;
function movement() {
var oElem = document.getElementById("colorRectangular");
oElem.getPropertyValue = tmp1;
tmp1 += "10px";
};
function stopMove(){
clearInterval(nIntervMove);
};
Pretty straight forward:
var makeMove = function(x, hx, t, complete) {
var target = document.getElementById('rect'),
dx = 0,
d = setInterval(function() {
target.style.left = dx + "px";
dx += hx;
if(dx >= x) {
clearInterval(d);
complete();
}
}, t);
};
makeMove(100, 5, 500, function() {
alert('done');
});
JSFiddle: http://jsfiddle.net/8ay9cqmd/
Is there a way to stop users on dragging the mouse down so they only can click instead of click and drag. I want htem to be only to draw dots on the canvas or any pattern i define similar to a stamp tool.
function Sketcher( canvasID, brushImage ) {
this.renderFunction = (brushImage == null || brushImage == undefined) ? this.updateCanvasByLine : this.updateCanvasByBrush;
this.brush = brushImage;
this.touchSupported = Modernizr.touch;
this.canvasID = canvasID;
this.canvas = $("#"+canvasID);
this.context = this.canvas.get(0).getContext("2d");
this.context.strokeStyle = "#000000";
this.context.lineWidth = 3;
this.lastMousePoint = {x:0, y:0};
if (this.touchSupported) {
this.mouseDownEvent = "touchstart";
this.mouseMoveEvent = "touchmove";
this.mouseUpEvent = "touchend";
}
else {
this.mouseDownEvent = "mousedown";
this.mouseMoveEvent = "mousemove";
this.mouseUpEvent = "mouseup";
}
this.canvas.bind( this.mouseDownEvent, this.onCanvasMouseDown() );
}
Sketcher.prototype.onCanvasMouseDown = function () {
var self = this;
return function(event) {
self.mouseMoveHandler = self.onCanvasMouseMove()
self.mouseUpHandler = self.onCanvasMouseUp()
$(document).bind( self.mouseMoveEvent, self.mouseMoveHandler );
$(document).bind( self.mouseUpEvent, self.mouseUpHandler );
self.updateMousePosition( event );
self.renderFunction( event );
}
}
Sketcher.prototype.onCanvasMouseMove = function () {
var self = this;
return function(event) {
self.renderFunction( event );
event.preventDefault();
return false;
}
}
Sketcher.prototype.onCanvasMouseUp = function (event) {
var self = this;
return function(event) {
$(document).unbind( self.mouseMoveEvent, self.mouseMoveHandler );
$(document).unbind( self.mouseUpEvent, self.mouseUpHandler );
self.mouseMoveHandler = null;
self.mouseUpHandler = null;
}
}
Sketcher.prototype.updateMousePosition = function (event) {
var target;
if (this.touchSupported) {
target = event.originalEvent.touches[0]
}
else {
target = event;
}
var offset = this.canvas.offset();
this.lastMousePoint.x = target.pageX - offset.left;
this.lastMousePoint.y = target.pageY - offset.top;
}
Sketcher.prototype.updateCanvasByLine = function (event) {
this.context.beginPath();
this.context.moveTo( this.lastMousePoint.x, this.lastMousePoint.y );
this.updateMousePosition( event );
this.context.lineTo( this.lastMousePoint.x, this.lastMousePoint.y );
this.context.stroke();
}
Sketcher.prototype.updateCanvasByBrush = function (event) {
var halfBrushW = this.brush.width/2;
var halfBrushH = this.brush.height/2;
var start = { x:this.lastMousePoint.x, y: this.lastMousePoint.y };
this.updateMousePosition( event );
var end = { x:this.lastMousePoint.x, y: this.lastMousePoint.y };
var distance = parseInt( Trig.distanceBetween2Points( start, end ) );
var angle = Trig.angleBetween2Points( start, end );
var x,y;
for ( var z=0; (z<=distance || z==0); z++ )
{
x = start.x + (Math.sin(angle) * z) - halfBrushW;
y = start.y + (Math.cos(angle) * z) - halfBrushH;
//console.log( x, y, angle, z );
this.context.drawImage(this.brush, x, y);
}
}
Sketcher.prototype.toString = function () {
var dataString = this.canvas.get(0).toDataURL("image/png");
var index = dataString.indexOf( "," )+1;
dataString = dataString.substring( index );
return dataString;
}
Sketcher.prototype.toDataURL = function () {
var dataString = this.canvas.get(0).toDataURL("image/png");
return dataString;
}
Sketcher.prototype.clear = function () {
var c = this.canvas[0];
this.context.clearRect( 0, 0, c.width, c.height );
}
You can achieve this by simply ignoring the mousemove and mouseup event handlers by either not initializing them or using flags to indicate that you are in stamp mode.
All you need is:
canvas.onmousedown = function(e) {
var pos = getMousePos(e);
render(pos.x, pos.y);
}
That's it, and it works similar for touch events.
To use flag (I would not recommend adding and removing handlers all the time):
var isStampMode = true;
canvas.onmousemove = function(e) {
if (isStampMode) return;
...
}
and similar for mouse up (but not really necessary unless it depends on what you do in mousedown).
Live example here
Hope this helps!
I am trying to get the distance between my character and the ground, I have found something that looks like it should do what I want but it has been written for another version of box2d.
Original:
float targetHeight = 3;
float springConstant = 100;
//make the ray at least as long as the target distance
b2Vec2 startOfRay = m_hovercarBody->GetPosition();
b2Vec2 endOfRay = m_hovercarBody->GetWorldPoint( b2Vec2(0,-5) );
overcarRayCastClosestCallback callback;
m_world->RayCast(&callback, startOfRay, endOfRay);
if ( callback.m_hit ) {
float distanceAboveGround = (startOfRay - callback.m_point).Length();
//dont do anything if too far above ground
if ( distanceAboveGround < targetHeight ) {
float distanceAwayFromTargetHeight = targetHeight - distanceAboveGround;
m_hovercarBody->ApplyForce( b2Vec2(0,springConstant*distanceAwayFromTargetHeight),
m_hovercarBody->GetWorldCenter() );
}
}
I have tried to change it to what I think it should be but it doesn't even call the callback.
var targetHeight = 3;
var springConstant = 100;
//make the ray at least as long as the target distance
startOfRay = new b2Vec2(m_hovercarBody.GetPosition());
endOfRay = new b2Vec(m_hovercarBody.GetWorldPoint( b2Vec2(0,-5)));
function callback(raycast){
if ( raycast.m_hit ) {
var distanceAboveGround = (startOfRay - raycast.m_point).Length();
//dont do anything if too far above ground
if ( distanceAboveGround < targetHeight ) {
var distanceAwayFromTargetHeight = targetHeight - distanceAboveGround;
m_hovercarBody.ApplyForce( b2Vec2(0,springConstant*distanceAwayFromTargetHeight),
m_hovercarBody.GetWorldCenter() );
}
}
}
m_world.RayCast(callback, startOfRay, endOfRay);
Any idea how to convert it to work with box2dweb?
Thanks
It might be that the original bit of code was written for a platform where the coordinate system works differently.
In a Canvas element, the coordinate system starts from the top left corner, meaning that m_hovercarBody.GetWorldPoint( b2Vec2(0,-5)) is checking for a point above the character, rather than below.
I'm not sure about the rest of the code but try changing that to m_hovercarBody.GetWorldPoint( b2Vec2(0,5)) and see what happens.
EDIT:
I think actually the problem is with the way you've structured your callback. Looking up the reference for the Raycast function would reveal more.
(The Javascript version of Box2D you're using is an automatic port of the Actionscript one. Given the two have fairly similar syntax, you can use the reference for Flash.)
The original code you posted seems to be C++, but I don't know much about its syntax. It seems there's some sort of class that does the raycasting (overcarRayCastClosestCallback). You can either look for that, or try and build your own callback function according to the first link I posted. It would be something along the lines of:
function customRaycastCallback(fixture, normal, fraction) {
// you can, for instance, check if fixture belongs to the ground
// or something else, then handle things accordingly
if( /* fixture belongs to ground */ ) {
// you've got the fraction of the original length of the raycast!
// you can use this to determine the distance
// between the character and the ground
return fraction;
}
else {
// continue looking
return 1;
}
}
Try running this on your browser. I coded this when I was learning sensor and RAYCAST in Box2Dweb. Hope it helps.
<html>
<head>
<title>Box2dWeb Demo</title>
</head>
<body>
<canvas id="canvas" width="600" height="420" style="background-color:#333333;" ></canvas>
<div id="cc" style="position:absolute; right:0; top:100px; width:500px; height:50px; margin:0;"></div>
</body>
<script type="text/javascript" src="Box2dWeb-2.1.a.3.js"></script>
<script type="text/javascript" src="jquery-1.7.2.js"></script>
<script type="text/javascript">
var b2Vec2 = Box2D.Common.Math.b2Vec2
, b2BodyDef = Box2D.Dynamics.b2BodyDef
, b2Body = Box2D.Dynamics.b2Body
, b2FixtureDef = Box2D.Dynamics.b2FixtureDef
, b2World = Box2D.Dynamics.b2World
, b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
, b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
, b2ContactFilter = Box2D.Dynamics.b2ContactFilter
, b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef
, b2DebugDraw = Box2D.Dynamics.b2DebugDraw
, b2Fixture = Box2D.Dynamics.b2Fixture
, b2AABB = Box2D.Collision.b2AABB
, b2WorldManifold = Box2D.Collision.b2WorldManifold
, b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint
, b2RayCastInput = Box2D.Collision.b2RayCastInput
, b2RayCastOutput = Box2D.Collision.b2RayCastOutput
, b2Color = Box2D.Common.b2Color;
var world = new b2World(new b2Vec2(0,10), true);
var canvas = $('#canvas');
var context = canvas.get(0).getContext('2d');
//box
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(9,7);
bodyDef.userData = 'box';
var fixDef = new b2FixtureDef;
fixDef.filter.categoryBits = 1;
fixDef.density = 10.0;
fixDef.friction = 0.5;
fixDef.restitution = .5;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(1,5);
var box1 = world.CreateBody(bodyDef);
box1.CreateFixture(fixDef);
//circle
var bodyDef2 = new b2BodyDef;
bodyDef2.type = b2Body.b2_dynamicBody;
bodyDef2.position.Set(4,8);
bodyDef2.userData = 'obj';
var fixDef2 = new b2FixtureDef;
fixDef2.filter.categoryBits = 2;
fixDef2.filter.maskBits = 13;
fixDef2.density = 10.0;
fixDef2.friction = 0.5;
fixDef2.restitution = .2;
fixDef2.shape = new b2CircleShape(1);
//circlesensor
var cc = new b2FixtureDef;
cc.shape = new b2CircleShape(2);
cc.shape.SetLocalPosition(new b2Vec2(0 ,0));
cc.density = 0;
cc.isSensor = true;
cc.filter.categoryBits = 8;
var wheel = world.CreateBody(bodyDef2);
wheel.CreateFixture(fixDef2);
wheel.CreateFixture(cc);
//create a ground
var holderDef = new b2BodyDef;
holderDef.type = b2Body.b2_staticBody;
holderDef.userData = "ground";
holderDef.position.Set(10, 14);
var fd = new b2FixtureDef;
fd.filter.categoryBits = 4;
fd.shape = new b2PolygonShape;
fd.shape.SetAsBox(10,1);
var ground = world.CreateBody(holderDef);
ground.CreateFixture(fd);
//create another static body
var holderDef = new b2BodyDef;
holderDef.type = b2Body.b2_staticBody;
holderDef.position.Set(10, 20);
var temp = world.CreateBody(holderDef);
temp.CreateFixture(fd);
var c=0;
$(window).keydown(function(e) {
$('#aa').html(++c);
code = e.keyCode;
if(c==1) {
if(code == 38 && onground)
wheel.SetLinearVelocity(new b2Vec2(0,-10));
if(code == 39)
wheel.ApplyForce(new b2Vec2(1000,0), box1.GetWorldPoint(new b2Vec2(0,0)));
if(code == 37)
wheel.ApplyForce(new b2Vec2(-1000,0), box1.GetWorldPoint(new b2Vec2(0,0)));
}
});
$(window).keyup(function(e) {
c=0;
});
var listener = new Box2D.Dynamics.b2ContactListener;
listener.BeginContact = function(contact) {
if(contact.GetFixtureA().GetBody().GetUserData()== 'obj' || contact.GetFixtureB().GetBody().GetUserData()== 'obj' ) // think about why we don't use fixture's userData directly.
onground = true;// don't put 'var' here!
fxA=contact.GetFixtureA();
fxB=contact.GetFixtureB();
sA=fxA.IsSensor();
sB=fxB.IsSensor();
if((sA && !sB) || (sB && !sA)) {
if(sA) {
$('#cc').prepend(contact.GetFixtureB().GetBody().GetUserData() + ' is in the viscinity of body '+contact.GetFixtureA().GetBody().GetUserData()+'<br>');
}
else {
$('#cc').prepend(contact.GetFixtureA().GetBody().GetUserData() + ' is in the viscinity of body '+contact.GetFixtureB().GetBody().GetUserData()+'<br>');
}
}
}
listener.EndContact = function(contact) {
if (contact.GetFixtureA().GetBody().GetUserData()== 'obj' || contact.GetFixtureB().GetBody().GetUserData()== 'obj' )
onground = false;
}
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite ( document.getElementById ("canvas").getContext ("2d"));
debugDraw.SetDrawScale(30); //define scale
debugDraw.SetAlpha(1);
debugDraw.SetFillAlpha(.3); //define transparency
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
window.setInterval(update,1000/60);
//mouse
var mouseX, mouseY, mousePVec, isMouseDown, selectedBody, mouseJoint;
var canvasPosition = getElementPosition(document.getElementById("canvas"));
document.addEventListener("mousedown", function(e) {
isMouseDown = true;
handleMouseMove(e);
document.addEventListener("mousemove", handleMouseMove, true);
}, true);
document.addEventListener("mouseup", function() {
document.removeEventListener("mousemove", handleMouseMove, true);
isMouseDown = false;
mouseX = undefined;
mouseY = undefined;
}, true);
function handleMouseMove(e) {
mouseX = (e.clientX - canvasPosition.x) / 30;
mouseY = (e.clientY - canvasPosition.y) / 30;
};
function getBodyAtMouse() {
mousePVec = new b2Vec2(mouseX, mouseY);
var aabb = new b2AABB();
aabb.lowerBound.Set(mouseX - 0.001, mouseY - 0.001);
aabb.upperBound.Set(mouseX + 0.001, mouseY + 0.001);
// Query the world for overlapping shapes.
selectedBody = null;
world.QueryAABB(getBodyCB, aabb);
return selectedBody;
}
function getBodyCB(fixture) {
if(fixture.GetBody().GetType() != b2Body.b2_staticBody) {
if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), mousePVec)) {
selectedBody = fixture.GetBody();
return false;
}
}
return true;
}
//at global scope
var currentRayAngle = 0;
var input = new b2RayCastInput();
var output = new b2RayCastOutput();
var b = new b2BodyDef();
var f = new b2FixtureDef();
var closestFraction = 1;
var intersectionNormal = new b2Vec2(0,0);
var intersectionPoint = new b2Vec2();
rayLength = 25; //long enough to hit the walls
var p1 = new b2Vec2( 11, 7 ); //center of scene
var p2 = new b2Vec2();
var normalEnd = new b2Vec2();
function update() {
if(isMouseDown && (!mouseJoint)) {
var body = getBodyAtMouse();
if(body) {
var md = new b2MouseJointDef();
md.bodyA = world.GetGroundBody();
md.bodyB = body;
md.target.Set(mouseX, mouseY);
md.collideConnected = true;
md.maxForce = 300.0 * body.GetMass();
mouseJoint = world.CreateJoint(md);
body.SetAwake(true);
}
}
if(mouseJoint) {
if(isMouseDown) {
mouseJoint.SetTarget(new b2Vec2(mouseX, mouseY));
} else {
world.DestroyJoint(mouseJoint);
mouseJoint = null;
}
}
world.Step(1 / 60, 10, 10);
world.DrawDebugData();
world.ClearForces();
world.SetContactListener(listener);
ray();
};
function ray() {
//in Step() function
var k = 360/20;
var t = k/60;
var DEGTORAD = Math.PI/180;
currentRayAngle += t * DEGTORAD; //one revolution every 20 seconds
//console.log(currentRayAngle*(180/Math.PI));
//calculate points of ray
p2.x = p1.x + rayLength * Math.sin(currentRayAngle);
p2.y = p1.y + rayLength * Math.cos(currentRayAngle);
input.p1 = p1;
input.p2 = p2;
input.maxFraction = 1;
closestFraction = 1;
var b = new b2BodyDef();
var f = new b2FixtureDef();
for(b = world.GetBodyList(); b; b = b.GetNext()) {
for(f = b.GetFixtureList(); f; f = f.GetNext()) {
if(!f.RayCast(output, input))
continue;
else if(output.fraction < closestFraction) {
closestFraction = output.fraction;
intersectionNormal = output.normal;
}
}
}
intersectionPoint.x = p1.x + closestFraction * (p2.x - p1.x);
intersectionPoint.y = p1.y + closestFraction * (p2.y - p1.y);
normalEnd.x = intersectionPoint.x + intersectionNormal.x;
normalEnd.y = intersectionPoint.y + intersectionNormal.y;
context.strokeStyle = "rgb(255, 255, 255)";
context.beginPath(); // Start the path
context.moveTo(p1.x*30,p1.y*30); // Set the path origin
context.lineTo(intersectionPoint.x*30, intersectionPoint.y*30); // Set the path destination
context.closePath(); // Close the path
context.stroke();
context.beginPath(); // Start the path
context.moveTo(intersectionPoint.x*30, intersectionPoint.y*30); // Set the path origin
context.lineTo(normalEnd.x*30, normalEnd.y*30); // Set the path destination
context.closePath(); // Close the path
context.stroke(); // Outline the path
}
//helpers
//http://js-tut.aardon.de/js-tut/tutorial/position.html
function getElementPosition(element) {
var elem=element, tagname="", x=0, y=0;
while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) {
y += elem.offsetTop;
x += elem.offsetLeft;
tagname = elem.tagName.toUpperCase();
if(tagname == "BODY")
elem=0;
if(typeof(elem) == "object") {
if(typeof(elem.offsetParent) == "object")
elem = elem.offsetParent;
}
}
return {x: x, y: y};
}
</script>
</html>
Here's a Raycast in Box2dWeb that I got working:
var p1 = new b2Vec2(body.GetPosition().x, body.GetPosition().y); //center of scene
var p2 = new b2Vec2(body.GetPosition().x, body.GetPosition().y + 5); //center of scene
world.RayCast(function(x){
console.log("You've got something under you");
}, p1,p2);