three.js rotate object on mouse down and move - javascript

I'm trying to get a good mouse movement in my scene so I can rotate around the object.
I have two problems, I can figure out how to limit the movement so that it never rotates below 0 degrees on the Y axis. (I dont want to see the object from below, only above)
And the second thing I can't figure out is how to make the movement smooth. Now with what I have achieved in the jsfiddle is that the camera moves back to its starting position before starting to rotate.
My try: http://jsfiddle.net/phacer/FHD8W/4/
This is the part I dont get:
var spdy = (HEIGHT_S / 2 - mouseY) / 100;
var spdx = (WIDTH / 2 - mouseX) / 100;
root.rotation.x += -(spdy/10);
root.rotation.y += -(spdx/10);
What I want without using an extra library: http://www.mrdoob.com/projects/voxels/#A/afeYl

You can rotate you scene with this code,
To ensure to not rotate under 0, simule rotation of a vector (0,0,1) and check if y of vector is negative
var mouseDown = false,
mouseX = 0,
mouseY = 0;
function onMouseMove(evt) {
if (!mouseDown) {
return;
}
evt.preventDefault();
var deltaX = evt.clientX - mouseX,
deltaY = evt.clientY - mouseY;
mouseX = evt.clientX;
mouseY = evt.clientY;
rotateScene(deltaX, deltaY);
}
function onMouseDown(evt) {
evt.preventDefault();
mouseDown = true;
mouseX = evt.clientX;
mouseY = evt.clientY;
}
function onMouseUp(evt) {
evt.preventDefault();
mouseDown = false;
}
function addMouseHandler(canvas) {
canvas.addEventListener('mousemove', function (e) {
onMouseMove(e);
}, false);
canvas.addEventListener('mousedown', function (e) {
onMouseDown(e);
}, false);
canvas.addEventListener('mouseup', function (e) {
onMouseUp(e);
}, false);
}
function rotateScene(deltaX, deltaY) {
root.rotation.y += deltaX / 100;
root.rotation.x += deltaY / 100;
}

Related

Touchend will cancel on canvas and doesnt fires

I have a weird problem. I'm creating a test game.Which uses touch events and canvas.There is a ball that you can push it and when you release your finger it must go(something like angry birds).
I made that in mouse and it work correctly.I wanna make it on android. But it doesn't run.But when you use 2 finger it works correctly.
I'm sure the problem is here :
canvas.addEventListener("touchstart",function(event){
event.preventDefault();
if (event.touches[0].clientX >= x && event.touches[0].clientX <= x + (radius * 2) && event.touches[0].clientY >= y && event.touches[0].clientY <= y + (radius * 2)) {
dx = 0;
dy = 0;
isindrag = true;
oldx = x;
oldy = y;
}
});
canvas.addEventListener("touchmove", function (event) {
event.preventDefault();
if (isindrag) {
x = event.touches[0].clientX;
y = event.touches[0].clientY;
}
});
canvas.addEventListener("touchend", function (event) {
var touchX = event.touches[0].clientX;
var touchY = event.touches[0].clientY;
if (isindrag && touchX < canvas.width && touchY < canvas.height && touchX > 0 && touchY > 0) {
isindrag = false;
dx = -(x - oldx) / 30;
dy = -(y - oldy) / 30;
ismoving = true;
}
});
canvas.addEventListener("touchcancel", function(event){
event.preventDefault();
});
x : x of ball
y : y of ball
dx : Delta x of ball
dy : delta y of ball
radius : radius of ball
Can you help me?
The touches object of a touch event contains a collection of points currently on the screen. Now imagine that you put a single finger onto the surface and release it. This will trigger a touchend event but as the touches object just contains information on the active 'fingers', it will come up empty thus there is no clientX or clientY property to query. In a touchend event handler you need to use changedTouches instead of touches.
So try changing
var touchX = event.touches[0].clientX;
var touchY = event.touches[0].clientY;
to
var touchX = event.changedTouches[0].clientX;
var touchY = event.changedTouches[0].clientY;

Html5 Canvas - dynamic table pushed canvas down and now the draw/image is not showing

