Skip to content

Commit 00bbfd4

Browse files
committed
Initial feature code and example
Added one segment per image feature and created basic example wheel.
1 parent 8692fbb commit 00bbfd4

File tree

14 files changed

+501
-5
lines changed

14 files changed

+501
-5
lines changed

Winwheel.js

Lines changed: 209 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function Winwheel(options, drawWheel)
3838
'outerRadius' : null, // The radius of the outside of the wheel. If left null it will be set to the radius from the center of the canvas to its shortest side.
3939
'innerRadius' : 0, // Normally 0. Allows the creation of rings / doughnuts if set to value > 0. Should not exceed outer radius.
4040
'numSegments' : 1, // The number of segments. Need at least one to draw.
41-
'drawMode' : 'code', // The draw mode. Possible values are 'code' and 'image'. Default is code which means segments are drawn using canvas arc() function.
41+
'drawMode' : 'code', // The draw mode. Possible values are 'code', 'image', 'segmentImage'. Default is code which means segments are drawn using canvas arc() function.
4242
'rotationAngle' : 0, // The angle of rotation of the wheel - 0 is 12 o'clock position.
4343
'textFontFamily' : 'Arial', // Segment text font, you should use web safe fonts.
4444
'textFontSize' : 20, // Size of the segment text.
@@ -182,7 +182,7 @@ function Winwheel(options, drawWheel)
182182

183183
// ------------------------------------------
184184
// On that note, if the drawMode is image change some defaults provided a value has not been specified.
185-
if (this.drawMode == 'image')
185+
if ((this.drawMode == 'image') || (this.drawMode == 'segmentImage'))
186186
{
187187
// Remove grey fillStyle.
188188
if (typeof(options['fillStyle']) === 'undefined')
@@ -237,6 +237,23 @@ function Winwheel(options, drawWheel)
237237
if (drawWheel == true)
238238
{
239239
this.draw(this.clearTheCanvas);
240+
}
241+
else if (this.drawMode == 'segmentImage')
242+
{
243+
// If segment image then loop though all the segments and load the images for them setting a callback
244+
// which will call the draw function of the wheel once all the images have been loaded.
245+
winwheelToDrawDuringAnimation = this;
246+
winhweelAlreadyDrawn = false;
247+
248+
for (y = 1; y <= this.numSegments; y ++)
249+
{
250+
if (this.segments[y].image !== null)
251+
{
252+
this.segments[y].imgData = new Image();
253+
this.segments[y].imgData.onload = winwheelLoadedImage;
254+
this.segments[y].imgData.src = this.segments[y].image;
255+
}
256+
}
240257
}
241258
}
242259

@@ -350,6 +367,25 @@ Winwheel.prototype.draw = function(clearTheCanvas)
350367
this.drawSegments();
351368
}
352369
}
370+
else if (this.drawMode == 'segmentImage')
371+
{
372+
// Draw the wheel by rendering the image for each segment.
373+
this.drawSegmentImages();
374+
375+
// If we are to draw the text, do so before the overlay is drawn
376+
// as this allows the overlay to be used to create some interesting effects.
377+
if (this.drawText == true)
378+
{
379+
this.drawSegmentText();
380+
}
381+
382+
// If image overlay is true then call function to draw the segments over the top of the image.
383+
// This is useful during development to check alignment between where the code thinks the segments are and where they appear on the image.
384+
if (this.imageOverlay == true)
385+
{
386+
this.drawSegments();
387+
}
388+
}
353389
else
354390
{
355391
// The default operation is to draw the segments using code via the canvas arc() method.
@@ -427,6 +463,109 @@ Winwheel.prototype.drawWheelImage = function()
427463
}
428464
}
429465

