I have a little canvas that draws a cross and an input box to control the angle of rotation.
<input type='text' ng-model='angle'>
<canvas id="myLitleCanvas" width="200" height="200"></canvas>
<script>
var canvas = document.getElementById('myLitleCanvas');
var context = canvas.getContext('2d');
context.save();
context.translate(100, 100);
context.rotate({{angle}} * Math.PI / 180.0); // <---- problem
context.translate(-100, -100);
context.beginPath();
context.moveTo(100, 0);
context.lineTo(100, 200);
context.moveTo(0, 100);
context.lineTo(200, 100);
context.stroke();
</script>
Then I have a very simple controller bound to angle
function MapCtrl($scope) {
$scope.angle = 45;
}
ButI can't seem to access angle or redraw the canvas when the value in the text box changes. Is this even possible?
There is no token replacement in javascript blocks. The recommended way of doing DOM manipulation is to put your javascript code into a directive. You would then have an attribute that references your 'angle' parameter. You might want to look at angular-ui for ideas on doing custom UI directives. Hope this helps.
As previously mentioned, there is no token replacement in javascript blocks.
To get this working...move the code from the script block with the controller. And just simply access the angle as $scope.angle. You could also write a rotateAndRedraw function and bind to ng-click or whatever:
$scope.rotateAndRedraw = function (angle) {
context.clearRect(x,y,width,height);
context.translate(100, 100);
context.rotate(angle * Math.PI / 180.0);
context.translate(-100, -100);
context.beginPath();
context.moveTo(100, 0);
context.lineTo(100, 200);
context.moveTo(0, 100);
context.lineTo(200, 100);
context.stroke();
};
You could also wrap all this canvas code within a directive and easily replicate the canvas multiple times on a page.
Related
For an assignment I need to animate something simple using CSS and JavaScript. I've been able to figure out the CSS but everything I read to make an object fade in using JavaScript just doesn't seem to work with the object I drew in JavaScript. I just wanted to draw a circle in JavaScript and then animate it to fade in in 5 seconds.
Here is the basic Code I have so far:
HTML:
<body onload="draw();">
<canvas id="circle" width="450" height="450"></canvas>
</body>
JavaScript:
<script>
function draw()
{
var canvas = document.getElementById('circle');
if (canvas.getContext)
{
var ctx = canvas.getContext('2d');
var X = canvas.width / 2;
var Y = canvas.height / 2;
var R = 45;
ctx.beginPath();
ctx.arc(X, Y, R, 0, 2 * Math.PI, false);
ctx.lineWidth = 3;
ctx.strokeStyle = '#645862';
ctx.stroke();
}
}
</script>
As you can see I only have the circle part of the code. I have tried multiple versions of different fade in animations but I just can't quite get them to work. I'm not very good at JavaScript. It's the one language I have trouble understanding for some reason. I'm also really sick right now otherwise I would be troubleshooting more reasons as to why it isn't working.
To understand how a canvas works, you need to know that it's just a place to display something, and initially it doesn't do anything on its own. You've drawn the circle once, which is enough to display the circle, but not to animate it in any way.
If we want to move the circle in any direction, we must clear the canvas of the already drawn circle and draw the circle in a different place, changing its coordinates by N pixels. The same goes for transparency. We must change the transparency of the color of the circle in each frame, and draw the circle again and again.
This is how 2D and 3D canvas works, as well as all video games - they draw scenes 60 times per second, changing some values along the way, such as coordinates, values, color, transparency, height and width.
In order for this to work, we need two additional variables, opacity and the direction (fading) in which the opacity changes, to know whether the circle appears or disappears.
Also important is the recursive call to our draw() function. We will call it constantly, and we will constantly redraw our image on the canvas.
I also want to point out some conceptual mistakes in your code.
Dont use "var", it is deprecated. Use "let","const". Also don`t repeat "var","var","var" in every line. Use commas.
Dont use onload,onclick and others HTML on-attributes. They are only suitable for educational purposes, not for real work. Use script tag and document event listeners.
Dont name canvas id like "circle","box" etc. It is not a circle and a box, it is a canvas.
Use document.querySelector instead of document.getElementById. It is more modern
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas opacity animation</title>
</head>
<body>
<canvas id="canvas" width="450" height="450"></canvas>
<script>
document.addEventListener("DOMContentLoaded",()=>{
const OPACITY_SPEED = .005
let canvas = document.querySelector('canvas'),
context = canvas.getContext('2d'),
opacity = 1,
fading = true
draw()
function draw(){
// clear canvas for redrawing (important!)
context.clearRect(0, 0, canvas.width, canvas.height);
let circleX = canvas.width/2,
circleY = canvas.height/2,
radius = 45
// changing circle opacity
if(fading) opacity -= OPACITY_SPEED
else opacity += OPACITY_SPEED
// check if we need to fade in or to fade out
if(opacity >= 1) fading = true
if(opacity <= 0) fading = false
// draw circle
context.beginPath();
context.arc(circleX, circleY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 3;
context.strokeStyle = `rgba(0, 0, 0, ${opacity})`;
context.stroke();
// call draw() again and again
requestAnimationFrame(draw)
}
})
</script>
</body>
</html>
I have a problem in my code it dont work and i dont find the misstakes i think the misstakes is because the many nesting and i have set a bracket on the wrong place.
The Function from the code is a Animation in the Animation are some images at the top of the canvas and than should this images slowly came from the top to the bottom like a watterfall.i hope you can understand my explanation.
console.log("hey");
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'); //ctx = contex
var img = new Image();
img.src="../img/cookie.png";
canvas.width = canvas.scrollWidth;
canvas.height = canvas.scrollHeight;
img.onload = function() {
console.log("Loaded image")
var add = 10;
var id = setInterval(function () {
if (add == 500) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.rect(0, 0, 1000, 1000);
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.drawImage(img,0 , 0, 100, 100);
ctx.drawImage(img,100,0, 100, 100);
ctx.drawImage(img,200,0, 100, 100);
ctx.drawImage(img,300,0, 100, 100);
ctx.drawImage(img,400,0, 100, 100);
ctx.drawImage(img,500,0, 100, 100);
ctx.drawImage(img,600,0, 100, 100);
ctx.drawImage(img,700,0, 100, 100);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.rect(0, 0, 1000, 1000);
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.drawImage(img,0 , add, 100, 100);
ctx.drawImage(img,100,add, 100, 100);
ctx.drawImage(img,200,add, 100, 100);
ctx.drawImage(img,300,add, 100, 100);
ctx.drawImage(img,400,add, 100, 100);
ctx.drawImage(img,500,add, 100, 100);
ctx.drawImage(img,600,add, 100, 100);
ctx.drawImage(img,700,add, 100, 100);
add++;
}
}, 10)
}
PS:sorry if some misstakes in my text but i am still student. :D
PPS: thanks for the help.
EDIT: Now it works thanks for the help.
**EDit2:**now i have a nother problem the code will only exectude one time but it should excetuded the full time if anybody can help me i am very danbar.
I think all of your brackets are in the right place. The big error I see is that your if statement says if (add = 1000) using single = instead of double ==. This means that you're setting add to 1000 in your if statement instead of comparing it.
Edit: Another issue you had was that your image src was being defined in its onload, which doesn't really make sense, as the onload waits for src to be loaded.
I made a jsfiddle here where your code works, check it out: https://jsfiddle.net/pjkmwvp6/
Can you try changing this???
// Change this
if(add = 1000){
// To this
if(add === 1000){
To address any doubts you may have with brackets, many editors and web services can perform code beautifying (aka pretty printing) for you. Give it a Google. Also, there’s one such tool build into Firefox with the Shift+F4 “slate”, just paste your code in it and hit Ctrl+P.
I think you’re not loading your image the right way. Be aware that setting an image’s src attribute is what actually triggers its loading. As is, your code can’t load the image since the instruction that sets src is inside the onload handler. Put it after.
When dealing with animations, setInterval is not the best suited function. Prefer requestAnimationFrame. Its syntax is very close and it has CPU-saving capabilities.
I am seeking for a way that allows players to draw their own characters and later to be able to play with them in-game. To make the concept very simple lets make the drawn player just a 2d shape or a group of lines and circles or even a mix of both. I think this can be decomposed in these steps:
An empty canvas is made for the user to create what he wants:
By painting or something of that genre
By using a specific polygon creation interface that allows dragging and molding shapes;
Note: I was able to create a way to paint on canvas *** but I didn't find a way to let user drag and create shapes or something of that kind. I would more likely opt for the second option so some suggestions on how do this would be really appreciated.
window.onload = init;
function init() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var painting = document.getElementById('paint');
var paint_style = getComputedStyle(painting);
canvas.width = "1024"
canvas.height = "1024";
var mouse = {
x: 0,
y: 0
};
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
ctx.lineWidth = 3;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#00CC99';
canvas.addEventListener('mousedown', function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tojo - canvas draw</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<script src="app.js"></script>
<div id="paint"></div>
<canvas id="myCanvas" style="border: 3px solid black;"></canvas>
</body>
</html>
(paint on canvas snippet) ***
Somehow, I need to only get the user drawn / shaped creation from all the canvas. There should be a way to "surround" what the user has created and then save it:
By (in the drawing case probably) checking only for the color comparison between the white and the player color;
By, somehow, defining different points that all together would countain the user creation (either drawn or shaped);
Note: In this case I am kind of lost. I have almost no clue of how this could be made. However, I have heard of box2d but I think it was more focused in C or something of that kind? Would it work and how could I do it?
I would finally have the user creation stored and ready to load it in game as an image of a sprite.
I hope I could explain it all correctly. Can someone give me some orientation on this? FYI I am using Phaser.js as js game engine. (sorry for any mistakes, I am not very experienced with this matters).
Hopefully this will get you headed in the right direction:
Instead of drawing to the canvas, create a Phaser bitmapData object and have the user draw to that object. See this example that shows how to draw to a bitmapData object.
If you follow #1, then all of the data that you want will be stored in the bitmapData object, and you can create a Sprite directly from your bitmapData object, e.g.:
// Create a bitmapData object for the user to draw on
var bmd = this.game.make.bitmapData(64, 64);
// code to draw on `bmd` goes here
// Create a Sprite based on the bitmapData from above
var userSprite = this.game.add.sprite(0, 0, bmd);
I'm trying to change the color of the contents of the canvas after it is drawn. So if you start drawing a green circle, you could then decide later to make your previously drawn circle into a red a circle.
I'm using the signaturePad plugin here:
https://github.com/szimek/signature_pad
I have some of the functionality built, but the pen color change doesn't change previously drawn elements. Here's a fiddle:
http://jsfiddle.net/Z6g5Z/
Thanks for your help! The fiddle is prob. the best way to see the issue, but the JS and markup are below.
var canvas = $("#can")[0];
var signaturePad = new SignaturePad(canvas, {
minWidth: 2,
maxWidth: 5,
penColor: "rgb(66, 133, 244)"
});
$('#clear').click(function(){
signaturePad.clear();
});
$('.global-color li').click(function(){
$('.on').removeClass('on');
var $t = $(this);
$t.addClass('on');
var selectedColor = $t.data('color');
signaturePad.penColor = hexToRgb(selectedColor);
});
<ul class="global-color">
<li class="yellow-pick" data-color="#f8c90d">yellow</li>
<li class="green-pick" data-color="#3dae49">green</li>
<li class="orange-pick" data-color="#e87425">orange</li>
<li class="blue-pick on" data-color="#009cc5">blue</li>
</ul>
<div>
<input id="clear" type="button" value="clear" />
</div>
<canvas id="can" width="200px" height="200px"></canvas>
In your color change handler, have all canvas change its (non-transparent) pixels to the new color.
For this, most simple is to use globalComposite operation mode 'source-in', and fill over the canvas with the new color :
// set all pixels of the image to this color
function setCurrentColor(canvas, color) {
var context = canvas.getContext('2d');
context.save();
context.fillStyle = color;
context.globalCompositeOperation = 'source-in';
context.fillRect(0,0,canvas.width, canvas.height);
context.restore();
}
i updated your demo :
http://jsfiddle.net/gamealchemist/Z6g5Z/3/
You can by changing composite mode and fill in the color you want on the existing content.
With a library like this you have no guarantee of the inner workings of it so it may work today and may not work tomorrow - if the author decides to change the way it behaves internally.
So with that disclaimer you can use the following code to change the color of the existing drawing - this works in general with all canvas drawings and changes non-transparent pixels to what you draw on top:
function changeColor() {
ctx.save();
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = selectedColor;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.restore();
}
However, since we are going to tap into the library there are at least one other limitation here. The library seem to use a second canvas on top where it registers the mouse. When pen is up it transfer that drawing to the main canvas. The drawback with this, for us, is that the pen change won't happen until we draw something new; we can't change the pen color visually just by using the above function - for that you would have to patch the library to add for example a method which did all the steps needed internally.
But we do get close by adding the following setting:
var signaturePad = new SignaturePad(canvas, {
minWidth: 2,
maxWidth: 5,
penColor: "rgb(66, 133, 244)",
onBegin: changeColor /// add callback here
});
Live demo here
Hope this helps!
I have a problem with the click function in javascript. This is my code:
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext('2d');
BigCircle = function(x, y, color, circleSize) {
ctx.shadowBlur = 10;
ctx.shadowColor = color;
ctx.beginPath();
ctx.arc(x, y, circleSize, 0, Math.PI * 2, true);
ctx.fill();
ctx.closePath();
};
var bigGreen = new BigCircle(1580, 800, '#5eb62b', 180);
function init() {
$("#bigGreen").click(function(e){
alert("test");
});
}
$(document).ready(function() {
init();
});
But the click event is not working! Does anybody know why? Thank you so much in advance!
You can now use hit regions in Chrome and Firefox:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility#Hit_regions
(Edit: Hit regions are now obsolete)
or just use one of the many canvas APIs:
http://www.fabricjs.com/
http://www.createjs.com/easeljs
http://www.paperjs.org
etc...
without seeing your html this question is a little bit unclear, it seems you would like to draw something on a canvas and use jquery to add click events for the circle, this isn't possible.
you can use jquery to get the click event ON the canvas and from the cursor position you can calculate if the user clicked the circle or not, but jquery won't help you here you have to do the math yourself.
jquery does only work for dom elements.
BigCircle = function(ctx,x, y, color, circleSize) {
ctx.beginPath();
ctx.arc(x, y, circleSize, 0, Math.PI * 2, true);
ctx.fillStyle=color
ctx.fill();
ctx.closePath();
this.clicked=function(){
ctx.fillStyle='#ff0000'
ctx.fill();
}
};
function init() {
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext('2d');
var bigGreen = new BigCircle(ctx,50, 50, '#5eb62b', 50);
$('#canvas').click(function(e){
var x = e.clientX
, y = e.clientY
if(Math.pow(x-50,2)+Math.pow(y-50,2) < Math.pow(50,2))
bigGreen.clicked()
})
}
$(document).ready(function() {
init();
});
jsfiddle is here
http://jsfiddle.net/yXVrk/1/
Canvas API function isPointInPath() can be used to assist with hit detection. This function can at least tell if mouse coordinates are within a complex shape without doing sophisticated math yourself. May work for simple shapes as well but my use case was for on a bezier curve path. However, you need to either incorporate this function in your drawing logic to test while paths are open or keep an array of Path2d objects to test against. I redraw on onClick handler and pass in mouse coords from event args, but I think I could have kept an array of Path2d objects instead.
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath
bigGreen is not in the HTML, so $("#bigGreen") selects nothing. You can't put a click function on things like JavaScript functions; since they don't exist in the DOM, how could you click one? You should replace #bigGreen with #canvas, since "canvas" is your HTML element.
I forked your fiddle to show this here.
Edit: If you want to see that the user clicked on a particular circle, you use the canvas click event, and then, you determine which circle was clicked by the coordinates passed into the click event.