I am using HTML5 Canvas with JavaScript. In the HTML layout, the canvas has a dynamic table above it. The table size is not static and changes at run-time depending on the parameter given. The problem I have is that when the table becomes long, it pushes the canvas down and the drawn image no longer shows. I know the drawn image is there because when I apply the following style code:
canvas {
position: absolute;
top: 0px;
left: 0px
}
the canvas moves to the top and the drawn image appears. Also, when the table is short, the canvas works fine.
I have tried using absolute and relative positioning on the table and canvas elements but that is not helping. I have tried getting the height of the table and applying a margin top to the canvas at run time but that didn't work. I have tried offsets, but they are not working either. I don't know what to do in order to keep the drawn image with the canvas element.
//declare variables
var canvas, context, flag = false;
var offsetX, offsetY;
var prevX; //initial position of mouse along x-axis
var currX; //new position of mouse along x-axis, initially set to 0
var prevY; //initial position of mouse along y axis
var currY; //new position of mouse along y axis, initially set to 0
var dot_draw = false;
var font_color = "black";
function startSignaturePad() {
canvas = document.getElementById('signaturepad'); //get the canvas element
if (canvas) {
context = canvas.getContext("2d"); //get the 2d drawing context
canvas.width = 400;
canvas.height = 150;
width = canvas.width;
height = canvas.height;
}
function reOffset() {
var BB = canvas.getBoundingClientRect();
offsetX = BB.left;
offsetY = BB.top;
}
reOffset();
window.onscroll = function(e) {
reOffset();
}
window.onresize = function(e) {
reOffset();
}
//bind the event listeners to the canvas
canvas.addEventListener("mousemove", function onMouseMove(e) {
getPositionXY('move', e)
}, false);
canvas.addEventListener("mousedown", function onMouseDown(e) {
getPositionXY('down', e)
}, false);
canvas.addEventListener("mouseup", function onMouseUp(e) {
getPositionXY('up', e)
}, false);
canvas.addEventListener("mouseout", function onMouseOut(e) {
getPositionXY('out', e)
}, false);
}
function draw() { //function to draw a dot at a specific position - grabs and then draws the position of x and y
context.beginPath();
context.moveTo(prevX, prevY);
context.lineTo(currX, currY);
context.strokeStyle = font_color;
context.lineWidth = font_size;
context.stroke();
context.closePath();
}
function erase() { //erase what is on the canvas
var erase = confirm("Are you sure you want to erase?");
if (erase) {
context.clearRect(0, 0, width, height);
}
}
function getPositionXY(mouse, e) {
if (mouse == 'down') {
prevX = currX; //reset previous position of x and y
prevY = currY;
currX = (e.clientX - canvas.offsetLeft) < (e.clientX - canvas.offsetX) ? e.clientX - canvas.offsetX : e.clientX - canvas.offsetLeft; //set new position of x and y
currY = (e.clientY - canvas.offsetTop) < (e.clientY - canvas.offsetY) ? e.clientY - canvas.offsetY : e.clientY - canvas.offsetTop;
flag = true;
dot_draw = true;
if (dot_draw) { //draw path while mouse is pressed down
context.textBaseline = "hanging";
context.beginPath();
context.fillStyle = font_color;
context.arc(currX, currY, 2, 0, 2 * Math.PI);
context.closePath();
dot_draw = false;
}
}
if (mouse == 'up' || mouse == "out") {
flag = false; //when mouse is released do nothing
}
if (mouse == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = (e.clientX - canvas.offsetLeft) < (e.clientX - canvas.offsetX) ? e.clientX - canvas.offsetX : e.clientX - canvas.offsetLeft;
currY = (e.clientY - canvas.offsetTop) < (e.clientY - canvas.offsetY) ? e.clientY - canvas.offsetY : e.clientY - canvas.offsetTop;
draw();
}
}
}
canvas {
position: absolute;
top: 0px;
left: 0px
}
<div>
<table>
<!-- some code -->
</table>
</div>
<div id="sigCanvas">
<canvas id="signaturepad" style="border:1px solid;"></canvas>
</div>
Since your canvas can move around, you want the latest position, so get it at the last possible instant.
Since your code works when the canvas is at (0,0), just adding
a call to reOffset() and the very beginning of getPositionXY() might do the trick.
If not, here is how I locate a mouse click relative to the canvas:
function locateMouse(evnt)
{
var x = evnt.pageX;
var y = evnt.pageY;
var c = canvas.getBoundingClientRect();
x = Math.floor(x) - c.left;
y = Math.floor(y) - c.top;
/// then use x and y however you want
}

Use Canvas as pad for multiple range inputs

