在React.js中使用HTML5 Lucky Wheel

时间:2018-08-04 15:09:50

标签: javascript reactjs undefined

我正在我的reactjs应用程序https://konvajs.github.io/docs/sandbox/Wheel_of_Fortune.html

中实现这种“幸运之轮”

这是组件的代码:

 import React from "react";
import { Link } from "react-router-dom";


class RollTabak extends React.Component {
    constructor() {
        super();
        var width = window.innerWidth;
        var height = window.innerHeight;

        Konva.angleDeg = false;
        var angularVelocity = 6;
        var angularVelocities = [];
        var lastRotation = 0;
        var controlled = false;
        var numWedges = 25;
        var angularFriction = 0.2;
        var target, activeWedge, stage, layer, wheel, pointer;
        var finished = false;

      }
    render() {

        return (
            <div>
               <div id="container"></div>
            </div>
        );
    }


    componentDidMount(){
        this.init();
    }
    getAverageAngularVelocity() {
        var total = 0;
        var len = this.angularVelocities.length;

        if (len === 0) {
            return 0;
        }

        for (var n = 0; n < len; n++) {
            total += this.angularVelocities[n];
        }

        return total / len;
    }
    purifyColor(color) {
        var randIndex = Math.round(Math.random() * 3);
        color[randIndex] = 0;
        return color;
    }
    getRandomColor() {
        var r = 100 + Math.round(Math.random() * 55);
        var g = 100 + Math.round(Math.random() * 55);
        var b = 100 + Math.round(Math.random() * 55);
        var color = [r, g, b];
        color = purifyColor(color);
        color = purifyColor(color);

        return color;
    }
    bind() {
        this.wheel.on('mousedown', function (evt) {
            this.angularVelocity = 0;
            this.controlled = true;
            this.target = evt.target;
            this.finished = false;
        });
        // add listeners to container
        document.body.addEventListener('mouseup', function () {
            this.controlled = false;
            this.angularVelocity = getAverageAngularVelocity() * 5;

            if (this.angularVelocity > 20) {
                this.angularVelocity = 20;
            }
            else if (this.angularVelocity < -20) {
                this.angularVelocity = -20;
            }

            this.angularVelocities = [];
        }, false);

        document.body.addEventListener('mousemove', function (evt) {
            var mousePos = this.stage.getPointerPosition();
            if (this.controlled && this.mousePos && this.target) {
                var x = this.mousePos.x - this.wheel.getX();
                var y = this.mousePos.y - this.wheel.getY();
                var atan = Math.atan(y / x);
                var rotation = x >= 0 ? atan : atan + Math.PI;
                var targetGroup = this.target.getParent();

                this.wheel.setRotation(this.rotation - targetGroup.startRotation - (this.target.getAngle() / 2));
            }
        }, false);
    }
    getRandomReward() {
        var mainDigit = Math.round(Math.random() * 9);
        return mainDigit + '\n0\n0';
    }
    addWedge(n) {
        var s = getRandomColor();
        var reward = getRandomReward();
        var r = s[0];
        var g = s[1];
        var b = s[2];
        var angle = 2 * Math.PI / this.numWedges;

        var endColor = 'rgb(' + r + ',' + g + ',' + b + ')';
        r += 100;
        g += 100;
        b += 100;

        var startColor = 'rgb(' + r + ',' + g + ',' + b + ')';

        var wedge = new Konva.Group({
            rotation: 2 * n * Math.PI / this.numWedges,
        });

        var wedgeBackground = new Konva.Wedge({
            radius: 400,
            angle: angle,
            fillRadialGradientStartPoint: 0,
            fillRadialGradientStartRadius: 0,
            fillRadialGradientEndPoint: 0,
            fillRadialGradientEndRadius: 400,
            fillRadialGradientColorStops: [0, startColor, 1, endColor],
            fill: '#64e9f8',
            fillPriority: 'radial-gradient',
            stroke: '#ccc',
            strokeWidth: 2
        });

        wedge.add(wedgeBackground);

        var text = new Konva.Text({
            text: reward,
            fontFamily: 'Calibri',
            fontSize: 50,
            fill: 'white',
            align: 'center',
            stroke: 'yellow',
            strokeWidth: 1,
            rotation: (Math.PI + angle) / 2,
            x: 380,
            y: 30,
            listening: false
        });

        wedge.add(text);
        text.cache();

        wedge.startRotation = wedge.getRotation();

        this.wheel.add(wedge);
    }
    animate(frame) {
        // handle wheel spin
        var angularVelocityChange = this.angularVelocity * this.frame.timeDiff * (1 - this.angularFriction) / 1000;
        this.angularVelocity -= this.angularVelocityChange;

        // activate / deactivate wedges based on point intersection
        var shape = this.stage.getIntersection({
            x: this.stage.getWidth() / 2,
            y: 100
        });

        if (this.controlled) {
            if (this.angularVelocities.length > 10) {
                this.angularVelocities.shift();
            }

            this.angularVelocities.push((this.wheel.getRotation() - this.lastRotation) * 1000 / this.frame.timeDiff);
        }
        else {
            var diff = this.frame.timeDiff * this.angularVelocity / 1000;
            if (diff > 0.0001) {
                this.wheel.rotate(diff);
            } else if (!this.finished && !this.controlled) {
                if (this.shape) {
                    var text = this.shape.getParent().findOne('Text').text();
                    var price = text.split('\n').join('');
                    alert('You price is ' + price);
                }
                this.finished = true;
            }
        }
        lastRotation = this.wheel.getRotation();



        if (this.shape) {
            if (this.shape && (!this.activeWedge || (this.shape._id !== this.activeWedge._id))) {
                this.pointer.setY(20);

                new Konva.Tween({
                    node: pointer,
                    duration: 0.3,
                    y: 30,
                    easing: Konva.Easings.ElasticEaseOut
                }).play();

                if (this.activeWedge) {
                    this.activeWedge.setFillPriority('radial-gradient');
                }
                this.shape.setFillPriority('fill');
                this.activeWedge = this.shape;
            }
        }
    }
    init() {
        this.stage = new Konva.Stage({
            container: 'container',
            width: this.width,
            height: this.height
        });
        this.layer = new Konva.Layer();
        this.wheel = new Konva.Group({
            x: this.stage.getWidth() / 2,
            y: 410
        });

        for (var n = 0; n < this.numWedges; n++) {
            addWedge(n);
        }
        this.pointer = new Konva.Wedge({
            fillRadialGradientStartPoint: 0,
            fillRadialGradientStartRadius: 0,
            fillRadialGradientEndPoint: 0,
            fillRadialGradientEndRadius: 30,
            fillRadialGradientColorStops: [0, 'white', 1, 'red'],
            stroke: 'white',
            strokeWidth: 2,
            lineJoin: 'round',
            angle: 1,
            radius: 30,
            x: this.stage.getWidth() / 2,
            y: 33,
            rotation: -90,
            shadowColor: 'black',
            shadowOffset: 3,
            shadowBlur: 2,
            shadowOpacity: 0.5
        });

        // add components to the stage
        this.layer.add(this.wheel);
        this.layer.add(this.pointer);
        this.stage.add(this.layer);

        // bind events
        this.bind();

        var anim = new Konva.Animation(this.animate, this.layer);

        // wait one second and then spin the wheel
        setTimeout(function () {
            anim.start();
        }, 1000);


     }
    }

    export default RollTabak;

