hey guys i am taking an angle input from user and using it to stroke the line in that
direction
function makeline(angle)
{
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
angle=document.getElementById("radi").value;
//alert(angle);
angle=(Math.PI/180)*angle;
//getting end coordinates
x2= 0+theCanvas.width*Math.cos(angle) //here angle should be in radians
y2=400+theCanvas.width *Math.sin(angle);
context.beginPath();
context.setLineDash([3,2]);
context.lineWidth=10;
context.strokeStyle="black";
context.moveTo(400,400);
context.lineTo(x2,y2);
context.stroke();
}
now is it possible to move an image on the line that is generated every time with the new angle. Please help. take the image of a car or anything.
Yes, it is. You can already work out where to draw the image using simple trigonometry. What you need to do is look into how to draw an image with arbitrary rotation onto a canvas.
Here's a quick sample of drawing a line of variable length and angle to a canvas. Add to it the results of your research into drawing rotated images and you're done.
<!DOCTYPE html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e);}
window.addEventListener('load', mInit, false);
function mInit()
{
byId('angleSlider').addEventListener('change', onSliderChange, false);
byId('lengthSlider').addEventListener('change', onSliderChange, false);
}
function onSliderChange(evt)
{
var slider = this;
var tgtSpan = slider.nextSibling;
tgtSpan.innerHTML = slider.value;
drawCurValues();
}
function drawCurValues()
{
var angle = byId('angleSlider').value;
var displacement = byId('lengthSlider').value;
var originX = 128, originY = 128; // center of 256x256 canvas
var can = byId('outputCanvas');
var ctx = can.getContext('2d');
ctx.clearRect(0,0,can.width, can.height);
var xOfs, yOfs;
yOfs = displacement * Math.sin( angle * 3.141/180 );
xOfs = displacement * Math.cos( angle * 3.141/180 );
yOfs *= -1; // since canvas 0,0 is at top-left, rather than bottom-left. 90 deg should be above origin, not below it
ctx.beginPath();
ctx.moveTo(originX,originY);
ctx.lineTo( originX+xOfs, originY+yOfs );
ctx.closePath();
ctx.stroke();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
</script>
<style>
canvas
{
border: solid 1px black;
}
</style>
</head>
<body>
Angle <input type='range' value='0' min='0' max='360' id='angleSlider'/><span id='angleDisplay'></span><br>
Length <input type='range' value='0' min='0' max='181' id='lengthSlider'/><span id='lengthDisplay'></span><br> <!-- 181 = sqrt(2) * 128; i.e dist from center to corners of canvas -->
<canvas width='256' height='256' id='outputCanvas'></canvas>
</body>
</html>
Related
I'm tyring to rotate a diagram in canvas around its center while keeping the letters upright. I'm trying to use ctx.rotate(#) but it's rotating the entire diagram using what appears to be the left side of the canvas as the center.
The following link offers a visual: I want it to look like the green, not the red, as it currently does with my code. Visual Explanation
The following is the JSFiddle: http://jsfiddle.net/ddxarcag/143/
And my code is below:
<script>
$(document).ready(function () {
init();
function init() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
draw(ctx);
}
function draw(ctx) {
// layer1/Line
ctx.rotate(00);
ctx.beginPath();
ctx.moveTo(75.1, 7.7);
ctx.lineTo(162.9, 7.7);
ctx.stroke();
function WordSelector1() {
var word = ['A', 'B', 'C'];
var random = word[Math.floor(Math.random() * word.length)];
return random;
}
var x = WordSelector1();
// layer1/P
ctx.font = "12.0px 'Myriad Pro'";
ctx.rotate(0);
ctx.fillText(x, 60.0, 10.0);
}
});
</script>
Any help would be much appreciated. Thanks!
Drawing rotated graphs in canvas is somewhat easy once you know how to move the origin (0,0) to another point and then rotating the axes around it.
I added some comments in the code as not to repeat code and explanations.
I also moved the functions out of the $(document).ready and changed some numbers for more rounded values.
$(document).ready(function () {
init();
});
function init() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
draw(ctx);
}
function draw(ctx) {
ctx.font = "12.0px 'Myriad Pro'";
var angle = Math.random()*150; //Run more times to see other angles
//This translates the 0,0 to the center of the horizontal line
ctx.translate(100, 100);
//This draws the original straight line
ctx.beginPath();
ctx.moveTo(-50, 0); //The coordinates are relative to the new origin
ctx.lineTo(50, 0);
ctx.stroke();
//Draw the first letter
var x = WordSelector1();
ctx.fillText(x, -60, 0);
//This section draws the rotated line with the text straight
//Rotate the canvas axes by "angle"
ctx.rotate(angle * Math.PI/180);
ctx.beginPath();
ctx.moveTo(-50, 0); //The relative coordinates DO NOT change
ctx.lineTo(50, 0); //This shows that the axes rotate, not the drawing
ctx.stroke();
var x = WordSelector1();
ctx.translate(-60,0); //The origin must now move where the letter is to be placed
ctx.rotate(-angle * Math.PI/180); //Counter-rotate by "-angle"
ctx.fillText(x, 0, 0); //Draw the letter
}
function WordSelector1() {
var word = ['A', 'B', 'C'];
var random = word[Math.floor(Math.random() * word.length)];
return random;
}
canvas{
border: 1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="200" height="200"></canvas>
One warning: after everything is drawn the axes end parallel to the canvas borders because it was rotated by -angle, but the origin is where the last letter was placed. You may want to use ctx.save() and ctx.restore() to avoid having to revert translations and rotations.
This question already has an answer here:
How to fillstyle with Images in canvas html5
(1 answer)
Closed 7 years ago.
I'm trying to create a spinning wheel of sorts, where an image is displayed as a prize. I'm reusing a project I found online, and I'm pretty new to canvas, so I would appreciate some help.
This is how it looks, here an image would be displayed in each of the fields, with as angle to match the wheel. Here is the code generating it:
var outsideRadius = 210;
var textRadius = 160;
var insideRadius = 155;
ctx = canvas.getContext("2d");
ctx.clearRect(0,0,500,500);
ctx.strokeStyle = "#943127";
ctx.lineWidth = 4;
for(var i = 0; i < 12; i++) {
var angle = startAngle + i * arc;
ctx.fillStyle = '#a9382d';
ctx.beginPath();
ctx.arc(250, 250, outsideRadius, angle, angle + arc, false);
ctx.arc(250, 250, insideRadius, angle + arc, angle, true);
ctx.closePath();
ctx.stroke();
ctx.fill();
}
In each of the fields above should be displayed a image of a prize from an array. Im having problems drawing the images in the fields. I've tried using createPattern() without luck.
EDIT: Added jsfiddle: http://jsfiddle.net/46k72m7z/
To clip an image inside one of your wheel-wedges:
See illustration below.
Calculate the 4 vertices of your specified wedge.
Begin a new Path with context.beginPath and move to point0.
Draw a line from point0 to point1.
Draw an arc from point1 to point2.
Draw a line from point2 to point3.
Draw an arc from point3 back to point0.
Close the path (not needed, just being extra careful).
Call context.clip() to create a clipping area of your wedge.
Drawing the image at the appropriate angle
See illustration below.
Find the centerpoint of the wedge.
Set the canvas origin to that centerpoint with context.translate.
Calculate the angle from the wheel center (point#1 below) to the wedge center.
Rotate the canvas by the calculated angle.
Draw the image offset by half the image's width & height. This causes the image to be visually centered inside the wedge.
Other useful information
When you set a clip with context.clip the only way to undo that clip is to wrap the clip between context.save and context.restore. (Or resize the canvas, but that's counter-productive when you're trying to draw multiple clipped regions because all content is erased when the canvas is resized).
// save the begininning unclipped context state
context.save();
... draw your path
// create the clipping area
context.clip();
... draw the image inside the clipping area
// restore the context to its unclipped state
context.restore();
To center an image anywhere, find the center point where you want the image centered and then draw the image offset by half it's width & height:
ctx.drawImage( img,-img.width/2, -img.height/2 );
Calculating points on the circumference of a circle:
// given...
var centerX=150; // the circle's center
var centerY=150;
var radius=25; // the circle's radius
var angle=PI/2; // the desired angle on the circle (angles are expressed in radians)
var x = centerX + radius * Math.cos(angle);
var y = centerY + radius * Math.sin(angle);
An efficiency: The path command will automatically draw a line from the previous command's endpoint to your new command's startpoint. Therefore, you can skip step#3 & step#5 because the lines will be drawn automatically when you draw the arcs.
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
var PI=Math.PI;
var cx=250;
var cy=250;
var outsideRadius = 210;
var textRadius = 160;
var insideRadius = 155;
var wedgecount=12;
var arc=Math.PI*2/wedgecount;
var startAngle=-arc/2-PI/2;
var mm=new Image;
mm.onload=start;
mm.src='https://dl.dropboxusercontent.com/u/139992952/multple/mm1.jpg';
var goldCar=new Image();
goldCar.onload=start;
goldCar.src='https://dl.dropboxusercontent.com/u/139992952/multple/carGold.png';
var redCar=new Image();
redCar.onload=start;
redCar.src='https://dl.dropboxusercontent.com/u/139992952/multple/cars1.png';
var imgCount=2;
function start(){
if(++imgCount<2){return;}
drawWheel();
for(var i=0;i<wedgecount;i++){
var img=(i%2==0)?goldCar:redCar;
if(i==3){img=mm;}
clipImageToWedge(i,img);
}
}
function drawWheel(){
ctx.clearRect(0,0,500,500);
ctx.lineWidth = 4;
for(var i = 0; i < 12; i++) {
var angle = startAngle + i * arc;
ctx.fillStyle = '#a9382d';
ctx.beginPath();
ctx.arc(cx,cy, outsideRadius, angle, angle + arc, false);
ctx.arc(cx,cy, insideRadius, angle + arc, angle, true);
ctx.closePath();
ctx.stroke();
ctx.fill();
}
}
function clipImageToWedge(index,img){
var angle = startAngle+arc*index;
var angle1= startAngle+arc*(index+1);
var x0=cx+insideRadius*Math.cos(angle);
var y0=cy+insideRadius*Math.sin(angle);
var x1=cx+outsideRadius*Math.cos(angle);
var y1=cy+outsideRadius*Math.sin(angle);
var x3=cx+outsideRadius*Math.cos(angle1);
var y3=cy+outsideRadius*Math.sin(angle1);
ctx.save();
ctx.beginPath();
ctx.moveTo(x0,y0);
ctx.lineTo(x1,y1);
ctx.arc(cx,cy,outsideRadius,angle,angle1);
ctx.arc(cx,cy,insideRadius,angle1,angle,true);
ctx.clip();
var midRadius=(insideRadius+outsideRadius)/2;
var midAngle=(angle+angle1)/2;
var midX=cx+midRadius*Math.cos(midAngle);
var midY=cy+midRadius*Math.sin(midAngle);
ctx.translate(midX,midY);
ctx.rotate(midAngle+PI/2);
ctx.drawImage(img,-img.width/2,-img.height/2);
ctx.restore();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=500 height=500></canvas>
How can I restrict a line in a circle boundary?
I want my drawed line to be cut off when it exceeds the max length (100px) but the line keeps restricting inside a rectangle.
I think I'm missing something obvious but I can't figure it out.
var midX = canvas.width/2,
midY = canvas.height/2,
x = (mouseCurrent.x - midX),
y = (mouseCurrent.y - midY),
maxX = midX+clamp(x,-MAX_LENGTH,MAX_LENGTH),
maxY = midY+clamp(y,-MAX_LENGTH,MAX_LENGTH);
ctx.moveTo(midX, midY);
ctx.lineTo(maxX, maxY);
I've created a fiddle to show my problem:
fiddle
Your clamp function, when you pass it -MAX_LENGTH and MAX_LENGTH as the min and max boundaries, doesn't take into account anything related to the angle the line is at.
For example, in your picture, the y value would be clamped to -MAX_LENGTH, which obviously, from the middle, will extend to the bottom-most point of the circle, and the x value will be clamped to MAX_LENGTH, extending as far as the right-most point of the circle.
What you should do is calculate the angle made from the mouse position, and use the sine and cosine of that angle to determine the coordinates.
You'll want something like this:
var x = (mouseCurrent.x - midX),
y = (mouseCurrent.y - midY);
var angleInRadians = Math.atan2(x - midX, y - midY);
var realX = Math.cos(angleInRadians);
var realY = Math.sin(angleInRadians);
Then, from the realX and realY values, you should be able to create your line. You might have to tweak this a little bit. I tried to adjust based on the fact that the origin isn't at (0, 0).
Here's one way:
Get the angle from the mouse to the circle centerpoint.
Use trigonometry to get the point at radius distance at the calculated angle.
draw a line from the centerpoint to the calculated point on the circumference.
Example code and a Demo: http://jsfiddle.net/m1erickson/Zje8Y/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var isDown=false;
var startX;
var startY;
draw(100,100);
function draw(x,y){
var cx=150;
var cy=150;
var r=50;
var dx=x-cx;
var dy=y-cy;
var angle=Math.atan2(dy,dx);
var xx=cx+r*Math.cos(angle);
var yy=cy+r*Math.sin(angle);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc(cx,cy,r,0,Math.PI*2);
ctx.closePath();
ctx.stroke()
ctx.beginPath();
ctx.arc(x,y,5,0,Math.PI*2);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(cx,cy);
ctx.lineTo(xx,yy);
ctx.stroke();
ctx.beginPath();
ctx.arc(xx,yy,5,0,Math.PI*2);
ctx.closePath();
ctx.fill();
}
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
draw(mouseX,mouseY);
}
$("#canvas").mousemove(function(e){handleMouseMove(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
You can use basic trigonometry to calculate the angle and you can find the point intersecting with both the line and the circle.
First use tangent of the line to calculate angle. Then use angle value to find x and y coordinates of the point that you are looking for. Here is the code:
angle = Math.atan2(mouseCurrent.y - midY, mouseCurrent.x - midX);
maxY = midY + Math.sin(angle) * MAX_LENGTH;
maxX = midX + Math.cos(angle) * MAX_LENGTH;
I have drawn a polygon with the following code. Now I want to resize that polygon animatedly. In detail, I want to set an angular movement to one side of the polygon, such that it makes an arc, and so changes the size of polygon. I googled for everything regarding the polygon animation, but didn't get anything, though there is plenty of material for line animation.
<script>
$(function(){
var c=$('#myCanvas');
var ctx=c.getContext("2d");
ctx.fillStyle='#f00';
ctx.beginPath();
ctx.moveTo(0,40);
ctx.lineTo(80,200);
ctx.lineTo(100,200);
ctx.lineTo(40,0);
ctx.closePath();
ctx.fill();
</script>
</div>
Is it possible to pick a line of a polygon and animate it, to change the shape of the polygon?
The trick is to store the coordinates of the polygon in an array and work on the numbers in that array instead.
Then render what you have in the array to canvas. Worry-free when it comes to translation and what-have-you.
See canvas as only a snapshot of whatever you have in the array at the moment.
Ok this is what I did and which has worked out:
<script>
var canvas = document.getElementById("myCanvas");
var dc = canvas.getContext("2d");
var angle = 0;
var x = canvas.width;
var y = canvas.height;
window.setInterval(function(){
angle = (angle + 1) % 360;
dc.clearRect(0, 0, canvas.width, canvas.height);
dc.save();
dc.fillStyle = "#DDDDDD";
dc.translate(x/2,y);
dc.rotate( angle*Math.PI/270 ); // rotate 90 degrees
dc.translate(0,0);
dc.beginPath();
dc.moveTo(-x/16, 0);
dc.lineTo(-x, y/2);
dc.lineTo(-x/2,y);
dc.lineTo(-0,y/16);
dc.closePath();
dc.fill();
dc.restore();
}, 20);
</script>
I referred to Bill's answer at https://stackoverflow.com/a/2767556/2163837 Thanks for your help also.
Here’s how to turn a triangle into a square, a square into a pentagon, etc ….
This code draws a regular polygon with the specified number of sides:
function drawPolygon(sideCount,size,centerX,centerY){
// draw a regular polygon with sideCount sides
ctx.save();
ctx.beginPath();
ctx.moveTo (centerX + size * Math.cos(0), centerY + size * Math.sin(0));
for (var i = 1; i <= sideCount;i += 1) {
var x=centerX + size * Math.cos(i * 2 * Math.PI / sideCount);
var y=centerY + size * Math.sin(i * 2 * Math.PI / sideCount);
ctx.lineTo (x, y);
}
ctx.stroke();
ctx.fill();
ctx.restore();
}
Animating odd-sided polygons into even-sided polygons
In this illustration, you can animate a triangle into a square by animating each colored vertex on the triangle to its corresponding position on the square. All odd-sided polygons are transformed into even-sided polygons that same way.
Animating even-sided polygons into odd-sided polygons
In this illustration, you can animate a square into a pentagon by animating each colored vertex on the square to its corresponding position on the pentagon. In this case, you have to also cut the left-most yellow vertex in two and animate the two portions to the two yellow vertices on the pentagon. All even-sided polygons are transformed into odd-sided polygons that same way.
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/DjV5f/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:10px; }
canvas{border:1px solid red;}
p{font-size:24px;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
//
var colors=["","blue","green","black"];
drawPolygon(3,50,70,70,2,"blue","red",colors,true);
colors=["","blue","yellow","green","black"];
drawPolygon(4,50,215,70,2,"blue","red",colors,false);
//
ctx.beginPath();
ctx.moveTo(0,162);
ctx.lineTo(300,162);
ctx.stroke();
//
var colors=["black","blue","yellow","green"];
drawPolygon(4,50,70,250,2,"blue","red",colors,true);
colors=["black","blue","yellow","yellow","green"];
drawPolygon(5,50,215,250,2,"blue","red",colors,false);
function drawPolygon(sideCount,size,centerX,centerY,strokeWidth,strokeColor,fillColor,colorPts,showBursePoint){
// draw a regular polygon with sideCount sides
ctx.save();
ctx.beginPath();
ctx.moveTo (centerX + size * Math.cos(0), centerY + size * Math.sin(0));
for (var i = 1; i <= sideCount;i += 1) {
var x=centerX + size * Math.cos(i * 2 * Math.PI / sideCount);
var y=centerY + size * Math.sin(i * 2 * Math.PI / sideCount);
ctx.lineTo (x, y);
}
ctx.fillStyle=fillColor;
ctx.strokeStyle = strokeColor;
ctx.lineWidth = strokeWidth;
ctx.stroke();
ctx.fill();
ctx.restore();
// draw vertex points
for (var i = 1; i <= sideCount;i += 1) {
var x=centerX + size * Math.cos(i * 2 * Math.PI / sideCount);
var y=centerY + size * Math.sin(i * 2 * Math.PI / sideCount);
drawPoint(x,y,colorPts[i]);
}
// draw point where this poly will "burst" to create next poly
if(showBursePoint){
var burstX= centerX + size * Math.cos( Math.floor(sideCount/2) * 2 * Math.PI / sideCount);
var burstY= centerY;
drawPoint(burstX, burstY, "yellow");
}
}
function drawPoint(x,y,fill){
ctx.save()
ctx.strokeStyle="black";
ctx.lineWidth=2;
ctx.fillStyle=fill;
ctx.beginPath();
ctx.arc(x,y,6,0,Math.PI*2,false);
ctx.fill();
ctx.stroke();
ctx.restore();
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Regular polygons (3-8 sides)</p><br/>
<p>Unmoving anchor point is green</p><br/>
<p>Burst point is yellow</p><br/>
<canvas id="canvas" width=300 height=350></canvas>
</body>
</html>
I'm trying to draw a circle, kind of a clock, i start at point p1 and draw an arc in black using the canvas 2d context, when i reach the point p1 (complete circle tour) i change color to white, and continue to draw, that should give it an effect like if the black arc is being erased, however this doesn't work as expected, because when i change the context's color, everything change...
how to keep the first circle, in a color, and draw another one on topof it with different color, without changing the color in the whole scene ?
here's my attempt
<!DOCTYPE html />
<html>
<head>
<title></title>
<script type="text/javascript">
var i = 0.01;
var Color = "Black";
var x = 75; // x coordinate
var y = 75; // y coordinate
var radius = 20; // Arc radius
var startAngle = 0; // Starting point on circle
var anticlockwise = false; // clockwise or anticlockwise
function draw() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
var endAngle = i; // End point on circleMath.PI + (Math.PI * 5) /
if (Math.floor(endAngle) >= 6) {
i = 0.01;
if (Color == "Black") {
Color = "White";
} else {
Color = "Black";
}
}
ctx.strokeStyle = Color;
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
ctx.stroke();
i = i + 0.05;
//document.getElementById('display').innerHTML = Math.floor(endAngle) + " " + Color;
}
</script>
</head>
<body onload="window.setInterval(function(){draw()},100);">
<canvas id="canvas" width="150" height="150"></canvas>
<span id="display"></span>
</body>
</html>
You're having a little trouble with your angles. You're essentially redrawing the arc from 0 to your endAngle every time. So at the end when endAngle is greater than 6 you're redrawing from 0-6 with a white arc.
The easy fix is to just set endAngle = 0.01 when you reset i. You may also want to update your startAngle on each iteration to be the end of your last arc, just so that it doesn't draw over itself all the time.
Hope this helps!
Using Shaded's answer, you could do the following:
if (Math.floor(endAngle) > 6.0) {
i = 0.01;
endAngle = i;
startAngle = 0;
if (Color == "Black") {
Color = "White";
ctx.lineWidth = 4;
} else {
Color = "Black";
ctx.lineWidth = 1;
}
}
ctx.strokeStyle = Color;
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
ctx.stroke();
startAngle = endAngle - 0.1;
Because the white will anti-alias with the black behind it, you'll get the jaggies at the edges if the line widths are the same. Increasing the line width alleviates this issue.
EDIT: Updated to remove excessive over-painting as per Shaded's comments.