I'm trying to build an html canvas pad that will allow a user to drag and drop a dot on the pad, which will then return two values (one for Y axis, and one for Y axis), which I can use to trigger effects using the web audio API.
I've already sorted out the web Audio API portion of the problem.
The User:
Clicks and drags the dot to anywhere on the X/Y grid
On Drop we will have an X & Y value (perhaps in hidden range inputs), that trigger eventListeners.
The X value eventListener affects the wet/dry of the delay effect
The Y value eventListener affects the delay_time of the delay effect
so far I've been able to create and render the canvas and circle, and add event listeners on the svg element and the window. With the idea being that I can detect when an event occurs inside the canvas and when that click event leaves the canvas.
// Draw SVG pad
function drawDelayPad() {
var canvas = document.getElementById('delayPad');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var rectangle = new Path2D();
rectangle.rect(1, 1, 200, 200);
var circle = new Path2D();
circle.moveTo(150, 150);
circle.arc(100, 35, 10, 0 , 2 * Math.PI);
ctx.stroke(rectangle);
ctx.fill(circle);
}
}
// Listener on canvas
var canvas = document.getElementById('delayPad');
canvas.addEventListener("mousedown", function(){
console.log("click inside our canvas")
})
// Listener on document to check if we're outside the canvas
window.addEventListener("mouseup", function(){
console.log("outside our canvas")
});
So I think what I need to determine now is that when a click event does occur inside of the canvas, how far it is from the cirle, and if it does fall within the bounds of the circle, I should redraw it as long as the mousedown event is active.
Any help would be greatly appreciated.
I've found a nice little solution that kind of confirms my suspicions surrounding a hit counter! All credit really goes to rectangleWorld since I was for the most part just able to modify the example they had available.
Here's a codepen
// Draw SVG pad
function canvasApp(canvasID) {
var theCanvas = document.getElementById(canvasID);
var context = theCanvas.getContext("2d");
init();
var numShapes;
var shapes;
var dragIndex;
var dragging;
var mouseX;
var mouseY;
var dragHoldX;
var dragHoldY;
function init() {
numShapes = 1;
shapes = [];
makeShapes();
drawScreen();
theCanvas.addEventListener("mousedown", mouseDownListener, false);
}
function makeShapes() {
var i;
var tempX;
var tempY;
var tempRad;
var tempR;
var tempG;
var tempB;
var tempColor;
var tempShape;
for (i = 0; i < numShapes; i++) {
// My canvas element is 240x240
tempRad = 10;
tempX = 0 + tempRad;
tempY = 240 - tempRad;
tempR = Math.floor(Math.random() * 255);
tempG = Math.floor(Math.random() * 255);
tempB = Math.floor(Math.random() * 255);
tempColor = "rgb(" + tempR + "," + tempG + "," + tempB + ")";
tempShape = {
x: tempX,
y: tempY,
rad: tempRad,
color: tempColor
};
shapes.push(tempShape);
}
}
function mouseDownListener(evt) {
var i;
//We are going to pay attention to the layering order of the objects so that if a mouse down occurs over more than object,
//only the topmost one will be dragged.
var highestIndex = -1;
//getting mouse position correctly, being mindful of resizing that may have occured in the browser:
var bRect = theCanvas.getBoundingClientRect();
mouseX = (evt.clientX - bRect.left) * (theCanvas.width / bRect.width);
mouseY = (evt.clientY - bRect.top) * (theCanvas.height / bRect.height);
//find which shape was clicked
for (i = 0; i < numShapes; i++) {
if (hitTest(shapes[i], mouseX, mouseY)) {
dragging = true;
if (i > highestIndex) {
//We will pay attention to the point on the object where the mouse is "holding" the object:
dragHoldX = mouseX - shapes[i].x;
dragHoldY = mouseY - shapes[i].y;
highestIndex = i;
dragIndex = i;
}
}
}
if (dragging) {
window.addEventListener("mousemove", mouseMoveListener, false);
}
theCanvas.removeEventListener("mousedown", mouseDownListener, false);
window.addEventListener("mouseup", mouseUpListener, false);
//code below prevents the mouse down from having an effect on the main browser window:
if (evt.preventDefault) {
evt.preventDefault();
} //standard
else if (evt.returnValue) {
evt.returnValue = false;
} //older IE
return false;
}
function mouseUpListener(evt) {
theCanvas.addEventListener("mousedown", mouseDownListener, false);
window.removeEventListener("mouseup", mouseUpListener, false);
if (dragging) {
dragging = false;
window.removeEventListener("mousemove", mouseMoveListener, false);
}
}
function mouseMoveListener(evt) {
var posX;
var posY;
var shapeRad = shapes[dragIndex].rad;
var minX = shapeRad;
var maxX = theCanvas.width - shapeRad;
var minY = shapeRad;
var maxY = theCanvas.height - shapeRad;
//getting mouse position correctly
var bRect = theCanvas.getBoundingClientRect();
mouseX = (evt.clientX - bRect.left) * (theCanvas.width / bRect.width);
mouseY = (evt.clientY - bRect.top) * (theCanvas.height / bRect.height);
// Divide by width of canvas and multiply to get percentage out of 100
var DelayTime = ((mouseX / 240) * 100);
// Invert returned value to get percentage out of 100
var DelayFeedback = (100 - (mouseY / 240) * 100);
// Set delay time as a portion of 2seconds
delayEffect.delayTime.value = DelayTime / 100 * 2.0;
// set delay feedback gain as value of random number
delayFeedback.gain.value = (DelayFeedback / 100 * 1.0);
//clamp x and y positions to prevent object from dragging outside of canvas
posX = mouseX - dragHoldX;
posX = (posX < minX) ? minX : ((posX > maxX) ? maxX : posX);
posY = mouseY - dragHoldY;
posY = (posY < minY) ? minY : ((posY > maxY) ? maxY : posY);
shapes[dragIndex].x = posX;
shapes[dragIndex].y = posY;
drawScreen();
}
function hitTest(shape, mx, my) {
var dx;
var dy;
dx = mx - shape.x;
dy = my - shape.y;
//a "hit" will be registered if the distance away from the center is less than the radius of the circular object
return (dx * dx + dy * dy < shape.rad * shape.rad);
}
function drawShapes() {
var i;
for (i = 0; i < numShapes; i++) {
context.fillStyle = shapes[i].color;
context.beginPath();
context.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2 * Math.PI, false);
context.closePath();
context.fill();
}
}
function drawScreen() {
context.fillStyle = "#000000";
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
drawShapes();
}
}
window.addEventListener("load", windowLoadHandler, false);
function windowLoadHandler() {
canvasApp('delayPad');
}
There are still a few shortcomings, for instance the mouseMoveListener, although constricting the movement of the circle, will continue to increase your x & y values. Meaning you'll either have to use your existing listeners to check when the drag event has exited the circle, or much more simply, you could set an upper limit to your X and Y values.
You'll have to create an object which will store your x and y values.
In below example I called it pad.
This object will serve both your canvas visualization, and your audio processing.
These are both outputs (respectively visual and audio), while the input will be user gesture (e.g mousemove).
The inputs update the pad object, while outputs read it.
[Note]: This example will only work in newest Chrome and Firefox since it uses MediaElement.captureStream() which is not yet widely implemented.
const viz_out = canvas.getContext('2d');
let aud_out, mainVolume;
// our pad object holding the coordinates
const pad = {
x: 0,
y: 0,
down: false,
rad: 10
};
let canvRect = canvas.getBoundingClientRect();
function mousemove(event) {
if (!aud_out || !pad.down) {
return;
}
pad.x = event.clientX - canvRect.left;
pad.y = canvRect.height - (event.clientY - canvRect.top); // inverts y axis
// all actions are splitted
updateViz();
updateAud();
updateLog();
}
viz_out.setTransform(1, 0, 0, -1, 0, 300) // invert y axis on the canvas too
// simply draws a circle where at our pad's coords
function updateViz() {
viz_out.clearRect(0, 0, canvas.width, canvas.height);
viz_out.beginPath();
viz_out.arc(pad.x, pad.y, pad.rad, 0, Math.PI * 2);
viz_out.fill();
}
// You'll do it as you wish, here it just modifies a biquadFilter
function updateAud() {
const default_freq = 350;
const max_freq = 6000;
const y_ratio = pad.y / 300;
aud_out.frequency.value = (default_freq + (max_freq * y_ratio)) - default_freq;
aud_out.Q.value = (pad.x / 300) * 10;
mainVolume.value = 1 + ((pad.y + pad.x) / 75);
}
function updateLog() {
log.textContent = `x:${~~pad.x} y:${~~pad.y}`;
}
canvas.addEventListener('mousedown', e => pad.down = true);
canvas.addEventListener('mouseup', e => pad.down = false);
canvas.addEventListener('mousemove', mousemove);
btn.onclick = e => {
btn.textContent = 'stop';
startLoadingAudio();
btn.onclick = e => {
mainVolume.value = 0;
}
}
window.onscroll = window.onresize = e => canvRect = canvas.getBoundingClientRect();
function startLoadingAudio() {
const audio = new Audio();
audio.loop = true;
audio.muted = true;
audio.onloadedmetadata = e => {
audio.play();
const stream = audio.captureStream ? audio.captureStream() : audio.mozCaptureStream();
initAudioProcessor(stream);
updateLog();
window.onscroll();
updateViz();
}
// FF will "taint" the stream, even if the media is served with correct CORS...
fetch("https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3").then(resp => resp.blob()).then(b => audio.src = URL.createObjectURL(b));
function initAudioProcessor(stream) {
var a_ctx = new AudioContext();
var gainNode = a_ctx.createGain();
var biquadFilter = a_ctx.createBiquadFilter();
var source = a_ctx.createMediaStreamSource(stream);
source.connect(biquadFilter);
biquadFilter.connect(gainNode);
gainNode.connect(a_ctx.destination);
aud_out = biquadFilter;
mainVolume = gainNode.gain;
biquadFilter.type = "bandpass";
}
}
canvas {
border: 1px solid;
}
<button id="btn">
start
</button>
<pre id="log"></pre>
<canvas id="canvas" width="300" height="300"></canvas>

