zarocknz/javascript-winwheel

2 direction outer/inner image wheel

Vizzielli opened this issue · 6 comments

Hi, I'm trying make a responsive wheel like this:

  • Outer section (clockwise rotation) + tick audio + fixed final angle
  • Inner section (anti-clockwise rotation) + fixed final angle
  • Fixed center

I used docs and mainly this examples:

  • responsive wheel
  • two_part_wheel
  • pins_and_sound_wheel
  • basic_image_wheel

Now, no problem using responsive, tick audio, images. Problem comes using two part wheels using images. I tried a lot but cant afford to get a working result. Current code show me outer wheel + center, the inner wheel space is transparent. At the end, I think also that if I find a way to show inner image too, then there is any chance of giving inner wheel an anti-clockwise rotation during the clockwise rotation of the outer wheel?

Here my current not-full-working code:

    <body>
        <div align="center">
            <table cellpadding="0" cellspacing="0" border="0">
                <tr>
                    <td width="1632" height="1632" class="the_wheel" align="center" valign="center">
                        <canvas id="canvas" width="1632" height="1632" data-responsiveMinWidth="180" data-responsiveScaleHeight="true" onClick="startSpin();">
                            <p>Sorry, your browser doesn't support canvas. Please try another.</p>
                        </canvas>
                    </td>
                </tr>
            </table>
        </div>
        <script>
            // Inner wheel
            let innerWheel = new Winwheel({
                'numSegments': 12,
                'drawMode': 'image',
                'drawText': false,
                'responsive': true,
                'pins': {
                    'number': 12,
                    'outerRadius': 0,
                    'responsive': true,
                    'margin': 0,
                    'fillStyle': '',
                    'strokeStyle': ''
                }
            });

            // Outer wheel
            let outerWheel = new Winwheel({
                'numSegments': 64,
                'drawMode': 'image',
                'drawText': false,
                'responsive': true,
                'animation': {
                    'type': 'spinToStop',
                    'duration': 6,
                    'spins': 1,
                    'stopAngle': 330,
                    'callbackSound': tickPlay,
                    'soundTrigger': 'pin'
                },
                'pins': {
                    'number': 64,
                    'outerRadius': 0,
                    'responsive': true,
                    'margin': 0,
                    'fillStyle': '',
                    'strokeStyle': ''
                }
            });

            let outerImg = new Image();
            outerWheel.wheelImage = outerImg;
            outerWheel.draw();
            outerImg.src = "outerImg.png";

            let innerImg = new Image();
            innerWheel.wheelImage = innerImg;
            innerWheel.draw(false); // Pass false to stop it clearing the canvas and wiping the outer wheel.
            innerImg.src = "innerImg.png";

            function drawInnerWheel() {
                innerWheel.rotationAngle = outerWheel.rotationAngle;
                innerWheel.draw(false);
            }

            // -----------------------------------------------------------------
            // Load tick audio
            // -----------------------------------------------------------------
            let tickAudio = new Audio('tick.mp3');

            function tickPlay() {
                tickAudio.pause();
                tickAudio.currentTime = 0;
                tickAudio.play();
            }

            // -----------------------------------------------------------------
            // Start the wheel
            // -----------------------------------------------------------------
            function startSpin() {
                outerWheel.stopAnimation(false);
                innerWheel.stopAnimation(false);
                outerWheel.rotationAngle = outerWheel.rotationAngle % 360;
                innerWheel.rotationAngle = outerWheel.rotationAngle % 360;

                // Start animation.
                outerWheel.startAnimation();
            }
        </script>
    </body>

Any suggestion will be appreciated!

Hi Gian,

You don't appear to be calling the drawInnerWheel() function from anywhere. I think you need to add this line to the outerWheel animation config...

'callbackAfter' : drawInnerWheel,

To make the inner wheel rotate anti-clockwise in the drawInnerWheel() function set the innerWheel.rotationAngle to negative that of the outerWheel

function drawInnerWheel() {
    innerWheel.rotationAngle = -outerWheel.rotationAngle;
    innerWheel.draw(false);
}

Cheers,
DouG.

Thank you DouG!

In the meanwhile I put had some edits to the code above here, and I'm try to figure out how to implement correctly your solution.

Now the 2 wheels rotate but:

  • on page load I can't see the inner wheel
  • after clic all seems ok (except when reducing the size of the window: the inner wheel isnt responsive like everything else)
  • if resize the windows after the end of animation, inner wheel disappear again.