控制台中的错误是:

RollTabak.js?763e:87 Uncaught TypeError: Cannot read property 'getPointerPosition' of undefined
    at HTMLBodyElement.eval (RollTabak.js?763e:87)

我可以弄清楚this.stage是未定义的,但我不知道为什么。 我对Reactjs很陌生,如果有经验的人可以给我一些建议来解决这个问题,那将是很好的。

2 个答案:

答案 0 :(得分:0)

我猜想事件监听器即使在组件卸载后仍会运行-导致this.stage未定义。您必须在卸载事件上删除事件侦听器:

componentWillUnmount() {
        document.body.removeEventListener('yourEvent', yourFunction);
    }

答案 1 :(得分:0)

this上下文在代码中的多个位置存在问题。我已经将它们固定在某些地方,因此没有未定义的消息。例如 this.animate.bind(this),您需要在调用animate函数时绑定此上下文,还需要在事件侦听器回调中使用箭头函数,以便将this上下文保留在内部。您是否应该了解一下为什么您的代码无法正常工作。

class RollTabak extends React.Component {
        constructor() {
            super();
            var width = window.innerWidth;
            var height = window.innerHeight;

            Konva.angleDeg = false;
            var angularVelocity = 6;
            var angularVelocities = [];
            var lastRotation = 0;
            var controlled = false;
            var numWedges = 25;
            var angularFriction = 0.2;
            var target, activeWedge, stage, layer, wheel, pointer;
            var finished = false;

          }
        render() {

            return (
                <div>
                   <div id="container"></div>
                </div>
            );
        }