How to clear trails when drawing rectangles on an HMTL5 canvas

I am currently working on an application where I draw a rectangle on a canvas. I can draw the rectangle perfectly but then when I try to change the movement of the mouse to make the rectangle smaller there are trails that are left behind. How do I clear these trails when I make the rectangle's size smaller? below is my JavaScript code that I used. Thanks in advance.
function drawSquare() {
// creating a square
var w = lastX - startX;
var h = lastY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
context.beginPath();
context.rect(startX + offsetX, startY + offsetY, width, height);
context.fillStyle = "gold";
context.fill();
context.lineWidth = 1;
context.strokeStyle = 'red';
context.stroke();
canvas.style.cursor = "default";
}
function getMousePos(canvas, e) {
var rect = canvas.getBoundingClientRect();
return {
x: e.pageX - canvas.offsetLeft,
y: e.pageY - canvas.offsetTop,
};
}
function handleMouseDown(e) {
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
isDown = true;
if (isChecBoxClicked == true) {
mouseIsDown = 1;
startX = lastX;
startY = lastY;
var pos = getMousePos(canvas, e);
startX = lastX = pos.x;
startY = lastY = pos.y;
drawSquare();
}
else {
canvas.style.cursor = "default";
}
}
function handleMouseUp(e) {
// clear the dragging flag
isDown = false;
canvas.style.cursor = "default";
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
if (isChecBoxClicked == true)
{
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
function handleMouseMove(e) {
// if we're not dragging, exit
if (!isDown) {
return;
}
//if (defaultval == 1) {
// return;
//}
if (isChecBoxClicked == true) {
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
A canvas doesn't clear itself. At least not a 2D context, like you are using. If you keep drawing on it, the new graphics is placed on top of the old. You need to explicitly clear it:
context.clearRect(0, 0, canvas.width, canvas.height);
You will probably have to clear your canvas. If you are only drawing a square you will have to do that in the drawSquare function. If you are drawing multiple things you will have to do it in a higher function that redraws multiple things.
For clearing the whole canvas, you can use the following code:
context.clearRect ( 0 , 0 , canvas.width, canvas.height );
There are also a lot of canvas libraries that will manage this for you and optimize the areas redrawn (they might only clear a part of the canvas, so there are less pixels redrawn)

Simple way to track mouse coordinates while moving over HTML5 canvas

Is there a simple way to get relative mouse coordinates while moving mouse over HTML5 canvas?
I found this:
function getMousePos(canvas, evt){
// get canvas position
var obj = canvas;
var top = 0;
var left = 0;
while (obj && obj.tagName != 'BODY') {
top += obj.offsetTop;
left += obj.offsetLeft;
obj = obj.offsetParent;
}
// return relative mouse position
var mouseX = evt.clientX - left + window.pageXOffset;
var mouseY = evt.clientY - top + window.pageYOffset;
return {
x: mouseX,
y: mouseY
};
}
But it seems too heavy to me. Is there a reason using frameworks (like Kinetic) when working with canvas to simplify such things?
If you're not using your mousemove on your canvas use this:
$(function () {
canvas = document.getElementById('canvas');
canvas.onmousemove = mousePos;
});
function mousePos(e) {
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
}
else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
}
You could position canvas absolutely and then remove while loop.
Ultimately, if canvas would not move, you could cache it's offset and then use cached value.
And to cover all cases: if canvas would have fixed position, you'll need not consider scrolling: pageXOffset, pageYOffset.

Categories