Here the update. I sent you also a collaboration in private repository with all the files if this can help to try it without waste of time. All fix I tried broke completely it (mainly the inner wheel never rotate or jump to the final result without animation, some time all wheels broken..). Thank you for any advice!

    <body>
        <div align="center">
            <table cellpadding="0" cellspacing="0" border="0">
                <tr>
                    <td width="1048" height="1048" class="the_wheel" align="center" valign="center">
                        <canvas id="canvas" width="1048" height="1048" data-responsiveMinWidth="180" data-responsiveScaleHeight="true" onClick="startSpin();">
                            <p>Sorry, your browser doesn't support canvas. Please try another.</p>
                        </canvas>
                    </td>
                </tr>
            </table>
        </div>
        <script>
            // Inner wheel
            let innerWheel = new Winwheel({
                'numSegments': 12,
                'drawMode': 'image',
                'drawText': false,
                'responsive': true,
                'animation': {
                    'type': 'spinToStop',
                    'duration': 6,
                    'spins': 1
                },
                'pins': {
                    'number': 12,
                    'outerRadius': 0,
                    'responsive': true,
                    'margin': 0,
                    'fillStyle': '',
                    'strokeStyle': ''
                }
            });

            // Outer wheel
            let outerWheel = new Winwheel({
                'numSegments': 64,
                'drawMode': 'image',
                'drawText': false,
                'responsive': true,
                'animation': {
                    'type': 'spinToStop',
                    'duration': 6,
                    'spins': 1,
                    'stopAngle': 360,
                    'callbackAfter' : drawInnerWheel,
                    'callbackSound': tickPlay,
                    'soundTrigger': 'pin'
                },
                'pins': {
                    'number': 64,
                    'outerRadius': 0,
                    'responsive': true,
                    'margin': 0,
                    'fillStyle': '',
                    'strokeStyle': ''
                }
            });

            let outerImg = new Image();
            outerWheel.wheelImage = outerImg;
            outerWheel.draw();
            outerImg.src = "img/outerImg.png";

            let innerImg = new Image();
            innerWheel.wheelImage = innerImg;
            innerWheel.draw(); // Pass false to stop it clearing the canvas and wiping the outer wheel.
            innerImg.src = "img/innerImg.png";

            function drawInnerWheel() {
                let innerAngle = 180;
                innerWheel.rotationAngle = -outerWheel.rotationAngle - (360 - innerAngle);
                innerWheel.draw(false);
            }

            // -----------------------------------------------------------------
            // Load tick audio
            // -----------------------------------------------------------------
            let tickAudio = new Audio('audio/tick.mp3');
            tickAudio.preload; // It works? Seems not. Find preload...

            function tickPlay() {
                tickAudio.pause();
                tickAudio.currentTime = 0;
                tickAudio.play();
            }

            // -----------------------------------------------------------------
            // Start the wheel
            // -----------------------------------------------------------------
            function startSpin() {
                outerWheel.stopAnimation(false);
                outerWheel.rotationAngle = outerWheel.rotationAngle % 360;
                outerWheel.startAnimation();
            }
        </script>
    </body>

Another quesitons, there's a way to preload the audio? Because for the first clic it start after some seconds..

Hi Gian,

Thanks for giving access to your repo, makes it a heck of a lot easier to see what is going on! Yeah a few problems :(

Winwheel.js is only really designed to work with one wheel, as noted at the top of this example http://dougtesting.net/winwheel/examples/two_part_wheel there are issues with multiwheels.

The main culprit is a single winwheelToDrawDuringAnimation variable which, as well as being used for animations, is also used in the resize code which is why its not working for both wheels.

I have some ideas on how to possibly make this work - I have experimented with multiwheel several times in the past (from memory it was changing winwheelToDrawDuringAnimation to an array and updating the draw code to loop the array) so I'll create a feature branch and have a play around tomorrow to see if I can get things working.

Regards,
DouG.

Hi DouG,

I read and I only get a doubt about the framerate problems with the previous attempts made:
Currently I had similar problem, when I setup the 'stopAngle': directly inside the innerWheel animation options and used the value below, the effect obtained during the rotation was the doubling of the internal wheel, as if it were going much faster...

I don't understand the reason, but I solved the problem by avoiding setting the final angle above, but setting it directly in the portion of code that uses that value:

            function drawInnerWheel() {
                let innerAngle = 180;
                innerWheel.rotationAngle = -outerWheel.rotationAngle - (360 - innerAngle);
                innerWheel.draw(false);
            }

Is it possible to recover your previous tests? Because if the problem was about framerate only, you could give it a try this way.

Unfortunately js is not my favorite language and I only use it when it is strictly necessary, so I cannot give you a big hand apart from relying on the tests done in the last few days.

Thank you for the new attempt you will make, in the meantime, based on the latest information you have written, however, I'll try to check it too.

Regards,
Gianluigi

Hi,

I spent several hours working on this and I think I have sorted. Please take a look at the PR I sent you and have a test out. Fortunately I still had the multiwheel experiment code from a couple of years ago so was able to take a fresh copy of Winwheel.js and alter the places needed to support Multiwheel.

Hit some strange issues with the responsive that took quite a while to figure out. Solution is a bit hacky but hopefully it works OK.

Both wheels should now show on load and the resize should work as expected. Note that the inner wheel is no longer connected to the outer wheel as before; now you control its animation just like the outer wheel.

Let me know if it works or if there are still any problems. Will have time for one more look before I go back to work next week.

Cheers,
DouG.

Hi DouG,

This seems perfect!

At first glance I did not understand where the final rotation of the internal wheel was set. It was not set so I think in that case it stops at a random rotation angle. So it's ok.

I removed: _outerWheel.rotationAngle = ; and _innerWheel.rotationAngle = ; inside startSpin() because no more needed.

Really thank you, the result is now what I was looking for.

I only add some info following tests with different browsers, in case someone had the opportunity to suggest solutions at least for firefox...

Ok tests:

  • android chrome
  • windows chrome 79.x
  • windows brave 1.1.x (chromium 79.x)
  • windows edge 44.x
  • windows ie11

Problems I didn't expect:

While other browsers load audio with some latency, firefox seems to be much slower. It only loads the last 2 ticks on a 180 degree rotation and 4 ticks on 360 degrees, and maybe so on...

This solved latency issues on all other browsers, but firefox seems to ignore this too:

<audio controls preload="auto" style="display: none;">
  <source src="audio/tick.mp3" type="audio/mpeg">
</audio>

Known issues, don't know if today there's a chance to overcome the apple will:

  • ios mobile devices don't let you hear the audio even if you start the wheel/audio with a click.

Thanks again,
Gianluigi.