0

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.

enter image description here

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/

  • Not sure what your question is. Can you state it explicitly? Also, what have you tried to get this to work, and where are you having problems? It'd be helpful if you created a [jsfiddle](http://jsfiddle.net) for it so we can see the entire code of what you're trying to do. – delliottg Jun 14 '15 at 19:02
  • Here you go http://jsfiddle.net/46k72m7z/. I want to display an image in each of the fields on the wheel. This image would be of a prize. –  Jun 14 '15 at 19:08
  • you should write a function that draws prizes that can look like `drawRouletteWheel();` – maioman Jun 14 '15 at 19:27
  • The problem is placing the images correctly using clip(); Which i cant get to work –  Jun 14 '15 at 19:28
  • Your [first question](http://stackoverflow.com/questions/30831467/html5-javascript-canvas-clip-an-image-to-a-shape) was closed as duplicate. Instead of deleting it and creating a new exact copy, you can edit the content and have it reviewed for reopening. –  Jun 15 '15 at 03:44

1 Answers1

0

enter image description here

To clip an image inside one of your wheel-wedges:

See illustration below.

  1. Calculate the 4 vertices of your specified wedge.
  2. Begin a new Path with context.beginPath and move to point0.
  3. Draw a line from point0 to point1.
  4. Draw an arc from point1 to point2.
  5. Draw a line from point2 to point3.
  6. Draw an arc from point3 back to point0.
  7. Close the path (not needed, just being extra careful).
  8. Call context.clip() to create a clipping area of your wedge.

enter image description here

Drawing the image at the appropriate angle

See illustration below.

  1. Find the centerpoint of the wedge.
  2. Set the canvas origin to that centerpoint with context.translate.
  3. Calculate the angle from the wheel center (point#1 below) to the wedge center.
  4. Rotate the canvas by the calculated angle.
  5. Draw the image offset by half the image's width & height. This causes the image to be visually centered inside the wedge.

enter image description here

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>
markE
  • 102,905
  • 11
  • 164
  • 176