466+
// ====================================================================================================================
467+
// This function draws the wheel on the canvas by rendering the image for each segment.
468+
// ====================================================================================================================
469+
Winwheel.prototype.drawSegmentImages = function()
470+
{
471+
// Again check have context in case this function was called directly and not via draw function.
472+
if (this.ctx)
473+
{
474+
// Draw the segments if there is at least one in the segments array.
475+
if (this.segments)
476+
{
477+
// Loop though and output all segments - position 0 of the array is not used, so start loop from index 1
478+
// this is to avoid confusion when talking about the first segment.
479+
for (x = 1; x <= this.numSegments; x ++)
480+
{
481+
// Get the segment object as we need it to read options from.
482+
seg = this.segments[x];
483+
484+
// Check image has loaded so a property such as height has a value.
485+
if (seg.imgData.height)
486+
{
487+
// Work out the correct X and Y to draw the image at which depends on the direction of the image.
488+
// Images can be created in 4 directions. North, South, East, West.
489+
// North: Outside at top, inside at bottom. Sits evenly over the 0 degrees angle.
490+
// South: Outside at bottom, inside at top. Sits evenly over the 180 degrees angle.
491+
// East: Outside at right, inside at left. Sits evenly over the 90 degrees angle.
492+
// West: Outside at left, inside at right. Sits evenly over the 270 degrees angle.
493+
var imageLeft = 0;
494+
var imageTop = 0;
495+
var imageAngle = 0;
496+
497+
if (seg.imageDirection == 'S')
498+
{
499+
// Left set so image sits half/half over the 180 degrees point.
500+
imageLeft = (this.centerX - (seg.imgData.width / 2));
501+
502+
// Top so image starts at the centerY.
503+
imageTop = this.centerY;
504+
505+
// Angle to draw the image is its starting angle + half its size.
506+
// Here we add 180 to the angle to the segment is poistioned correctly.
507+
imageAngle = (seg.startAngle + 180 + ((seg.endAngle - seg.startAngle) / 2));
508+
}
509+
else if (seg.imageDirection == 'E')
510+
{
511+
// Left set so image starts and the center point.
512+
imageLeft = this.centerX;
513+
514+
// Top is so that it sits half/half over the 90 degree point.
515+
imageTop = (this.centerY - (seg.imgData.height / 2));
516+
517+
// Again get the angle in the center of the segment and add it to the rotation angle.
518+
// this time we need to add 270 to that to the segment is rendered the correct place.
519+
imageAngle = (seg.startAngle + 270 + ((seg.endAngle - seg.startAngle) / 2));
520+
}
521+
else if (seg.imageDirection == 'W')
522+
{
523+
// Left is the centerX minus the width of the image.
524+
imageLeft = (this.centerX - seg.imgData.width);
525+
526+
// Top is so that it sits half/half over the 270 degree point.
527+
imageTop = (this.centerY - (seg.imgData.height / 2));
528+
529+
// Again get the angle in the center of the segment and add it to the rotation angle.
530+
// this time we need to add 90 to that to the segment is rendered the correct place.
531+
imageAngle = (seg.startAngle + 90 + ((seg.endAngle - seg.startAngle) / 2));
532+
}
533+
else // North is the default.
534+
{
535+
// Left set so image sits half/half over the 0 degrees point.
536+
imageLeft = (this.centerX - (seg.imgData.width / 2));
537+
538+
// Top so image is its height out (above) the center point.
539+
imageTop = (this.centerY - seg.imgData.height);
540+
541+
// Angle to draw the image is its starting angle + half its size.
542+
// this sits it half/half over the center angle of the segment.
543+
imageAngle = (seg.startAngle + ((seg.endAngle - seg.startAngle) / 2));
544+
}
545+
546+
// --------------------------------------------------
547+
// Rotate to the position of the segment and then draw the image.
548+
this.ctx.save();
549+
this.ctx.translate(this.centerX, this.centerY);
550+
551+
// So math here is the rotation angle of the wheel plus half way between the start and end angle of the segment.
552+
this.ctx.rotate(this.degToRad(this.rotationAngle + imageAngle));
553+
this.ctx.translate(-this.centerX, -this.centerY);
554+
555+
// Draw the image.
556+
this.ctx.drawImage(seg.imgData, imageLeft, imageTop);
557+
558+
this.ctx.restore();
559+
}
560+
else
561+
{
562+
console.log('Segment ' + x + ' imgData is not loaded');
563+
}
564+
}
565+
}
566+
}
567+
}
568+
430569
// ====================================================================================================================
431570
// This function draws the wheel on the page by rendering the segments on the canvas.
432571
// ====================================================================================================================
@@ -1843,7 +1982,10 @@ function Segment(options)
18431982
'textMargin' : null,
18441983
'textFillStyle' : null,
18451984
'textStrokeStyle' : null,
1846-
'textLineWidth' : null
1985+
'textLineWidth' : null,
1986+
'image' : null, // Name/path to the image
1987+
'imageDirection' : 'N', // The direction the image is facing. Can be North, South, East, West.
1988+
'imgData' : null // Image object created here and loaded with image data.
18471989
};
18481990