        componentDidMount(){
            this.init();
        }
        getAverageAngularVelocity() {
            var total = 0;
            var len = this.angularVelocities.length;

            if (len === 0) {
                return 0;
            }

            for (var n = 0; n < len; n++) {
                total += this.angularVelocities[n];
            }

            return total / len;
        }
        purifyColor(color) {
            var randIndex = Math.round(Math.random() * 3);
            color[randIndex] = 0;
            return color;
        }
        getRandomColor() {
            var r = 100 + Math.round(Math.random() * 55);
            var g = 100 + Math.round(Math.random() * 55);
            var b = 100 + Math.round(Math.random() * 55);
            var color = [r, g, b];
            color = purifyColor(color);
            color = purifyColor(color);

            return color;
        }
        bind() {
            this.wheel.on('mousedown', evt => {
                this.angularVelocity = 0;
                this.controlled = true;
                this.target = evt.target;
                this.finished = false;
            });
            // add listeners to container
            document.body.addEventListener('mouseup', () => {
                this.controlled = false;
                this.angularVelocity = getAverageAngularVelocity() * 5;

                if (this.angularVelocity > 20) {
                    this.angularVelocity = 20;
                }
                else if (this.angularVelocity < -20) {
                    this.angularVelocity = -20;
                }

                this.angularVelocities = [];
            }, false);

            document.body.addEventListener('mousemove', evt => {
                var mousePos = this.stage.getPointerPosition();
                if (this.controlled && this.mousePos && this.target) {
                    var x = this.mousePos.x - this.wheel.getX();
                    var y = this.mousePos.y - this.wheel.getY();
                    var atan = Math.atan(y / x);
                    var rotation = x >= 0 ? atan : atan + Math.PI;
                    var targetGroup = this.target.getParent();

                    this.wheel.setRotation(this.rotation - targetGroup.startRotation - (this.target.getAngle() / 2));
                }
            }, false);
        }
        getRandomReward() {
            var mainDigit = Math.round(Math.random() * 9);
            return mainDigit + '\n0\n0';
        }
        addWedge(n) {
            var s = getRandomColor();
            var reward = getRandomReward();
            var r = s[0];
            var g = s[1];
            var b = s[2];
            var angle = 2 * Math.PI / this.numWedges;

            var endColor = 'rgb(' + r + ',' + g + ',' + b + ')';
            r += 100;
            g += 100;
            b += 100;

            var startColor = 'rgb(' + r + ',' + g + ',' + b + ')';

            var wedge = new Konva.Group({
                rotation: 2 * n * Math.PI / this.numWedges,
            });

            var wedgeBackground = new Konva.Wedge({
                radius: 400,
                angle: angle,
                fillRadialGradientStartPoint: 0,
                fillRadialGradientStartRadius: 0,
                fillRadialGradientEndPoint: 0,
                fillRadialGradientEndRadius: 400,
                fillRadialGradientColorStops: [0, startColor, 1, endColor],
                fill: '#64e9f8',
                fillPriority: 'radial-gradient',
                stroke: '#ccc',
                strokeWidth: 2
            });

            wedge.add(wedgeBackground);

            var text = new Konva.Text({
                text: reward,
                fontFamily: 'Calibri',
                fontSize: 50,
                fill: 'white',
                align: 'center',
                stroke: 'yellow',
                strokeWidth: 1,
                rotation: (Math.PI + angle) / 2,
                x: 380,
                y: 30,
                listening: false
            });

            wedge.add(text);
            text.cache();

            wedge.startRotation = wedge.getRotation();

            this.wheel.add(wedge);
        }
        animate(frame) {
            // handle wheel spin
            var angularVelocityChange = this.angularVelocity * frame.timeDiff * (1 - this.angularFriction) / 1000;
            this.angularVelocity -= this.angularVelocityChange;

            // activate / deactivate wedges based on point intersection
            var shape = this.stage.getIntersection({
                x: this.stage.getWidth() / 2,
                y: 100
            });

            if (this.controlled) {
                if (this.angularVelocities.length > 10) {
                    this.angularVelocities.shift();
                }

                this.angularVelocities.push((this.wheel.getRotation() - this.lastRotation) * 1000 / frame.timeDiff);
            }
            else {
                var diff = frame.timeDiff * this.angularVelocity / 1000;
                if (diff > 0.0001) {
                    this.wheel.rotate(diff);
                } else if (!this.finished && !this.controlled) {
                    if (this.shape) {
                        var text = this.shape.getParent().findOne('Text').text();
                        var price = text.split('\n').join('');
                        alert('You price is ' + price);
                    }
                    this.finished = true;
                }
            }
            this.lastRotation = this.wheel.getRotation();



            if (this.shape) {
                if (this.shape && (!this.activeWedge || (this.shape._id !== this.activeWedge._id))) {
                    this.pointer.setY(20);

                    new Konva.Tween({
                        node: pointer,
                        duration: 0.3,
                        y: 30,
                        easing: Konva.Easings.ElasticEaseOut
                    }).play();

                    if (this.activeWedge) {
                        this.activeWedge.setFillPriority('radial-gradient');
                    }
                    this.shape.setFillPriority('fill');
                    this.activeWedge = this.shape;
                }
            }
        }
        init() {
            this.stage = new Konva.Stage({
                container: 'container',
                width: this.width,
                height: this.height
            });
            this.layer = new Konva.Layer();
            this.wheel = new Konva.Group({
                x: this.stage.getWidth() / 2,
                y: 410
            });

            for (var n = 0; n < this.numWedges; n++) {
                addWedge(n);
            }
            this.pointer = new Konva.Wedge({
                fillRadialGradientStartPoint: 0,
                fillRadialGradientStartRadius: 0,
                fillRadialGradientEndPoint: 0,
                fillRadialGradientEndRadius: 30,
                fillRadialGradientColorStops: [0, 'white', 1, 'red'],
                stroke: 'white',
                strokeWidth: 2,
                lineJoin: 'round',
                angle: 1,
                radius: 30,
                x: this.stage.getWidth() / 2,
                y: 33,
                rotation: -90,
                shadowColor: 'black',
                shadowOffset: 3,
                shadowBlur: 2,
                shadowOpacity: 0.5
            });

            // add components to the stage
            this.layer.add(this.wheel);
            this.layer.add(this.pointer);
            this.stage.add(this.layer);

            // bind events
            this.bind();

            var anim = new Konva.Animation(this.animate.bind(this), this.layer);

            // wait one second and then spin the wheel
            setTimeout(function () {
                anim.start();
            }, 1000);


         }
        }