I need to rotate an image inside an canvas..I have googled and saw similar questions in stackoverflow.What i learnt is
I cannot rotate single object inside canvas.
I can rotate only thewhole canvas.
So i need to translate to center of the object and then rotate the
canvas.
I Followed exactly same stuffs , But i am struck at translating to the image center..Below is the code i am using.Here is the jsfiddle http://jsfiddle.net/J6Pfa/1/. This one is rotating the whole canvas regardless image..some one guide me where i am wrong.Thanks
//hero canvas
ball = new Hero();
var ang = 0;
herocanvas = document.createElement("canvas");
herocanvas.width = herocanvas.width = 500;
herocanvas.height = herocanvas.height = 500;
heroctx = herocanvas.getContext('2d');
document.body.appendChild(herocanvas);
var requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame;
var imgSprite = new Image();
imgSprite.src = 'http://i.imgur.com/WTgOHGg.png';
imgSprite.addEventListener('load',init,false);
function init()
{
startloop();
}
function startloop()
{
heroctx.save(); //saves the state of canvas
clearherobg() ; // clear canvas
heroctx.translate(ball.drawX, ball.drawY); //let's translate
heroctx.rotate(Math.PI / 180 * (ang += 4));
ball.draw(); // draw image here
heroctx.restore();
requestAnimFrame(startloop);
}
function Hero() {
this.srcX = 0;
this.srcY = 500;
this.drawX = 220;
this.drawY = 200;
this.width = 100;
this.height = 40;
this.speed = 5;
this.isUpKey = false;
this.isRightKey = false;
this.isDownKey = false;
this.isLeftKey = false;
}
Hero.prototype.draw = function () {
heroctx.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
};
function clearherobg() {
heroctx.clearRect(0,0,500,500);
}
Those who cannot read full code ..Please check startloop() , thats the main infinite loop..ball.drawX and ball.drawY are the x and y position of image inside canvas
Hero's drawX and drawY need to be updated to new coordinate system of canvas, if u want it to be in the middle of canvas it needs to be 0,0.
Something like this: jsfiddle.net/J6Pfa/3
Hm, i dont exactly understand what you want to achieve, an image moving on the circle path ? or having image in one place, and just rotate it ?
Related
I'm trying to use Fabric.js with Fabric Brush This issue that I'm running into is that Fabric Brush only puts the brush strokes onto the Top Canvas and not the lower canvas. (The stock brushes in fabric.js save to the bottom canvas) I think I need to convert "this.canvas.contextTop.canvas" to an object and add that object to the the lower canvas. Any ideas?
I've tried running:
this.canvas.add(this.canvas.contextTop)
in
onMouseUp: function (pointer) {this.canvas.add(this.canvas.contextTop)}
But I'm getting the error
Uncaught TypeError: obj._set is not a function
So the contextTop is CanvasHTMLElement context. You cannot add it.
You can add to the fabricJS canvas just fabric.Object derived classes.
Look like is not possible for now.
They draw as pixel effect and then they allow you to export as an image.
Would be nice to extend fabricJS brush interface to create redrawable objects.
As of now with fabricJS and that particular version of fabric brush, the only thing you can do is:
var canvas = new fabric.Canvas(document.getElementById('c'))
canvas.freeDrawingBrush = new fabric.CrayonBrush(canvas, {
width: 70,
opacity: 0.6,
color: "#ff0000"
});
canvas.isDrawingMode = true
canvas.on('mouse:up', function(opt) {
if (canvas.isDrawingMode) {
var c = fabric.util.copyCanvasElement(canvas.upperCanvasEl);
var img = new fabric.Image(c);
canvas.contextTopDirty = true;
canvas.add(img);
canvas.isDrawingMode = false;
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.1/fabric.min.js"></script>
<script src="https://tennisonchan.github.io/fabric-brush/bower_components/fabric-brush/dist/fabric-brush.min.js"></script>
<button>Enter free drawing</button>
<canvas id="c" width="500" height="500" ></canvas>
That is just creating an image from the contextTop and add as an object.
I have taken the approach suggested by AndreaBogazzi and modified the Fabric Brush so that it does the transfer from upper to lower canvas (as an image) internal to Fabric Brush. I also used some code I found which crops the image to a smaller bounding box so that is smaller than the full size of the canvas. Each of the brushes in Fabric Brush has an onMouseUp function where the code should be placed. Using the case of the SprayBrush, the original code here was:
onMouseUp: function(pointer) {
},
And it is replaced with this code:
onMouseUp: function(pointer){
function trimbrushandcopytocanvas() {
let ctx = this.canvas.contextTop;
let pixels = ctx.getImageData(0, 0, canvas.upperCanvasEl.width, canvas.upperCanvasEl.height),
l = pixels.data.length,
bound = {
top: null,
left: null,
right: null,
bottom: null
},
x, y;
// Iterate over every pixel to find the highest
// and where it ends on every axis ()
for (let i = 0; i < l; i += 4) {
if (pixels.data[i + 3] !== 0) {
x = (i / 4) % canvas.upperCanvasEl.width;
y = ~~((i / 4) / canvas.upperCanvasEl.width);
if (bound.top === null) {
bound.top = y;
}
if (bound.left === null) {
bound.left = x;
} else if (x < bound.left) {
bound.left = x;
}
if (bound.right === null) {
bound.right = x;
} else if (bound.right < x) {
bound.right = x;
}
if (bound.bottom === null) {
bound.bottom = y;
} else if (bound.bottom < y) {
bound.bottom = y;
}
}
}
// Calculate the height and width of the content
var trimHeight = bound.bottom - bound.top,
trimWidth = bound.right - bound.left,
trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
// generate a second canvas
var renderer = document.createElement('canvas');
renderer.width = trimWidth;
renderer.height = trimHeight;
// render our ImageData on this canvas
renderer.getContext('2d').putImageData(trimmed, 0, 0);
var img = new fabric.Image(renderer,{
scaleY: 1./fabric.devicePixelRatio,
scaleX: 1./fabric.devicePixelRatio,
left: bound.left/fabric.devicePixelRatio,
top:bound.top/fabric.devicePixelRatio
});
this.canvas.clearContext(ctx);
canvas.add(img);
}
setTimeout(trimbrushandcopytocanvas, this._interval); // added delay because last spray was on delay and may not have finished
},
The setTimeout function was used because Fabric Brush could still be drawing to the upper canvas after the mouseup event occurred, and there were occasions where the brush would continue painting the upper canvas after its context was cleared.
Website: http://minimedit.com/
Currently implementing an eye dropper. It works fine in my normal resolution of 1080p, but when testing on a higher or lower resolution it doesn't work.
This is the basics of the code:
var ctx = canvas.getContext("2d");
canvas.on('mouse:down', function(e) {
var newColor = dropColor(e, ctx);
}
function dropColor(e, ctx) {
var mouse = canvas.getPointer(e.e),
x = parseInt(mouse.x),
y = parseInt(mouse.y),
px = ctx.getImageData(x, y, 1, 1).data;
return rgb2hex('rgba('+px+')');
}
When I first initiate the canvas I have it resize to fit resolution:
setResolution(16/9);
function setResolution(ratio) {
var conWidth = ($(".c-container").css('width')).replace(/\D/g,'');
var conHeight = ($(".c-container").css('height')).replace(/\D/g,'');
var tempWidth = 0;
var tempHeight = 0;
tempHeight = conWidth / ratio;
tempWidth = conHeight * ratio;
if (tempHeight > conHeight) {
canvas.setWidth(tempWidth);
canvas.setHeight(conHeight);
} else {
canvas.setWidth(conWidth);
canvas.setHeight(tempHeight);
}
}
The x and y mouse coordinates work fine when zoomed in, but they don't line up with the returned image data. It seems as though the ctx isn't changing it's width and height and scaling along with the actual canvas size.
The canvas element is showing the correct width and height before using getContext as well.
Any ideas on a solution?
Feel free to check out the full scripts on the live website at: http://minimedit.com/
Try "fabric.devicePixelRatio" for calculating actual position, for example:
x = parseInt(mouse.x) * fabric.devicePixelRatio
I've tried for a couple of weeks to trouble shoot this problem and I've come to a dead end.
as a word of warning I'm very new to coding and I may not be able to understand much.
I'm trying to draw an image at the location of the mouse.
this is my script so far
$(function()
{
var canvas = $('#canvas')[0];
var context = canvas.getContext("2d");
var img = new Image();
img.src = 'cross.png';
function getTopLeft(elm)
{
var x, y = 0;
x = elm.offsetLeft;
y = elm.offsetTop;
elm = elm.offsetParent;
while(elm != null)
{
x = parseInt(x) + parseInt(elm.offsetLeft);
y = parseInt(y) + parseInt(elm.offsetTop);
elm = elm.offsetParent;
}
return {Top:y, Left: x};
}
canvas.style.cursor = "none";
canvas.addEventListener("mousemove", function (ev)
{
var mouseX = ev.pageX - getTopLeft(canvas).Left;
var mouseY = ev.pageX - getTopLeft(canvas).Top;
});
function animate()
{
context.onmousemove = function(evt)
{
context.clearRect(0,0,canvas.width,canvas.height);
context.drawImage(img, Left, Top);
}
}
});
I think the problem lies in defining the x y value of the picture ive tried every variable used in the code but to no avail the script loads without error but doesnt draw the image at the mouse location.
I have just realised also that i need the image to be centred over the mouse position.
its very confused i`m designing a 2d game and i use this code to draw images to canvas the alert method return background.x = 0 ! but when i change x to z or any letter its return the number 400 i ! why background.x always equal to zero ???
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
function loadResources(){
background = new Image();
background.src = "11.jpg";
background.width = 128;
background.height = 128;
background.x = 400;
background.y = 450;
}
function drawimage(){
alert(background.x);
context.drawImage(background,background.x,background.y,background.width,background.height);
}
function gameLoop() {
drawimage();
}
loadResources();
setInterval(gameLoop, 1000/60);
Unlike other objects, you are actually not able to set properties of an Image object that do not belong to it. As you've seen, when you try to access them after setting them, the properties will not be available. You can slightly rework your code as follows to get the behavior you're looking for:
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var resources = {};
function loadResources(){
resources.background = new Image();
resources.background.src = "11.jpg";
resources.background.width = 128;
resources.background.height = 128;
resources.backgroundx = 400;
resources.backgroundy = 450;
}
function drawimage(){
console.log(resources.backgroundx);
context.drawImage(resources.background,resources.backgroundx,resources.backgroundy,resources.background.width,resources.background.height);
}
function gameLoop() {
drawimage();
}
loadResources();
setInterval(gameLoop, 1000/60);
I am making a game and in it I would like to have the ability to use cached canvas's instead of rotating the image every frame. I think I made a function for adding images that makes sense to me, but I am getting an error every frame that tells me that the canvas object is no longer available.
INVALID_STATE_ERR: DOM Exception 11: An attempt was made to use an
object that is not, or is no longer, usable.
You might also need to know that I am using object.set(); to go ahead and add that image to a renderArray. That may be affecting whether the canvas object is still avaliable?
Here is the function that returns a cached canvas, (I took it from a post on this website :D)
rotateAndCache = function(image, angle){
var offscreenCanvas = document.createElement('canvas');
var offscreenCtx = offscreenCanvas.getContext('2d');
var size = Math.max(image.width, image.height);
offscreenCanvas.width = size;
offscreenCanvas.height = size;
offscreenCtx.translate(size/2, size/2);
offscreenCtx.rotate(angle + Math.PI/2);
offscreenCtx.drawImage(image, -(image.width/2), -(image.height/2));
return offscreenCanvas;
}
And here is some more marked up code:
var game = {
render:function(){
//gets called every frame
context.clearRect(0, 0, canvas.width, canvas.height);
for(i = 0; i < game.renderArray.length; i++){
switch(game.renderArray[i].type){
case "image":
context.save();
context.translate(game.renderArray[i].x, game.renderArray[i].y);
context.rotate(Math.PI*game.renderArray[i].rotation/180);
context.translate(-game.renderArray[i].x, -game.renderArray[i].y);
context.drawImage(game.renderArray[i].image, game.renderArray[i].x, game.renderArray[i].y);
context.restore();
break;
}
if(game.renderArray[i].remove == true){
game.renderArray.splice(i,1);
if(i > 1){
i--;
}else{
break;
}
}
}
},
size:function(width, height){
canvas.height = height;
canvas.width = width;
return height + "," + width;
},
renderArray:new Array(),
//initialize the renderArray
image:function(src, angle){
if(angle != undefined){
//if the argument 'angle' was given
this.tmp = new Image();
this.tmp.src = src;
//sets 'this.image' (peach.image) to the canvas. It then should get rendered in the next frame, but apparently it doesn't work...
this.image = rotateAndCache(this.tmp, angle);
}else{
this.image = new Image();
this.image.src = src;
}
this.x = 0;
this.y = 0;
this.rotation = 0;
this.destroy = function(){
this.remove = true;
return "destroyed";
};
this.remove = false;
this.type = "image";
this.set = function(){
game.renderArray.push(this);
}
}
};
var canvas, context, peach;
$(document).ready(function(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
//make the variable peach a new game.image with src of meme.jpg and an angle of 20.
peach = new game.image('meme.jpg', 20);
peach.set();
game.size(700,500);
animLoop();
});
If you want, here is this project hosted on my site:
http://keirp.com/zap
There are no errors on your page, at least not anymore or not that I can see.
It's quite possible that the problem is an image that is not done loading. For instance that error will happen if you try to make a canvas pattern out of a not-yet-finished-loading image. Use something like pxloader or your own image loading function to make sure all the images are complete before you start drawing.
Anyway, it's nigh impossible to figure out what was or is happening since your code isn't actually giving any errors (anymore).