18491991
// Now loop through the default options and create properties of this class set to the value for
@@ -1876,6 +2018,33 @@ function Segment(options)
18762018
this.endAngle = 0;
18772019
}
18782020

2021+
// ====================================================================================================================
2022+
// Changes an image for a segment by setting a callback to render the wheel once the image has loaded.
2023+
// ====================================================================================================================
2024+
Segment.prototype.changeImage = function(image, imageDirection)
2025+
{
2026+
// Change image name, blank image data.
2027+
this.image = image;
2028+
this.imgData = null;
2029+
2030+
// Set direction.
2031+
if (imageDirection)
2032+
{
2033+
this.imageDirection = imageDirection;
2034+
}
2035+
else
2036+
{
2037+
// North is the default.
2038+
this.imageDirection = 'N';
2039+
}
2040+
2041+
// Set imgData to a new image object, change set callback and change src (just like in wheel constructor).
2042+
winhweelAlreadyDrawn = false;
2043+
this.imgData = new Image();
2044+
this.imgData.onload = winwheelLoadedImage;
2045+
this.imgData.src = this.image;
2046+
}
2047+
18792048
// ====================================================================================================================
18802049
// Class that is created as property of the wheel. Draws line from center of the wheel out to edge of canvas to
18812050
// indicate where the code thinks the pointer location is. Helpful to get alignment correct esp when using images.
@@ -1923,8 +2092,6 @@ function winwheelPercentToDegrees(percentValue)
19232092
// In order for the wheel to be re-drawn during the spin animation the function greesock calls needs to be outside
19242093
// of the class as for some reason it errors if try to call winwheel.draw() directly.
19252094
// ====================================================================================================================
1926-
var winwheelToDrawDuringAnimation = null; // This global is set by the winwheel class to the wheel object to be re-drawn.
1927-
19282095
function winwheelAnimationLoop()
19292096
{
19302097
if (winwheelToDrawDuringAnimation)
@@ -1956,6 +2123,8 @@ function winwheelAnimationLoop()
19562123
// This function is called-back when the greensock animation has finished. We remove the event listener to the function
19572124
// above to stop the wheel being re-drawn all the time even though it is not animating as the greensock ticker keeps going.
19582125
// ====================================================================================================================
2126+
var winwheelToDrawDuringAnimation = null; // This global is set by the winwheel class to the wheel object to be re-drawn.
2127+
19592128
function winwheelStopAnimation(canCallback)
19602129
{
19612130
// Remove the redraw from the ticker.
@@ -1970,4 +2139,39 @@ function winwheelStopAnimation(canCallback)
19702139
eval(winwheelToDrawDuringAnimation.animation.callbackFinished);
19712140
}
19722141
}
2142+
}
2143+
2144+
// ====================================================================================================================
2145+
// Called after the image has loaded for each segment. Once all the images are loaded it then calls the draw function
2146+
// on the wheel to render it. Used in constructor and also when a segment image is changed.
2147+
// ====================================================================================================================
2148+
var winhweelAlreadyDrawn = false;
2149+
2150+
function winwheelLoadedImage()
2151+
{
2152+
// Prevent multiple drawings of the wheel which ocurrs without this check due to timing of function calls.
2153+
if (winhweelAlreadyDrawn == false)
2154+
{
2155+
// Set to 0.
2156+
var winwheelImageLoadCount = 0;
2157+
2158+
// Loop though all the segments of the wheel and check if image data loaded, if so increment counter.
2159+
for (i = 1; i <= winwheelToDrawDuringAnimation.numSegments; i ++)
2160+
{
2161+
// Check the image data object is not null and also that the image has completed loading by checking
2162+
// that a property of it such as the height has some sort of true value.
2163+
if ((winwheelToDrawDuringAnimation.segments[i].imgData != null) && (winwheelToDrawDuringAnimation.segments[i].imgData.height))
2164+
{
2165+
winwheelImageLoadCount ++;
2166+
}
2167+
}
2168+
2169+
// If number of images loaded matches the segments then all the images for the wheel are loaded.
2170+
if (winwheelImageLoadCount == winwheelToDrawDuringAnimation.numSegments)
2171+
{
2172+
// Call draw function to render the wheel.
2173+
winhweelAlreadyDrawn = true;
2174+
winwheelToDrawDuringAnimation.draw();
2175+
}
2176+
}
19732177
}
27.5 KB
Loading
26.7 KB
Loading

0 commit comments

Comments
 (0)