I'm trying to rotate an image added to my canvas using KineticJS.
I got it almost working.
I know I need to set the offset to 'move' the rotation point, that part is working.
But it is also moving to that location of the offset.
After doing some rotating I can drag my image to another location in the canvas and continue rotating around its own center.
I don't want to rotate the whole canvas, because I have multiple images on a layer.
The relevant code:
function rotateLayer() {
// Rotate bird image
var rotation = 15;
// Set rotation point:
imageDict[1].setOffsetX(imageDict[1].width() / 2);
imageDict[1].setOffsetY(imageDict[1].height() / 2);
// rotation in degrees
imageDict[1].rotate(rotation);
imageDict[1].getLayer().draw();
}
A working demo is on jsfiddle: http://jsfiddle.net/kp61vcfg/1/
So in short I want the rotation but not the movement.
How you want to rotate without movement?
KineticJS rotate objects relative it's "start point" . For example for Kinetic.Rect start points is {0, 0} - top left corner. You may move such "start point" to any position with offset params.
After a lot of trail and error I found the solution.
The trick is to set the offset during load to the half width and height to set the rotation point to the middle of the image AND don't call image.cache:
function initAddImage(imgId, imgwidth, imgheight) {
var imageObj = new Image();
imageObj.src = document.getElementById(imgId).src;
imageObj.onload = function () {
var image = new Kinetic.Image({
image: imageObj,
draggable: true,
shadowColor: '#787878',
shadowOffsetX: 2,
shadowOffsetY: 2,
width: imgwidth,
height: imgheight,
x: 150, // half width of container
y: 150, // half height of container
offset : {x : imgwidth / 2, y : imgheight / 2}, // Rotation point
imgId: imgId
});
layer.add(image);
//image.cache();
layer.draw();
imageDict[currentLayerHandle] = image;
currentLayerHandle++;
};
}
I've updated my demo to a working version:
http://jsfiddle.net/kp61vcfg/2/
Related
I am creating one geometry at location (0,0,0) but projecting at some other location (for ex. #50,50,50). If the point (0,0,0) is going out of canvas, then geometry is hiding.
Is there any way to always render it on canvas?
How far off the edge does the origin need to be?
You could make the canvas larger than you need, than mask the areas on the edge such that only the center area shows. That way when the origin goes off the side, it will still technically be on the canvas, and the projected geometry will be in the visible area. I expect you will only need a buffer space equal to projection offset.
See here for an example of applying a mask: https://jsfiddle.net/shawnoakley/n1368qr0/2/
Example code:
var context = document.getElementById('canvas').getContext('2d');
// Mask color
context.fillStyle = '#000';
// Image proportions
context.fillRect(0,0,600,400);
var unmaskedImage = function(x, y, radius){
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
unmaskedImage(300, 300, 300);
I need to convert the position and rotation on a 3d object to screen position and rotation. I can convert the position easily but not the rotation. I've attempted to convert the rotation of the camera but it does not match up.
Attached is an example plunkr & conversion code.
The white facebook button should line up with the red plane.
https://plnkr.co/edit/0MOKrc1lc2Bqw1MMZnZV?p=preview
function toScreenPosition(position, camera, width, height) {
var p = new THREE.Vector3(position.x, position.y, position.z);
var vector = p.project(camera);
vector.x = (vector.x + 1) / 2 * width;
vector.y = -(vector.y - 1) / 2 * height;
return vector;
}
function updateScreenElements() {
var btn = document.querySelector('#btn-share')
var pos = plane.getWorldPosition();
var vec = toScreenPosition(pos, camera, canvas.width, canvas.height);
var translate = "translate3d("+vec.x+"px,"+vec.y+"px,"+vec.z+"px)";
var euler = camera.getWorldRotation();
var rotate = "rotateX("+euler.x+"rad)"+
" rotateY("+(euler.y)+"rad)"+
" rotateY("+(euler.z)+"rad)";
btn.style.transform= translate+ " "+rotate;
}
... And a screenshot of the issue.
I would highly recommend not trying to match this to the camera space, but instead to apply the image as a texture map to the red plane, and then use a raycast to see whether a click goes over the plane. You'll save yourself headache in translating and rotating and then hiding the symbol when it's behind the cube, etc
check out the THREEjs examples to see how to use the Raycaster. It's a lot more flexible and easier than trying to do rotations and matching. Then whatever the 'btn' onclick function is, you just call when you detect a raycast collision with the plane
Is there a way to setup the Three.js renderer in such a way that the lookat point of the camera is not in the center of the rendered image?
To clarify: image a scene with just one 1x1x1m cube at ( 0, 0, 0 ). The camera is located at ( 0, 0, 10 ) and the lookat point is at the origin, coinciding with the center of the cube. If I render this scene as is, I might end up with something like this:
normal render
However I'd like to be able to render this scene in such a way that the lookat point is in the upper left corner, giving me something like this:
desired render
If the normal image is 800x600, then the result I envision would be as if I rendered a 1600x1200 image with the lookat in the center and then cropped that normal image so that only the lower right part remains.
Of course, I can change the lookat to make the cube go to the upper left corner, but then I view the cube under an angle, giving me an undesired result like this:
test.moobels.com/temp/cube_angle.jpg
I could also actually render the full 1600x1200 image and hide 3/4 of the image, but one would hope there is a more elegant solution. Does anybody know it?
If you want your perspective camera to have an off-center view, the pattern you need to use is:
camera = new THREE.PerspectiveCamera( for, aspect, near, far );
camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );
See the docs: https://threejs.org/docs/#api/cameras/PerspectiveCamera
You can find examples of this usage in this example and this example.
three.js r.73
Here's a simple solution:
Assuming your cube is 4 x 4 x 4, at position 0, 0, 0:
var geometry = new THREE.BoxGeometry( 4, 4, 4 );
var material = new THREE.MeshBasicMaterial( { color: 0x777777 } );
var cube = new THREE.Mesh( geometry, material );
cube.position.set( 0, 0, 0 );
Get cube's position:
var Vx = cube.position.x,
Vy = cube.position.y,
Vz = cube.position.z;
Then deduct by 2 from x position, then add 2 to y and z position, and use the values to create a new Vector3:
var newVx = Vx - 2,
newVy = Vy + 2;
newVz = Vz + 2;
var xyz = new THREE.Vector3(newVx, newVy, newVz)
Then camera lookAt:
camera.lookAt(xyz);
Using console log, it would show that the camera is now looking at -2, 2, 2, which is the upper-left of your cube.
console.log(xyz);
I am trying to get the corners of a rotated element in kineticjs. I found a similiar thread for fabricjs and would like to know if there is a similar solution for kineticjs.
Find the coordinates of the corners of a rotated object in fabricjs
I have a layer with an image in it, the image has a negative offset so the origin point is in the center. The layer gets the rotation.
var layer = new Kinetic.Layer({rotationDeg: 45});
var image = new Kinetic.Image({width: 100, height: 100, offsetX: -50, offsetY: -50});
layer.add(Image);
Thank you
You can use some trigonometry:
function findRotatedCornerXY(rectX,rectY,rectWidth,rectHeight,degreeAngle,
originalCornerX,originalCornerY){
// calc rotation centerpoint
var cx=rectX+rectWidth/2;
var cy=rectY+rectHeight/2;
// calc length from rect center to any rect corner
var r=Math.sqrt(rectWidth/2*rectWidth/2+rectHeight/2*rectHeight/2);
// calc unrotated angle from center to corner
var dx=originalCornerX-cx;
var dy=originalCornerY-cy;
var originalAngle=Math.atan2(dy,dx);
// calc new angle of rotated corner
var radianAngle=degreeAngle*Math.PI/180;
var newAngle=originalAngle+radianAngle;
// calc XY of rotated corner
var rx = cx + r * Math.cos(newAngle);
var ry = cy + r * Math.sin(newAngle);
// return the results
return({x:rx,y:ry});
}
I have a canvas where i have drawn a series of images onto it that can be dragged and dropped around, each image is a seperate entity.
I need to, depending on where the image is dropped rotate that image so that it looks appropiate, imaging dragging a triangle around a circle, the base line needs to always point outwards.
I thought i would be able to rotate the image and then draw that on the canvas, but what i seem to find when searching on the internet is that the canvas rotates each time - is it possible to rotate the image only and then place it on the canvas?
Many Thanks!
Yes you can, but it's not as simple as setting a rotation attribute. The way canvas works you can't rotate individual items specifically, only the whole canvas.
To rotate a single item, you'll need to rotate the canvas, place the item, and then rotate the canvas back to it's original orientation.
This question has a few examples: How do I rotate a single object on an html 5 canvas?
Before placing the image on the canvas, create a buffer canvas, place image there, rotate it and then port to main canvas.
var canvas = document.getElementById('test_canvas');
var ctx = canvas.getContext('2d');
var buffer = document.createElement('canvas');
buffer.width = buffer.height = 60;
var bctx = buffer.getContext('2d');
bctx.translate(30, 30);
bctx.rotate(0.5);
bctx.fillStyle = 'rgb(255, 0, 0)';
bctx.fillRect(-15, -15, 30, 30);
ctx.fillStyle = 'rgb(0, 255, 0)';
ctx.fillRect(30, 30, 30, 30);
ctx.drawImage(buffer, 50, 50);
You can check this code at JSFiddle I've setup - http://jsfiddle.net/dzenkovich/UdaUA/2/
Note you'll need to keep a close eye at the rotation point and buffer canvas size for this to work.
For more info check out this article I've found http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/